Showing the changes to Source/Libraries/GSF.Web/Shared/Scripts (4 of 36 files). Show all
Unified · Split
| @@ -0,0 +1,31768 @@ | |||
| 1 | /** | ||
| 2 | * @license AngularJS v1.5.8 | ||
| 3 | * (c) 2010-2016 Google, Inc. http://angularjs.org | ||
| 4 | * License: MIT | ||
| 5 | */ | ||
| 6 | (function(window) {'use strict'; | ||
| 7 | |||
| 8 | /** | ||
| 9 | * @description | ||
| 10 | * | ||
| 11 | * This object provides a utility for producing rich Error messages within | ||
| 12 | * Angular. It can be called as follows: | ||
| 13 | * | ||
| 14 | * var exampleMinErr = minErr('example'); | ||
| 15 | * throw exampleMinErr('one', 'This {0} is {1}', foo, bar); | ||
| 16 | * | ||
| 17 | * The above creates an instance of minErr in the example namespace. The | ||
| 18 | * resulting error will have a namespaced error code of example.one. The | ||
| 19 | * resulting error will replace {0} with the value of foo, and {1} with the | ||
| 20 | * value of bar. The object is not restricted in the number of arguments it can | ||
| 21 | * take. | ||
| 22 | * | ||
| 23 | * If fewer arguments are specified than necessary for interpolation, the extra | ||
| 24 | * interpolation markers will be preserved in the final string. | ||
| 25 | * | ||
| 26 | * Since data will be parsed statically during a build step, some restrictions | ||
| 27 | * are applied with respect to how minErr instances are created and called. | ||
| 28 | * Instances should have names of the form namespaceMinErr for a minErr created | ||
| 29 | * using minErr('namespace') . Error codes, namespaces and template strings | ||
| 30 | * should all be static strings, not variables or general expressions. | ||
| 31 | * | ||
| 32 | * @param {string} module The namespace to use for the new minErr instance. | ||
| 33 | * @param {function} ErrorConstructor Custom error constructor to be instantiated when returning | ||
| 34 | * error from returned function, for cases when a particular type of error is useful. | ||
| 35 | * @returns {function(code:string, template:string, ...templateArgs): Error} minErr instance | ||
| 36 | */ | ||
| 37 | |||
| 38 | function minErr(module, ErrorConstructor) { | ||
| 39 | ErrorConstructor = ErrorConstructor || Error; | ||
| 40 | return function() { | ||
| 41 | var SKIP_INDEXES = 2; | ||
| 42 | |||
| 43 | var templateArgs = arguments, | ||
| 44 | code = templateArgs[0], | ||
| 45 | message = '[' + (module ? module + ':' : '') + code + '] ', | ||
| 46 | template = templateArgs[1], | ||
| 47 | paramPrefix, i; | ||
| 48 | |||
| 49 | message += template.replace(/\{\d+\}/g, function(match) { | ||
| 50 | var index = +match.slice(1, -1), | ||
| 51 | shiftedIndex = index + SKIP_INDEXES; | ||
| 52 | |||
| 53 | if (shiftedIndex < templateArgs.length) { | ||
| 54 | return toDebugString(templateArgs[shiftedIndex]); | ||
| 55 | } | ||
| 56 | |||
| 57 | return match; | ||
| 58 | }); | ||
| 59 | |||
| 60 | message += '\nhttp://errors.angularjs.org/1.5.8/' + | ||
| 61 | (module ? module + '/' : '') + code; | ||
| 62 | |||
| 63 | for (i = SKIP_INDEXES, paramPrefix = '?'; i < templateArgs.length; i++, paramPrefix = '&') { | ||
| 64 | message += paramPrefix + 'p' + (i - SKIP_INDEXES) + '=' + | ||
| 65 | encodeURIComponent(toDebugString(templateArgs[i])); | ||
| 66 | } | ||
| 67 | |||
| 68 | return new ErrorConstructor(message); | ||
| 69 | }; | ||
| 70 | } | ||
| 71 | |||
| 72 | /* We need to tell jshint what variables are being exported */ | ||
| 73 | /* global angular: true, | ||
| 74 | msie: true, | ||
| 75 | jqLite: true, | ||
| 76 | jQuery: true, | ||
| 77 | slice: true, | ||
| 78 | splice: true, | ||
| 79 | push: true, | ||
| 80 | toString: true, | ||
| 81 | ngMinErr: true, | ||
| 82 | angularModule: true, | ||
| 83 | uid: true, | ||
| 84 | REGEX_STRING_REGEXP: true, | ||
| 85 | VALIDITY_STATE_PROPERTY: true, | ||
| 86 | |||
| 87 | lowercase: true, | ||
| 88 | uppercase: true, | ||
| 89 | manualLowercase: true, | ||
| 90 | manualUppercase: true, | ||
| 91 | nodeName_: true, | ||
| 92 | isArrayLike: true, | ||
| 93 | forEach: true, | ||
| 94 | forEachSorted: true, | ||
| 95 | reverseParams: true, | ||
| 96 | nextUid: true, | ||
| 97 | setHashKey: true, | ||
| 98 | extend: true, | ||
| 99 | toInt: true, | ||
| 100 | inherit: true, | ||
| 101 | merge: true, | ||
| 102 | noop: true, | ||
| 103 | identity: true, | ||
| 104 | valueFn: true, | ||
| 105 | isUndefined: true, | ||
| 106 | isDefined: true, | ||
| 107 | isObject: true, | ||
| 108 | isBlankObject: true, | ||
| 109 | isString: true, | ||
| 110 | isNumber: true, | ||
| 111 | isDate: true, | ||
| 112 | isArray: true, | ||
| 113 | isFunction: true, | ||
| 114 | isRegExp: true, | ||
| 115 | isWindow: true, | ||
| 116 | isScope: true, | ||
| 117 | isFile: true, | ||
| 118 | isFormData: true, | ||
| 119 | isBlob: true, | ||
| 120 | isBoolean: true, | ||
| 121 | isPromiseLike: true, | ||
| 122 | trim: true, | ||
| 123 | escapeForRegexp: true, | ||
| 124 | isElement: true, | ||
| 125 | makeMap: true, | ||
| 126 | includes: true, | ||
| 127 | arrayRemove: true, | ||
| 128 | copy: true, | ||
| 129 | equals: true, | ||
| 130 | csp: true, | ||
| 131 | jq: true, | ||
| 132 | concat: true, | ||
| 133 | sliceArgs: true, | ||
| 134 | bind: true, | ||
| 135 | toJsonReplacer: true, | ||
| 136 | toJson: true, | ||
| 137 | fromJson: true, | ||
| 138 | convertTimezoneToLocal: true, | ||
| 139 | timezoneToOffset: true, | ||
| 140 | startingTag: true, | ||
| 141 | tryDecodeURIComponent: true, | ||
| 142 | parseKeyValue: true, | ||
| 143 | toKeyValue: true, | ||
| 144 | encodeUriSegment: true, | ||
| 145 | encodeUriQuery: true, | ||
| 146 | angularInit: true, | ||
| 147 | bootstrap: true, | ||
| 148 | getTestability: true, | ||
| 149 | snake_case: true, | ||
| 150 | bindJQuery: true, | ||
| 151 | assertArg: true, | ||
| 152 | assertArgFn: true, | ||
| 153 | assertNotHasOwnProperty: true, | ||
| 154 | getter: true, | ||
| 155 | getBlockNodes: true, | ||
| 156 | hasOwnProperty: true, | ||
| 157 | createMap: true, | ||
| 158 | |||
| 159 | NODE_TYPE_ELEMENT: true, | ||
| 160 | NODE_TYPE_ATTRIBUTE: true, | ||
| 161 | NODE_TYPE_TEXT: true, | ||
| 162 | NODE_TYPE_COMMENT: true, | ||
| 163 | NODE_TYPE_DOCUMENT: true, | ||
| 164 | NODE_TYPE_DOCUMENT_FRAGMENT: true, | ||
| 165 | */ | ||
| 166 | |||
| 167 | //////////////////////////////////// | ||
| 168 | |||
| 169 | /** | ||
| 170 | * @ngdoc module | ||
| 171 | * @name ng | ||
| 172 | * @module ng | ||
| 173 | * @installation | ||
| 174 | * @description | ||
| 175 | * | ||
| 176 | * # ng (core module) | ||
| 177 | * The ng module is loaded by default when an AngularJS application is started. The module itself | ||
| 178 | * contains the essential components for an AngularJS application to function. The table below | ||
| 179 | * lists a high level breakdown of each of the services/factories, filters, directives and testing | ||
| 180 | * components available within this core module. | ||
| 181 | * | ||
| 182 | * <div doc-module-components="ng"></div> | ||
| 183 | */ | ||
| 184 | |||
| 185 | var REGEX_STRING_REGEXP = /^\/(.+)\/([a-z]*)$/; | ||
| 186 | |||
| 187 | // The name of a form control's ValidityState property. | ||
| 188 | // This is used so that it's possible for internal tests to create mock ValidityStates. | ||
| 189 | var VALIDITY_STATE_PROPERTY = 'validity'; | ||
| 190 | |||
| 191 | var hasOwnProperty = Object.prototype.hasOwnProperty; | ||
| 192 | |||
| 193 | var lowercase = function(string) {return isString(string) ? string.toLowerCase() : string;}; | ||
| 194 | var uppercase = function(string) {return isString(string) ? string.toUpperCase() : string;}; | ||
| 195 | |||
| 196 | |||
| 197 | var manualLowercase = function(s) { | ||
| 198 | /* jshint bitwise: false */ | ||
| 199 | return isString(s) | ||
| 200 | ? s.replace(/[A-Z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) | 32);}) | ||
| 201 | : s; | ||
| 202 | }; | ||
| 203 | var manualUppercase = function(s) { | ||
| 204 | /* jshint bitwise: false */ | ||
| 205 | return isString(s) | ||
| 206 | ? s.replace(/[a-z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) & ~32);}) | ||
| 207 | : s; | ||
| 208 | }; | ||
| 209 | |||
| 210 | |||
| 211 | // String#toLowerCase and String#toUpperCase don't produce correct results in browsers with Turkish | ||
| 212 | // locale, for this reason we need to detect this case and redefine lowercase/uppercase methods | ||
| 213 | // with correct but slower alternatives. See https://github.com/angular/angular.js/issues/11387 | ||
| 214 | if ('i' !== 'I'.toLowerCase()) { | ||
| 215 | lowercase = manualLowercase; | ||
| 216 | uppercase = manualUppercase; | ||
| 217 | } | ||
| 218 | |||
| 219 | |||
| 220 | var | ||
| 221 | msie, // holds major version number for IE, or NaN if UA is not IE. | ||
| 222 | jqLite, // delay binding since jQuery could be loaded after us. | ||
| 223 | jQuery, // delay binding | ||
| 224 | slice = [].slice, | ||
| 225 | splice = [].splice, | ||
| 226 | push = [].push, | ||
| 227 | toString = Object.prototype.toString, | ||
| 228 | getPrototypeOf = Object.getPrototypeOf, | ||
| 229 | ngMinErr = minErr('ng'), | ||
| 230 | |||
| 231 | /** @name angular */ | ||
| 232 | angular = window.angular || (window.angular = {}), | ||
| 233 | angularModule, | ||
| 234 | uid = 0; | ||
| 235 | |||
| 236 | /** | ||
| 237 | * documentMode is an IE-only property | ||
| 238 | * http://msdn.microsoft.com/en-us/library/ie/cc196988(v=vs.85).aspx | ||
| 239 | */ | ||
| 240 | msie = window.document.documentMode; | ||
| 241 | |||
| 242 | |||
| 243 | /** | ||
| 244 | * @private | ||
| 245 | * @param {*} obj | ||
| 246 | * @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments, | ||
| 247 | * String ...) | ||
| 248 | */ | ||
| 249 | function isArrayLike(obj) { | ||
| 250 | |||
| 251 | // `null`, `undefined` and `window` are not array-like | ||
| 252 | if (obj == null || isWindow(obj)) return false; | ||
| 253 | |||
| 254 | // arrays, strings and jQuery/jqLite objects are array like | ||
| 255 | // * jqLite is either the jQuery or jqLite constructor function | ||
| 256 | // * we have to check the existence of jqLite first as this method is called | ||
| 257 | // via the forEach method when constructing the jqLite object in the first place | ||
| 258 | if (isArray(obj) || isString(obj) || (jqLite && obj instanceof jqLite)) return true; | ||
| 259 | |||
| 260 | // Support: iOS 8.2 (not reproducible in simulator) | ||
| 261 | // "length" in obj used to prevent JIT error (gh-11508) | ||
| 262 | var length = "length" in Object(obj) && obj.length; | ||
| 263 | |||
| 264 | // NodeList objects (with `item` method) and | ||
| 265 | // other objects with suitable length characteristics are array-like | ||
| 266 | return isNumber(length) && | ||
| 267 | (length >= 0 && ((length - 1) in obj || obj instanceof Array) || typeof obj.item == 'function'); | ||
| 268 | |||
| 269 | } | ||
| 270 | |||
| 271 | /** | ||
| 272 | * @ngdoc function | ||
| 273 | * @name angular.forEach | ||
| 274 | * @module ng | ||
| 275 | * @kind function | ||
| 276 | * | ||
| 277 | * @description | ||
| 278 | * Invokes the `iterator` function once for each item in `obj` collection, which can be either an | ||
| 279 | * object or an array. The `iterator` function is invoked with `iterator(value, key, obj)`, where `value` | ||
| 280 | * is the value of an object property or an array element, `key` is the object property key or | ||
| 281 | * array element index and obj is the `obj` itself. Specifying a `context` for the function is optional. | ||
| 282 | * | ||
| 283 | * It is worth noting that `.forEach` does not iterate over inherited properties because it filters | ||
| 284 | * using the `hasOwnProperty` method. | ||
| 285 | * | ||
| 286 | * Unlike ES262's | ||
| 287 | * [Array.prototype.forEach](http://www.ecma-international.org/ecma-262/5.1/#sec-15.4.4.18), | ||
| 288 | * providing 'undefined' or 'null' values for `obj` will not throw a TypeError, but rather just | ||
| 289 | * return the value provided. | ||
| 290 | * | ||
| 291 | ```js | ||
| 292 | var values = {name: 'misko', gender: 'male'}; | ||
| 293 | var log = []; | ||
| 294 | angular.forEach(values, function(value, key) { | ||
| 295 | this.push(key + ': ' + value); | ||
| 296 | }, log); | ||
| 297 | expect(log).toEqual(['name: misko', 'gender: male']); | ||
| 298 | ``` | ||
| 299 | * | ||
| 300 | * @param {Object|Array} obj Object to iterate over. | ||
| 301 | * @param {Function} iterator Iterator function. | ||
| 302 | * @param {Object=} context Object to become context (`this`) for the iterator function. | ||
| 303 | * @returns {Object|Array} Reference to `obj`. | ||
| 304 | */ | ||
| 305 | |||
| 306 | function forEach(obj, iterator, context) { | ||
| 307 | var key, length; | ||
| 308 | if (obj) { | ||
| 309 | if (isFunction(obj)) { | ||
| 310 | for (key in obj) { | ||
| 311 | // Need to check if hasOwnProperty exists, | ||
| 312 | // as on IE8 the result of querySelectorAll is an object without a hasOwnProperty function | ||
| 313 | if (key != 'prototype' && key != 'length' && key != 'name' && (!obj.hasOwnProperty || obj.hasOwnProperty(key))) { | ||
| 314 | iterator.call(context, obj[key], key, obj); | ||
| 315 | } | ||
| 316 | } | ||
| 317 | } else if (isArray(obj) || isArrayLike(obj)) { | ||
| 318 | var isPrimitive = typeof obj !== 'object'; | ||
| 319 | for (key = 0, length = obj.length; key < length; key++) { | ||
| 320 | if (isPrimitive || key in obj) { | ||
| 321 | iterator.call(context, obj[key], key, obj); | ||
| 322 | } | ||
| 323 | } | ||
| 324 | } else if (obj.forEach && obj.forEach !== forEach) { | ||
| 325 | obj.forEach(iterator, context, obj); | ||
| 326 | } else if (isBlankObject(obj)) { | ||
| 327 | // createMap() fast path --- Safe to avoid hasOwnProperty check because prototype chain is empty | ||
| 328 | for (key in obj) { | ||
| 329 | iterator.call(context, obj[key], key, obj); | ||
| 330 | } | ||
| 331 | } else if (typeof obj.hasOwnProperty === 'function') { | ||
| 332 | // Slow path for objects inheriting Object.prototype, hasOwnProperty check needed | ||
| 333 | for (key in obj) { | ||
| 334 | if (obj.hasOwnProperty(key)) { | ||
| 335 | iterator.call(context, obj[key], key, obj); | ||
| 336 | } | ||
| 337 | } | ||
| 338 | } else { | ||
| 339 | // Slow path for objects which do not have a method `hasOwnProperty` | ||
| 340 | for (key in obj) { | ||
| 341 | if (hasOwnProperty.call(obj, key)) { | ||
| 342 | iterator.call(context, obj[key], key, obj); | ||
| 343 | } | ||
| 344 | } | ||
| 345 | } | ||
| 346 | } | ||
| 347 | return obj; | ||
| 348 | } | ||
| 349 | |||
| 350 | function forEachSorted(obj, iterator, context) { | ||
| 351 | var keys = Object.keys(obj).sort(); | ||
| 352 | for (var i = 0; i < keys.length; i++) { | ||
| 353 | iterator.call(context, obj[keys[i]], keys[i]); | ||
| 354 | } | ||
| 355 | return keys; | ||
| 356 | } | ||
| 357 | |||
| 358 | |||
| 359 | /** | ||
| 360 | * when using forEach the params are value, key, but it is often useful to have key, value. | ||
| 361 | * @param {function(string, *)} iteratorFn | ||
| 362 | * @returns {function(*, string)} | ||
| 363 | */ | ||
| 364 | function reverseParams(iteratorFn) { | ||
| 365 | return function(value, key) {iteratorFn(key, value);}; | ||
| 366 | } | ||
| 367 | |||
| 368 | /** | ||
| 369 | * A consistent way of creating unique IDs in angular. | ||
| 370 | * | ||
| 371 | * Using simple numbers allows us to generate 28.6 million unique ids per second for 10 years before | ||
| 372 | * we hit number precision issues in JavaScript. | ||
| 373 | * | ||
| 374 | * Math.pow(2,53) / 60 / 60 / 24 / 365 / 10 = 28.6M | ||
| 375 | * | ||
| 376 | * @returns {number} an unique alpha-numeric string | ||
| 377 | */ | ||
| 378 | function nextUid() { | ||
| 379 | return ++uid; | ||
| 380 | } | ||
| 381 | |||
| 382 | |||
| 383 | /** | ||
| 384 | * Set or clear the hashkey for an object. | ||
| 385 | * @param obj object | ||
| 386 | * @param h the hashkey (!truthy to delete the hashkey) | ||
| 387 | */ | ||
| 388 | function setHashKey(obj, h) { | ||
| 389 | if (h) { | ||
| 390 | obj.$$hashKey = h; | ||
| 391 | } else { | ||
| 392 | delete obj.$$hashKey; | ||
| 393 | } | ||
| 394 | } | ||
| 395 | |||
| 396 | |||
| 397 | function baseExtend(dst, objs, deep) { | ||
| 398 | var h = dst.$$hashKey; | ||
| 399 | |||
| 400 | for (var i = 0, ii = objs.length; i < ii; ++i) { | ||
| 401 | var obj = objs[i]; | ||
| 402 | if (!isObject(obj) && !isFunction(obj)) continue; | ||
| 403 | var keys = Object.keys(obj); | ||
| 404 | for (var j = 0, jj = keys.length; j < jj; j++) { | ||
| 405 | var key = keys[j]; | ||
| 406 | var src = obj[key]; | ||
| 407 | |||
| 408 | if (deep && isObject(src)) { | ||
| 409 | if (isDate(src)) { | ||
| 410 | dst[key] = new Date(src.valueOf()); | ||
| 411 | } else if (isRegExp(src)) { | ||
| 412 | dst[key] = new RegExp(src); | ||
| 413 | } else if (src.nodeName) { | ||
| 414 | dst[key] = src.cloneNode(true); | ||
| 415 | } else if (isElement(src)) { | ||
| 416 | dst[key] = src.clone(); | ||
| 417 | } else { | ||
| 418 | if (!isObject(dst[key])) dst[key] = isArray(src) ? [] : {}; | ||
| 419 | baseExtend(dst[key], [src], true); | ||
| 420 | } | ||
| 421 | } else { | ||
| 422 | dst[key] = src; | ||
| 423 | } | ||
| 424 | } | ||
| 425 | } | ||
| 426 | |||
| 427 | setHashKey(dst, h); | ||
| 428 | return dst; | ||
| 429 | } | ||
| 430 | |||
| 431 | /** | ||
| 432 | * @ngdoc function | ||
| 433 | * @name angular.extend | ||
| 434 | * @module ng | ||
| 435 | * @kind function | ||
| 436 | * | ||
| 437 | * @description | ||
| 438 | * Extends the destination object `dst` by copying own enumerable properties from the `src` object(s) | ||
| 439 | * to `dst`. You can specify multiple `src` objects. If you want to preserve original objects, you can do so | ||
| 440 | * by passing an empty object as the target: `var object = angular.extend({}, object1, object2)`. | ||
| 441 | * | ||
| 442 | * **Note:** Keep in mind that `angular.extend` does not support recursive merge (deep copy). Use | ||
| 443 | * {@link angular.merge} for this. | ||
| 444 | * | ||
| 445 | * @param {Object} dst Destination object. | ||
| 446 | * @param {...Object} src Source object(s). | ||
| 447 | * @returns {Object} Reference to `dst`. | ||
| 448 | */ | ||
| 449 | function extend(dst) { | ||
| 450 | return baseExtend(dst, slice.call(arguments, 1), false); | ||
| 451 | } | ||
| 452 | |||
| 453 | |||
| 454 | /** | ||
| 455 | * @ngdoc function | ||
| 456 | * @name angular.merge | ||
| 457 | * @module ng | ||
| 458 | * @kind function | ||
| 459 | * | ||
| 460 | * @description | ||
| 461 | * Deeply extends the destination object `dst` by copying own enumerable properties from the `src` object(s) | ||
| 462 | * to `dst`. You can specify multiple `src` objects. If you want to preserve original objects, you can do so | ||
| 463 | * by passing an empty object as the target: `var object = angular.merge({}, object1, object2)`. | ||
| 464 | * | ||
| 465 | * Unlike {@link angular.extend extend()}, `merge()` recursively descends into object properties of source | ||
| 466 | * objects, performing a deep copy. | ||
| 467 | * | ||
| 468 | * @param {Object} dst Destination object. | ||
| 469 | * @param {...Object} src Source object(s). | ||
| 470 | * @returns {Object} Reference to `dst`. | ||
| 471 | */ | ||
| 472 | function merge(dst) { | ||
| 473 | return baseExtend(dst, slice.call(arguments, 1), true); | ||
| 474 | } | ||
| 475 | |||
| 476 | |||
| 477 | |||
| 478 | function toInt(str) { | ||
| 479 | return parseInt(str, 10); | ||
| 480 | } | ||
| 481 | |||
| 482 | |||
| 483 | function inherit(parent, extra) { | ||
| 484 | return extend(Object.create(parent), extra); | ||
| 485 | } | ||
| 486 | |||
| 487 | /** | ||
| 488 | * @ngdoc function | ||
| 489 | * @name angular.noop | ||
| 490 | * @module ng | ||
| 491 | * @kind function | ||
| 492 | * | ||
| 493 | * @description | ||
| 494 | * A function that performs no operations. This function can be useful when writing code in the | ||
| 495 | * functional style. | ||
| 496 | ```js | ||
| 497 | function foo(callback) { | ||
| 498 | var result = calculateResult(); | ||
| 499 | (callback || angular.noop)(result); | ||
| 500 | } | ||
| 501 | ``` | ||
| 502 | */ | ||
| 503 | function noop() {} | ||
| 504 | noop.$inject = []; | ||
| 505 | |||
| 506 | |||
| 507 | /** | ||
| 508 | * @ngdoc function | ||
| 509 | * @name angular.identity | ||
| 510 | * @module ng | ||
| 511 | * @kind function | ||
| 512 | * | ||
| 513 | * @description | ||
| 514 | * A function that returns its first argument. This function is useful when writing code in the | ||
| 515 | * functional style. | ||
| 516 | * | ||
| 517 | ```js | ||
| 518 | function transformer(transformationFn, value) { | ||
| 519 | return (transformationFn || angular.identity)(value); | ||
| 520 | }; | ||
| 521 | |||
| 522 | // E.g. | ||
| 523 | function getResult(fn, input) { | ||
| 524 | return (fn || angular.identity)(input); | ||
| 525 | }; | ||
| 526 | |||
| 527 | getResult(function(n) { return n * 2; }, 21); // returns 42 | ||
| 528 | getResult(null, 21); // returns 21 | ||
| 529 | getResult(undefined, 21); // returns 21 | ||
| 530 | ``` | ||
| 531 | * | ||
| 532 | * @param {*} value to be returned. | ||
| 533 | * @returns {*} the value passed in. | ||
| 534 | */ | ||
| 535 | function identity($) {return $;} | ||
| 536 | identity.$inject = []; | ||
| 537 | |||
| 538 | |||
| 539 | function valueFn(value) {return function valueRef() {return value;};} | ||
| 540 | |||
| 541 | function hasCustomToString(obj) { | ||
| 542 | return isFunction(obj.toString) && obj.toString !== toString; | ||
| 543 | } | ||
| 544 | |||
| 545 | |||
| 546 | /** | ||
| 547 | * @ngdoc function | ||
| 548 | * @name angular.isUndefined | ||
| 549 | * @module ng | ||
| 550 | * @kind function | ||
| 551 | * | ||
| 552 | * @description | ||
| 553 | * Determines if a reference is undefined. | ||
| 554 | * | ||
| 555 | * @param {*} value Reference to check. | ||
| 556 | * @returns {boolean} True if `value` is undefined. | ||
| 557 | */ | ||
| 558 | function isUndefined(value) {return typeof value === 'undefined';} | ||
| 559 | |||
| 560 | |||
| 561 | /** | ||
| 562 | * @ngdoc function | ||
| 563 | * @name angular.isDefined | ||
| 564 | * @module ng | ||
| 565 | * @kind function | ||
| 566 | * | ||
| 567 | * @description | ||
| 568 | * Determines if a reference is defined. | ||
| 569 | * | ||
| 570 | * @param {*} value Reference to check. | ||
| 571 | * @returns {boolean} True if `value` is defined. | ||
| 572 | */ | ||
| 573 | function isDefined(value) {return typeof value !== 'undefined';} | ||
| 574 | |||
| 575 | |||
| 576 | /** | ||
| 577 | * @ngdoc function | ||
| 578 | * @name angular.isObject | ||
| 579 | * @module ng | ||
| 580 | * @kind function | ||
| 581 | * | ||
| 582 | * @description | ||
| 583 | * Determines if a reference is an `Object`. Unlike `typeof` in JavaScript, `null`s are not | ||
| 584 | * considered to be objects. Note that JavaScript arrays are objects. | ||
| 585 | * | ||
| 586 | * @param {*} value Reference to check. | ||
| 587 | * @returns {boolean} True if `value` is an `Object` but not `null`. | ||
| 588 | */ | ||
| 589 | function isObject(value) { | ||
| 590 | // http://jsperf.com/isobject4 | ||
| 591 | return value !== null && typeof value === 'object'; | ||
| 592 | } | ||
| 593 | |||
| 594 | |||
| 595 | /** | ||
| 596 | * Determine if a value is an object with a null prototype | ||
| 597 | * | ||
| 598 | * @returns {boolean} True if `value` is an `Object` with a null prototype | ||
| 599 | */ | ||
| 600 | function isBlankObject(value) { | ||
| 601 | return value !== null && typeof value === 'object' && !getPrototypeOf(value); | ||
| 602 | } | ||
| 603 | |||
| 604 | |||
| 605 | /** | ||
| 606 | * @ngdoc function | ||
| 607 | * @name angular.isString | ||
| 608 | * @module ng | ||
| 609 | * @kind function | ||
| 610 | * | ||
| 611 | * @description | ||
| 612 | * Determines if a reference is a `String`. | ||
| 613 | * | ||
| 614 | * @param {*} value Reference to check. | ||
| 615 | * @returns {boolean} True if `value` is a `String`. | ||
| 616 | */ | ||
| 617 | function isString(value) {return typeof value === 'string';} | ||
| 618 | |||
| 619 | |||
| 620 | /** | ||
| 621 | * @ngdoc function | ||
| 622 | * @name angular.isNumber | ||
| 623 | * @module ng | ||
| 624 | * @kind function | ||
| 625 | * | ||
| 626 | * @description | ||
| 627 | * Determines if a reference is a `Number`. | ||
| 628 | * | ||
| 629 | * This includes the "special" numbers `NaN`, `+Infinity` and `-Infinity`. | ||
| 630 | * | ||
| 631 | * If you wish to exclude these then you can use the native | ||
| 632 | * [`isFinite'](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/isFinite) | ||
| 633 | * method. | ||
| 634 | * | ||
| 635 | * @param {*} value Reference to check. | ||
| 636 | * @returns {boolean} True if `value` is a `Number`. | ||
| 637 | */ | ||
| 638 | function isNumber(value) {return typeof value === 'number';} | ||
| 639 | |||
| 640 | |||
| 641 | /** | ||
| 642 | * @ngdoc function | ||
| 643 | * @name angular.isDate | ||
| 644 | * @module ng | ||
| 645 | * @kind function | ||
| 646 | * | ||
| 647 | * @description | ||
| 648 | * Determines if a value is a date. | ||
| 649 | * | ||
| 650 | * @param {*} value Reference to check. | ||
| 651 | * @returns {boolean} True if `value` is a `Date`. | ||
| 652 | */ | ||
| 653 | function isDate(value) { | ||
| 654 | return toString.call(value) === '[object Date]'; | ||
| 655 | } | ||
| 656 | |||
| 657 | |||
| 658 | /** | ||
| 659 | * @ngdoc function | ||
| 660 | * @name angular.isArray | ||
| 661 | * @module ng | ||
| 662 | * @kind function | ||
| 663 | * | ||
| 664 | * @description | ||
| 665 | * Determines if a reference is an `Array`. | ||
| 666 | * | ||
| 667 | * @param {*} value Reference to check. | ||
| 668 | * @returns {boolean} True if `value` is an `Array`. | ||
| 669 | */ | ||
| 670 | var isArray = Array.isArray; | ||
| 671 | |||
| 672 | /** | ||
| 673 | * @ngdoc function | ||
| 674 | * @name angular.isFunction | ||
| 675 | * @module ng | ||
| 676 | * @kind function | ||
| 677 | * | ||
| 678 | * @description | ||
| 679 | * Determines if a reference is a `Function`. | ||
| 680 | * | ||
| 681 | * @param {*} value Reference to check. | ||
| 682 | * @returns {boolean} True if `value` is a `Function`. | ||
| 683 | */ | ||
| 684 | function isFunction(value) {return typeof value === 'function';} | ||
| 685 | |||
| 686 | |||
| 687 | /** | ||
| 688 | * Determines if a value is a regular expression object. | ||
| 689 | * | ||
| 690 | * @private | ||
| 691 | * @param {*} value Reference to check. | ||
| 692 | * @returns {boolean} True if `value` is a `RegExp`. | ||
| 693 | */ | ||
| 694 | function isRegExp(value) { | ||
| 695 | return toString.call(value) === '[object RegExp]'; | ||
| 696 | } | ||
| 697 | |||
| 698 | |||
| 699 | /** | ||
| 700 | * Checks if `obj` is a window object. | ||
| 701 | * | ||
| 702 | * @private | ||
| 703 | * @param {*} obj Object to check | ||
| 704 | * @returns {boolean} True if `obj` is a window obj. | ||
| 705 | */ | ||
| 706 | function isWindow(obj) { | ||
| 707 | return obj && obj.window === obj; | ||
| 708 | } | ||
| 709 | |||
| 710 | |||
| 711 | function isScope(obj) { | ||
| 712 | return obj && obj.$evalAsync && obj.$watch; | ||
| 713 | } | ||
| 714 | |||
| 715 | |||
| 716 | function isFile(obj) { | ||
| 717 | return toString.call(obj) === '[object File]'; | ||
| 718 | } | ||
| 719 | |||
| 720 | |||
| 721 | function isFormData(obj) { | ||
| 722 | return toString.call(obj) === '[object FormData]'; | ||
| 723 | } | ||
| 724 | |||
| 725 | |||
| 726 | function isBlob(obj) { | ||
| 727 | return toString.call(obj) === '[object Blob]'; | ||
| 728 | } | ||
| 729 | |||
| 730 | |||
| 731 | function isBoolean(value) { | ||
| 732 | return typeof value === 'boolean'; | ||
| 733 | } | ||
| 734 | |||
| 735 | |||
| 736 | function isPromiseLike(obj) { | ||
| 737 | return obj && isFunction(obj.then); | ||
| 738 | } | ||
| 739 | |||
| 740 | |||
| 741 | var TYPED_ARRAY_REGEXP = /^\[object (?:Uint8|Uint8Clamped|Uint16|Uint32|Int8|Int16|Int32|Float32|Float64)Array\]$/; | ||
| 742 | function isTypedArray(value) { | ||
| 743 | return value && isNumber(value.length) && TYPED_ARRAY_REGEXP.test(toString.call(value)); | ||
| 744 | } | ||
| 745 | |||
| 746 | function isArrayBuffer(obj) { | ||
| 747 | return toString.call(obj) === '[object ArrayBuffer]'; | ||
| 748 | } | ||
| 749 | |||
| 750 | |||
| 751 | var trim = function(value) { | ||
| 752 | return isString(value) ? value.trim() : value; | ||
| 753 | }; | ||
| 754 | |||
| 755 | // Copied from: | ||
| 756 | // http://docs.closure-library.googlecode.com/git/local_closure_goog_string_string.js.source.html#line1021 | ||
| 757 | // Prereq: s is a string. | ||
| 758 | var escapeForRegexp = function(s) { | ||
| 759 | return s.replace(/([-()\[\]{}+?*.$\^|,:#<!\\])/g, '\\$1'). | ||
| 760 | replace(/\x08/g, '\\x08'); | ||
| 761 | }; | ||
| 762 | |||
| 763 | |||
| 764 | /** | ||
| 765 | * @ngdoc function | ||
| 766 | * @name angular.isElement | ||
| 767 | * @module ng | ||
| 768 | * @kind function | ||
| 769 | * | ||
| 770 | * @description | ||
| 771 | * Determines if a reference is a DOM element (or wrapped jQuery element). | ||
| 772 | * | ||
| 773 | * @param {*} value Reference to check. | ||
| 774 | * @returns {boolean} True if `value` is a DOM element (or wrapped jQuery element). | ||
| 775 | */ | ||
| 776 | function isElement(node) { | ||
| 777 | return !!(node && | ||
| 778 | (node.nodeName // We are a direct element. | ||
| 779 | || (node.prop && node.attr && node.find))); // We have an on and find method part of jQuery API. | ||
| 780 | } | ||
| 781 | |||
| 782 | /** | ||
| 783 | * @param str 'key1,key2,...' | ||
| 784 | * @returns {object} in the form of {key1:true, key2:true, ...} | ||
| 785 | */ | ||
| 786 | function makeMap(str) { | ||
| 787 | var obj = {}, items = str.split(','), i; | ||
| 788 | for (i = 0; i < items.length; i++) { | ||
| 789 | obj[items[i]] = true; | ||
| 790 | } | ||
| 791 | return obj; | ||
| 792 | } | ||
| 793 | |||
| 794 | |||
| 795 | function nodeName_(element) { | ||
| 796 | return lowercase(element.nodeName || (element[0] && element[0].nodeName)); | ||
| 797 | } | ||
| 798 | |||
| 799 | function includes(array, obj) { | ||
| 800 | return Array.prototype.indexOf.call(array, obj) != -1; | ||
| 801 | } | ||
| 802 | |||
| 803 | function arrayRemove(array, value) { | ||
| 804 | var index = array.indexOf(value); | ||
| 805 | if (index >= 0) { | ||
| 806 | array.splice(index, 1); | ||
| 807 | } | ||
| 808 | return index; | ||
| 809 | } | ||
| 810 | |||
| 811 | /** | ||
| 812 | * @ngdoc function | ||
| 813 | * @name angular.copy | ||
| 814 | * @module ng | ||
| 815 | * @kind function | ||
| 816 | * | ||
| 817 | * @description | ||
| 818 | * Creates a deep copy of `source`, which should be an object or an array. | ||
| 819 | * | ||
| 820 | * * If no destination is supplied, a copy of the object or array is created. | ||
| 821 | * * If a destination is provided, all of its elements (for arrays) or properties (for objects) | ||
| 822 | * are deleted and then all elements/properties from the source are copied to it. | ||
| 823 | * * If `source` is not an object or array (inc. `null` and `undefined`), `source` is returned. | ||
| 824 | * * If `source` is identical to `destination` an exception will be thrown. | ||
| 825 | * | ||
| 826 | * <br /> | ||
| 827 | * <div class="alert alert-warning"> | ||
| 828 | * Only enumerable properties are taken into account. Non-enumerable properties (both on `source` | ||
| 829 | * and on `destination`) will be ignored. | ||
| 830 | * </div> | ||
| 831 | * | ||
| 832 | * @param {*} source The source that will be used to make a copy. | ||
| 833 | * Can be any type, including primitives, `null`, and `undefined`. | ||
| 834 | * @param {(Object|Array)=} destination Destination into which the source is copied. If | ||
| 835 | * provided, must be of the same type as `source`. | ||
| 836 | * @returns {*} The copy or updated `destination`, if `destination` was specified. | ||
| 837 | * | ||
| 838 | * @example | ||
| 839 | <example module="copyExample"> | ||
| 840 | <file name="index.html"> | ||
| 841 | <div ng-controller="ExampleController"> | ||
| 842 | <form novalidate class="simple-form"> | ||
| 843 | <label>Name: <input type="text" ng-model="user.name" /></label><br /> | ||
| 844 | <label>Age: <input type="number" ng-model="user.age" /></label><br /> | ||
| 845 | Gender: <label><input type="radio" ng-model="user.gender" value="male" />male</label> | ||
| 846 | <label><input type="radio" ng-model="user.gender" value="female" />female</label><br /> | ||
| 847 | <button ng-click="reset()">RESET</button> | ||
| 848 | <button ng-click="update(user)">SAVE</button> | ||
| 849 | </form> | ||
| 850 | <pre>form = {{user | json}}</pre> | ||
| 851 | <pre>master = {{master | json}}</pre> | ||
| 852 | </div> | ||
| 853 | </file> | ||
| 854 | <file name="script.js"> | ||
| 855 | // Module: copyExample | ||
| 856 | angular. | ||
| 857 | module('copyExample', []). | ||
| 858 | controller('ExampleController', ['$scope', function($scope) { | ||
| 859 | $scope.master = {}; | ||
| 860 | |||
| 861 | $scope.reset = function() { | ||
| 862 | // Example with 1 argument | ||
| 863 | $scope.user = angular.copy($scope.master); | ||
| 864 | }; | ||
| 865 | |||
| 866 | $scope.update = function(user) { | ||
| 867 | // Example with 2 arguments | ||
| 868 | angular.copy(user, $scope.master); | ||
| 869 | }; | ||
| 870 | |||
| 871 | $scope.reset(); | ||
| 872 | }]); | ||
| 873 | </file> | ||
| 874 | </example> | ||
| 875 | */ | ||
| 876 | function copy(source, destination) { | ||
| 877 | var stackSource = []; | ||
| 878 | var stackDest = []; | ||
| 879 | |||
| 880 | if (destination) { | ||
| 881 | if (isTypedArray(destination) || isArrayBuffer(destination)) { | ||
| 882 | throw ngMinErr('cpta', "Can't copy! TypedArray destination cannot be mutated."); | ||
| 883 | } | ||
| 884 | if (source === destination) { | ||
| 885 | throw ngMinErr('cpi', "Can't copy! Source and destination are identical."); | ||
| 886 | } | ||
| 887 | |||
| 888 | // Empty the destination object | ||
| 889 | if (isArray(destination)) { | ||
| 890 | destination.length = 0; | ||
| 891 | } else { | ||
| 892 | forEach(destination, function(value, key) { | ||
| 893 | if (key !== '$$hashKey') { | ||
| 894 | delete destination[key]; | ||
| 895 | } | ||
| 896 | }); | ||
| 897 | } | ||
| 898 | |||
| 899 | stackSource.push(source); | ||
| 900 | stackDest.push(destination); | ||
| 901 | return copyRecurse(source, destination); | ||
| 902 | } | ||
| 903 | |||
| 904 | return copyElement(source); | ||
| 905 | |||
| 906 | function copyRecurse(source, destination) { | ||
| 907 | var h = destination.$$hashKey; | ||
| 908 | var key; | ||
| 909 | if (isArray(source)) { | ||
| 910 | for (var i = 0, ii = source.length; i < ii; i++) { | ||
| 911 | destination.push(copyElement(source[i])); | ||
| 912 | } | ||
| 913 | } else if (isBlankObject(source)) { | ||
| 914 | // createMap() fast path --- Safe to avoid hasOwnProperty check because prototype chain is empty | ||
| 915 | for (key in source) { | ||
| 916 | destination[key] = copyElement(source[key]); | ||
| 917 | } | ||
| 918 | } else if (source && typeof source.hasOwnProperty === 'function') { | ||
| 919 | // Slow path, which must rely on hasOwnProperty | ||
| 920 | for (key in source) { | ||
| 921 | if (source.hasOwnProperty(key)) { | ||
| 922 | destination[key] = copyElement(source[key]); | ||
| 923 | } | ||
| 924 | } | ||
| 925 | } else { | ||
| 926 | // Slowest path --- hasOwnProperty can't be called as a method | ||
| 927 | for (key in source) { | ||
| 928 | if (hasOwnProperty.call(source, key)) { | ||
| 929 | destination[key] = copyElement(source[key]); | ||
| 930 | } | ||
| 931 | } | ||
| 932 | } | ||
| 933 | setHashKey(destination, h); | ||
| 934 | return destination; | ||
| 935 | } | ||
| 936 | |||
| 937 | function copyElement(source) { | ||
| 938 | // Simple values | ||
| 939 | if (!isObject(source)) { | ||
| 940 | return source; | ||
| 941 | } | ||
| 942 | |||
| 943 | // Already copied values | ||
| 944 | var index = stackSource.indexOf(source); | ||
| 945 | if (index !== -1) { | ||
| 946 | return stackDest[index]; | ||
| 947 | } | ||
| 948 | |||
| 949 | if (isWindow(source) || isScope(source)) { | ||
| 950 | throw ngMinErr('cpws', | ||
| 951 | "Can't copy! Making copies of Window or Scope instances is not supported."); | ||
| 952 | } | ||
| 953 | |||
| 954 | var needsRecurse = false; | ||
| 955 | var destination = copyType(source); | ||
| 956 | |||
| 957 | if (destination === undefined) { | ||
| 958 | destination = isArray(source) ? [] : Object.create(getPrototypeOf(source)); | ||
| 959 | needsRecurse = true; | ||
| 960 | } | ||
| 961 | |||
| 962 | stackSource.push(source); | ||
| 963 | stackDest.push(destination); | ||
| 964 | |||
| 965 | return needsRecurse | ||
| 966 | ? copyRecurse(source, destination) | ||
| 967 | : destination; | ||
| 968 | } | ||
| 969 | |||
| 970 | function copyType(source) { | ||
| 971 | switch (toString.call(source)) { | ||
| 972 | case '[object Int8Array]': | ||
| 973 | case '[object Int16Array]': | ||
| 974 | case '[object Int32Array]': | ||
| 975 | case '[object Float32Array]': | ||
| 976 | case '[object Float64Array]': | ||
| 977 | case '[object Uint8Array]': | ||
| 978 | case '[object Uint8ClampedArray]': | ||
| 979 | case '[object Uint16Array]': | ||
| 980 | case '[object Uint32Array]': | ||
| 981 | return new source.constructor(copyElement(source.buffer), source.byteOffset, source.length); | ||
| 982 | |||
| 983 | case '[object ArrayBuffer]': | ||
| 984 | //Support: IE10 | ||
| 985 | if (!source.slice) { | ||
| 986 | var copied = new ArrayBuffer(source.byteLength); | ||
| 987 | new Uint8Array(copied).set(new Uint8Array(source)); | ||
| 988 | return copied; | ||
| 989 | } | ||
| 990 | return source.slice(0); | ||
| 991 | |||
| 992 | case '[object Boolean]': | ||
| 993 | case '[object Number]': | ||
| 994 | case '[object String]': | ||
| 995 | case '[object Date]': | ||
| 996 | return new source.constructor(source.valueOf()); | ||
| 997 | |||
| 998 | case '[object RegExp]': | ||
| 999 | var re = new RegExp(source.source, source.toString().match(/[^\/]*$/)[0]); | ||
| 1000 | re.lastIndex = source.lastIndex; | ||
| 1001 | return re; | ||
| 1002 | |||
| 1003 | case '[object Blob]': | ||
| 1004 | return new source.constructor([source], {type: source.type}); | ||
| 1005 | } | ||
| 1006 | |||
| 1007 | if (isFunction(source.cloneNode)) { | ||
| 1008 | return source.cloneNode(true); | ||
| 1009 | } | ||
| 1010 | } | ||
| 1011 | } | ||
| 1012 | |||
| 1013 | |||
| 1014 | /** | ||
| 1015 | * @ngdoc function | ||
| 1016 | * @name angular.equals | ||
| 1017 | * @module ng | ||
| 1018 | * @kind function | ||
| 1019 | * | ||
| 1020 | * @description | ||
| 1021 | * Determines if two objects or two values are equivalent. Supports value types, regular | ||
| 1022 | * expressions, arrays and objects. | ||
| 1023 | * | ||
| 1024 | * Two objects or values are considered equivalent if at least one of the following is true: | ||
| 1025 | * | ||
| 1026 | * * Both objects or values pass `===` comparison. | ||
| 1027 | * * Both objects or values are of the same type and all of their properties are equal by | ||
| 1028 | * comparing them with `angular.equals`. | ||
| 1029 | * * Both values are NaN. (In JavaScript, NaN == NaN => false. But we consider two NaN as equal) | ||
| 1030 | * * Both values represent the same regular expression (In JavaScript, | ||
| 1031 | * /abc/ == /abc/ => false. But we consider two regular expressions as equal when their textual | ||
| 1032 | * representation matches). | ||
| 1033 | * | ||
| 1034 | * During a property comparison, properties of `function` type and properties with names | ||
| 1035 | * that begin with `$` are ignored. | ||
| 1036 | * | ||
| 1037 | * Scope and DOMWindow objects are being compared only by identify (`===`). | ||
| 1038 | * | ||
| 1039 | * @param {*} o1 Object or value to compare. | ||
| 1040 | * @param {*} o2 Object or value to compare. | ||
| 1041 | * @returns {boolean} True if arguments are equal. | ||
| 1042 | * | ||
| 1043 | * @example | ||
| 1044 | <example module="equalsExample" name="equalsExample"> | ||
| 1045 | <file name="index.html"> | ||
| 1046 | <div ng-controller="ExampleController"> | ||
| 1047 | <form novalidate> | ||
| 1048 | <h3>User 1</h3> | ||
| 1049 | Name: <input type="text" ng-model="user1.name"> | ||
| 1050 | Age: <input type="number" ng-model="user1.age"> | ||
| 1051 | |||
| 1052 | <h3>User 2</h3> | ||
| 1053 | Name: <input type="text" ng-model="user2.name"> | ||
| 1054 | Age: <input type="number" ng-model="user2.age"> | ||
| 1055 | |||
| 1056 | <div> | ||
| 1057 | <br/> | ||
| 1058 | <input type="button" value="Compare" ng-click="compare()"> | ||
| 1059 | </div> | ||
| 1060 | User 1: <pre>{{user1 | json}}</pre> | ||
| 1061 | User 2: <pre>{{user2 | json}}</pre> | ||
| 1062 | Equal: <pre>{{result}}</pre> | ||
| 1063 | </form> | ||
| 1064 | </div> | ||
| 1065 | </file> | ||
| 1066 | <file name="script.js"> | ||
| 1067 | angular.module('equalsExample', []).controller('ExampleController', ['$scope', function($scope) { | ||
| 1068 | $scope.user1 = {}; | ||
| 1069 | $scope.user2 = {}; | ||
| 1070 | $scope.result; | ||
| 1071 | $scope.compare = function() { | ||
| 1072 | $scope.result = angular.equals($scope.user1, $scope.user2); | ||
| 1073 | }; | ||
| 1074 | }]); | ||
| 1075 | </file> | ||
| 1076 | </example> | ||
| 1077 | */ | ||
| 1078 | function equals(o1, o2) { | ||
| 1079 | if (o1 === o2) return true; | ||
| 1080 | if (o1 === null || o2 === null) return false; | ||
| 1081 | if (o1 !== o1 && o2 !== o2) return true; // NaN === NaN | ||
| 1082 | var t1 = typeof o1, t2 = typeof o2, length, key, keySet; | ||
| 1083 | if (t1 == t2 && t1 == 'object') { | ||
| 1084 | if (isArray(o1)) { | ||
| 1085 | if (!isArray(o2)) return false; | ||
| 1086 | if ((length = o1.length) == o2.length) { | ||
| 1087 | for (key = 0; key < length; key++) { | ||
| 1088 | if (!equals(o1[key], o2[key])) return false; | ||
| 1089 | } | ||
| 1090 | return true; | ||
| 1091 | } | ||
| 1092 | } else if (isDate(o1)) { | ||
| 1093 | if (!isDate(o2)) return false; | ||
| 1094 | return equals(o1.getTime(), o2.getTime()); | ||
| 1095 | } else if (isRegExp(o1)) { | ||
| 1096 | if (!isRegExp(o2)) return false; | ||
| 1097 | return o1.toString() == o2.toString(); | ||
| 1098 | } else { | ||
| 1099 | if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) || | ||
| 1100 | isArray(o2) || isDate(o2) || isRegExp(o2)) return false; | ||
| 1101 | keySet = createMap(); | ||
| 1102 | for (key in o1) { | ||
| 1103 | if (key.charAt(0) === '$' || isFunction(o1[key])) continue; | ||
| 1104 | if (!equals(o1[key], o2[key])) return false; | ||
| 1105 | keySet[key] = true; | ||
| 1106 | } | ||
| 1107 | for (key in o2) { | ||
| 1108 | if (!(key in keySet) && | ||
| 1109 | key.charAt(0) !== '$' && | ||
| 1110 | isDefined(o2[key]) && | ||
| 1111 | !isFunction(o2[key])) return false; | ||
| 1112 | } | ||
| 1113 | return true; | ||
| 1114 | } | ||
| 1115 | } | ||
| 1116 | return false; | ||
| 1117 | } | ||
| 1118 | |||
| 1119 | var csp = function() { | ||
| 1120 | if (!isDefined(csp.rules)) { | ||
| 1121 | |||
| 1122 | |||
| 1123 | var ngCspElement = (window.document.querySelector('[ng-csp]') || | ||
| 1124 | window.document.querySelector('[data-ng-csp]')); | ||
| 1125 | |||
| 1126 | if (ngCspElement) { | ||
| 1127 | var ngCspAttribute = ngCspElement.getAttribute('ng-csp') || | ||
| 1128 | ngCspElement.getAttribute('data-ng-csp'); | ||
| 1129 | csp.rules = { | ||
| 1130 | noUnsafeEval: !ngCspAttribute || (ngCspAttribute.indexOf('no-unsafe-eval') !== -1), | ||
| 1131 | noInlineStyle: !ngCspAttribute || (ngCspAttribute.indexOf('no-inline-style') !== -1) | ||
| 1132 | }; | ||
| 1133 | } else { | ||
| 1134 | csp.rules = { | ||
| 1135 | noUnsafeEval: noUnsafeEval(), | ||
| 1136 | noInlineStyle: false | ||
| 1137 | }; | ||
| 1138 | } | ||
| 1139 | } | ||
| 1140 | |||
| 1141 | return csp.rules; | ||
| 1142 | |||
| 1143 | function noUnsafeEval() { | ||
| 1144 | try { | ||
| 1145 | /* jshint -W031, -W054 */ | ||
| 1146 | new Function(''); | ||
| 1147 | /* jshint +W031, +W054 */ | ||
| 1148 | return false; | ||
| 1149 | } catch (e) { | ||
| 1150 | return true; | ||
| 1151 | } | ||
| 1152 | } | ||
| 1153 | }; | ||
| 1154 | |||
| 1155 | /** | ||
| 1156 | * @ngdoc directive | ||
| 1157 | * @module ng | ||
| 1158 | * @name ngJq | ||
| 1159 | * | ||
| 1160 | * @element ANY | ||
| 1161 | * @param {string=} ngJq the name of the library available under `window` | ||
| 1162 | * to be used for angular.element | ||
| 1163 | * @description | ||
| 1164 | * Use this directive to force the angular.element library. This should be | ||
| 1165 | * used to force either jqLite by leaving ng-jq blank or setting the name of | ||
| 1166 | * the jquery variable under window (eg. jQuery). | ||
| 1167 | * | ||
| 1168 | * Since angular looks for this directive when it is loaded (doesn't wait for the | ||
| 1169 | * DOMContentLoaded event), it must be placed on an element that comes before the script | ||
| 1170 | * which loads angular. Also, only the first instance of `ng-jq` will be used and all | ||
| 1171 | * others ignored. | ||
| 1172 | * | ||
| 1173 | * @example | ||
| 1174 | * This example shows how to force jqLite using the `ngJq` directive to the `html` tag. | ||
| 1175 | ```html | ||
| 1176 | <!doctype html> | ||
| 1177 | <html ng-app ng-jq> | ||
| 1178 | ... | ||
| 1179 | ... | ||
| 1180 | </html> | ||
| 1181 | ``` | ||
| 1182 | * @example | ||
| 1183 | * This example shows how to use a jQuery based library of a different name. | ||
| 1184 | * The library name must be available at the top most 'window'. | ||
| 1185 | ```html | ||
| 1186 | <!doctype html> | ||
| 1187 | <html ng-app ng-jq="jQueryLib"> | ||
| 1188 | ... | ||
| 1189 | ... | ||
| 1190 | </html> | ||
| 1191 | ``` | ||
| 1192 | */ | ||
| 1193 | var jq = function() { | ||
| 1194 | if (isDefined(jq.name_)) return jq.name_; | ||
| 1195 | var el; | ||
| 1196 | var i, ii = ngAttrPrefixes.length, prefix, name; | ||
| 1197 | for (i = 0; i < ii; ++i) { | ||
| 1198 | prefix = ngAttrPrefixes[i]; | ||
| 1199 | if (el = window.document.querySelector('[' + prefix.replace(':', '\\:') + 'jq]')) { | ||
| 1200 | name = el.getAttribute(prefix + 'jq'); | ||
| 1201 | break; | ||
| 1202 | } | ||
| 1203 | } | ||
| 1204 | |||
| 1205 | return (jq.name_ = name); | ||
| 1206 | }; | ||
| 1207 | |||
| 1208 | function concat(array1, array2, index) { | ||
| 1209 | return array1.concat(slice.call(array2, index)); | ||
| 1210 | } | ||
| 1211 | |||
| 1212 | function sliceArgs(args, startIndex) { | ||
| 1213 | return slice.call(args, startIndex || 0); | ||
| 1214 | } | ||
| 1215 | |||
| 1216 | |||
| 1217 | /* jshint -W101 */ | ||
| 1218 | /** | ||
| 1219 | * @ngdoc function | ||
| 1220 | * @name angular.bind | ||
| 1221 | * @module ng | ||
| 1222 | * @kind function | ||
| 1223 | * | ||
| 1224 | * @description | ||
| 1225 | * Returns a function which calls function `fn` bound to `self` (`self` becomes the `this` for | ||
| 1226 | * `fn`). You can supply optional `args` that are prebound to the function. This feature is also | ||
| 1227 | * known as [partial application](http://en.wikipedia.org/wiki/Partial_application), as | ||
| 1228 | * distinguished from [function currying](http://en.wikipedia.org/wiki/Currying#Contrast_with_partial_function_application). | ||
| 1229 | * | ||
| 1230 | * @param {Object} self Context which `fn` should be evaluated in. | ||
| 1231 | * @param {function()} fn Function to be bound. | ||
| 1232 | * @param {...*} args Optional arguments to be prebound to the `fn` function call. | ||
| 1233 | * @returns {function()} Function that wraps the `fn` with all the specified bindings. | ||
| 1234 | */ | ||
| 1235 | /* jshint +W101 */ | ||
| 1236 | function bind(self, fn) { | ||
| 1237 | var curryArgs = arguments.length > 2 ? sliceArgs(arguments, 2) : []; | ||
| 1238 | if (isFunction(fn) && !(fn instanceof RegExp)) { | ||
| 1239 | return curryArgs.length | ||
| 1240 | ? function() { | ||
| 1241 | return arguments.length | ||
| 1242 | ? fn.apply(self, concat(curryArgs, arguments, 0)) | ||
| 1243 | : fn.apply(self, curryArgs); | ||
| 1244 | } | ||
| 1245 | : function() { | ||
| 1246 | return arguments.length | ||
| 1247 | ? fn.apply(self, arguments) | ||
| 1248 | : fn.call(self); | ||
| 1249 | }; | ||
| 1250 | } else { | ||
| 1251 | // In IE, native methods are not functions so they cannot be bound (note: they don't need to be). | ||
| 1252 | return fn; | ||
| 1253 | } | ||
| 1254 | } | ||
| 1255 | |||
| 1256 | |||
| 1257 | function toJsonReplacer(key, value) { | ||
| 1258 | var val = value; | ||
| 1259 | |||
| 1260 | if (typeof key === 'string' && key.charAt(0) === '$' && key.charAt(1) === '$') { | ||
| 1261 | val = undefined; | ||
| 1262 | } else if (isWindow(value)) { | ||
| 1263 | val = '$WINDOW'; | ||
| 1264 | } else if (value && window.document === value) { | ||
| 1265 | val = '$DOCUMENT'; | ||
| 1266 | } else if (isScope(value)) { | ||
| 1267 | val = '$SCOPE'; | ||
| 1268 | } | ||
| 1269 | |||
| 1270 | return val; | ||
| 1271 | } | ||
| 1272 | |||
| 1273 | |||
| 1274 | /** | ||
| 1275 | * @ngdoc function | ||
| 1276 | * @name angular.toJson | ||
| 1277 | * @module ng | ||
| 1278 | * @kind function | ||
| 1279 | * | ||
| 1280 | * @description | ||
| 1281 | * Serializes input into a JSON-formatted string. Properties with leading $$ characters will be | ||
| 1282 | * stripped since angular uses this notation internally. | ||
| 1283 | * | ||
| 1284 | * @param {Object|Array|Date|string|number} obj Input to be serialized into JSON. | ||
| 1285 | * @param {boolean|number} [pretty=2] If set to true, the JSON output will contain newlines and whitespace. | ||
| 1286 | * If set to an integer, the JSON output will contain that many spaces per indentation. | ||
| 1287 | * @returns {string|undefined} JSON-ified string representing `obj`. | ||
| 1288 | * @knownIssue | ||
| 1289 | * | ||
| 1290 | * The Safari browser throws a `RangeError` instead of returning `null` when it tries to stringify a `Date` | ||
| 1291 | * object with an invalid date value. The only reliable way to prevent this is to monkeypatch the | ||
| 1292 | * `Date.prototype.toJSON` method as follows: | ||
| 1293 | * | ||
| 1294 | * ``` | ||
| 1295 | * var _DatetoJSON = Date.prototype.toJSON; | ||
| 1296 | * Date.prototype.toJSON = function() { | ||
| 1297 | * try { | ||
| 1298 | * return _DatetoJSON.call(this); | ||
| 1299 | * } catch(e) { | ||
| 1300 | * if (e instanceof RangeError) { | ||
| 1301 | * return null; | ||
| 1302 | * } | ||
| 1303 | * throw e; | ||
| 1304 | * } | ||
| 1305 | * }; | ||
| 1306 | * ``` | ||
| 1307 | * | ||
| 1308 | * See https://github.com/angular/angular.js/pull/14221 for more information. | ||
| 1309 | */ | ||
| 1310 | function toJson(obj, pretty) { | ||
| 1311 | if (isUndefined(obj)) return undefined; | ||
| 1312 | if (!isNumber(pretty)) { | ||
| 1313 | pretty = pretty ? 2 : null; | ||
| 1314 | } | ||
| 1315 | return JSON.stringify(obj, toJsonReplacer, pretty); | ||
| 1316 | } | ||
| 1317 | |||
| 1318 | |||
| 1319 | /** | ||
| 1320 | * @ngdoc function | ||
| 1321 | * @name angular.fromJson | ||
| 1322 | * @module ng | ||
| 1323 | * @kind function | ||
| 1324 | * | ||
| 1325 | * @description | ||
| 1326 | * Deserializes a JSON string. | ||
| 1327 | * | ||
| 1328 | * @param {string} json JSON string to deserialize. | ||
| 1329 | * @returns {Object|Array|string|number} Deserialized JSON string. | ||
| 1330 | */ | ||
| 1331 | function fromJson(json) { | ||
| 1332 | return isString(json) | ||
| 1333 | ? JSON.parse(json) | ||
| 1334 | : json; | ||
| 1335 | } | ||
| 1336 | |||
| 1337 | |||
| 1338 | var ALL_COLONS = /:/g; | ||
| 1339 | function timezoneToOffset(timezone, fallback) { | ||
| 1340 | // IE/Edge do not "understand" colon (`:`) in timezone | ||
| 1341 | timezone = timezone.replace(ALL_COLONS, ''); | ||
| 1342 | var requestedTimezoneOffset = Date.parse('Jan 01, 1970 00:00:00 ' + timezone) / 60000; | ||
| 1343 | return isNaN(requestedTimezoneOffset) ? fallback : requestedTimezoneOffset; | ||
| 1344 | } | ||
| 1345 | |||
| 1346 | |||
| 1347 | function addDateMinutes(date, minutes) { | ||
| 1348 | date = new Date(date.getTime()); | ||
| 1349 | date.setMinutes(date.getMinutes() + minutes); | ||
| 1350 | return date; | ||
| 1351 | } | ||
| 1352 | |||
| 1353 | |||
| 1354 | function convertTimezoneToLocal(date, timezone, reverse) { | ||
| 1355 | reverse = reverse ? -1 : 1; | ||
| 1356 | var dateTimezoneOffset = date.getTimezoneOffset(); | ||
| 1357 | var timezoneOffset = timezoneToOffset(timezone, dateTimezoneOffset); | ||
| 1358 | return addDateMinutes(date, reverse * (timezoneOffset - dateTimezoneOffset)); | ||
| 1359 | } | ||
| 1360 | |||
| 1361 | |||
| 1362 | /** | ||
| 1363 | * @returns {string} Returns the string representation of the element. | ||
| 1364 | */ | ||
| 1365 | function startingTag(element) { | ||
| 1366 | element = jqLite(element).clone(); | ||
| 1367 | try { | ||
| 1368 | // turns out IE does not let you set .html() on elements which | ||
| 1369 | // are not allowed to have children. So we just ignore it. | ||
| 1370 | element.empty(); | ||
| 1371 | } catch (e) {} | ||
| 1372 | var elemHtml = jqLite('<div>').append(element).html(); | ||
| 1373 | try { | ||
| 1374 | return element[0].nodeType === NODE_TYPE_TEXT ? lowercase(elemHtml) : | ||
| 1375 | elemHtml. | ||
| 1376 | match(/^(<[^>]+>)/)[1]. | ||
| 1377 | replace(/^<([\w\-]+)/, function(match, nodeName) {return '<' + lowercase(nodeName);}); | ||
| 1378 | } catch (e) { | ||
| 1379 | return lowercase(elemHtml); | ||
| 1380 | } | ||
| 1381 | |||
| 1382 | } | ||
| 1383 | |||
| 1384 | |||
| 1385 | ///////////////////////////////////////////////// | ||
| 1386 | |||
| 1387 | /** | ||
| 1388 | * Tries to decode the URI component without throwing an exception. | ||
| 1389 | * | ||
| 1390 | * @private | ||
| 1391 | * @param str value potential URI component to check. | ||
| 1392 | * @returns {boolean} True if `value` can be decoded | ||
| 1393 | * with the decodeURIComponent function. | ||
| 1394 | */ | ||
| 1395 | function tryDecodeURIComponent(value) { | ||
| 1396 | try { | ||
| 1397 | return decodeURIComponent(value); | ||
| 1398 | } catch (e) { | ||
| 1399 | // Ignore any invalid uri component. | ||
| 1400 | } | ||
| 1401 | } | ||
| 1402 | |||
| 1403 | |||
| 1404 | /** | ||
| 1405 | * Parses an escaped url query string into key-value pairs. | ||
| 1406 | * @returns {Object.<string,boolean|Array>} | ||
| 1407 | */ | ||
| 1408 | function parseKeyValue(/**string*/keyValue) { | ||
| 1409 | var obj = {}; | ||
| 1410 | forEach((keyValue || "").split('&'), function(keyValue) { | ||
| 1411 | var splitPoint, key, val; | ||
| 1412 | if (keyValue) { | ||
| 1413 | key = keyValue = keyValue.replace(/\+/g,'%20'); | ||
| 1414 | splitPoint = keyValue.indexOf('='); | ||
| 1415 | if (splitPoint !== -1) { | ||
| 1416 | key = keyValue.substring(0, splitPoint); | ||
| 1417 | val = keyValue.substring(splitPoint + 1); | ||
| 1418 | } | ||
| 1419 | key = tryDecodeURIComponent(key); | ||
| 1420 | if (isDefined(key)) { | ||
| 1421 | val = isDefined(val) ? tryDecodeURIComponent(val) : true; | ||
| 1422 | if (!hasOwnProperty.call(obj, key)) { | ||
| 1423 | obj[key] = val; | ||
| 1424 | } else if (isArray(obj[key])) { | ||
| 1425 | obj[key].push(val); | ||
| 1426 | } else { | ||
| 1427 | obj[key] = [obj[key],val]; | ||
| 1428 | } | ||
| 1429 | } | ||
| 1430 | } | ||
| 1431 | }); | ||
| 1432 | return obj; | ||
| 1433 | } | ||
| 1434 | |||
| 1435 | function toKeyValue(obj) { | ||
| 1436 | var parts = []; | ||
| 1437 | forEach(obj, function(value, key) { | ||
| 1438 | if (isArray(value)) { | ||
| 1439 | forEach(value, function(arrayValue) { | ||
| 1440 | parts.push(encodeUriQuery(key, true) + | ||
| 1441 | (arrayValue === true ? '' : '=' + encodeUriQuery(arrayValue, true))); | ||
| 1442 | }); | ||
| 1443 | } else { | ||
| 1444 | parts.push(encodeUriQuery(key, true) + | ||
| 1445 | (value === true ? '' : '=' + encodeUriQuery(value, true))); | ||
| 1446 | } | ||
| 1447 | }); | ||
| 1448 | return parts.length ? parts.join('&') : ''; | ||
| 1449 | } | ||
| 1450 | |||
| 1451 | |||
| 1452 | /** | ||
| 1453 | * We need our custom method because encodeURIComponent is too aggressive and doesn't follow | ||
| 1454 | * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path | ||
| 1455 | * segments: | ||
| 1456 | * segment = *pchar | ||
| 1457 | * pchar = unreserved / pct-encoded / sub-delims / ":" / "@" | ||
| 1458 | * pct-encoded = "%" HEXDIG HEXDIG | ||
| 1459 | * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" | ||
| 1460 | * sub-delims = "!" / "$" / "&" / "'" / "(" / ")" | ||
| 1461 | * / "*" / "+" / "," / ";" / "=" | ||
| 1462 | */ | ||
| 1463 | function encodeUriSegment(val) { | ||
| 1464 | return encodeUriQuery(val, true). | ||
| 1465 | replace(/%26/gi, '&'). | ||
| 1466 | replace(/%3D/gi, '='). | ||
| 1467 | replace(/%2B/gi, '+'); | ||
| 1468 | } | ||
| 1469 | |||
| 1470 | |||
| 1471 | /** | ||
| 1472 | * This method is intended for encoding *key* or *value* parts of query component. We need a custom | ||
| 1473 | * method because encodeURIComponent is too aggressive and encodes stuff that doesn't have to be | ||
| 1474 | * encoded per http://tools.ietf.org/html/rfc3986: | ||
| 1475 | * query = *( pchar / "/" / "?" ) | ||
| 1476 | * pchar = unreserved / pct-encoded / sub-delims / ":" / "@" | ||
| 1477 | * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" | ||
| 1478 | * pct-encoded = "%" HEXDIG HEXDIG | ||
| 1479 | * sub-delims = "!" / "$" / "&" / "'" / "(" / ")" | ||
| 1480 | * / "*" / "+" / "," / ";" / "=" | ||
| 1481 | */ | ||
| 1482 | function encodeUriQuery(val, pctEncodeSpaces) { | ||
| 1483 | return encodeURIComponent(val). | ||
| 1484 | replace(/%40/gi, '@'). | ||
| 1485 | replace(/%3A/gi, ':'). | ||
| 1486 | replace(/%24/g, '$'). | ||
| 1487 | replace(/%2C/gi, ','). | ||
| 1488 | replace(/%3B/gi, ';'). | ||
| 1489 | replace(/%20/g, (pctEncodeSpaces ? '%20' : '+')); | ||
| 1490 | } | ||
| 1491 | |||
| 1492 | var ngAttrPrefixes = ['ng-', 'data-ng-', 'ng:', 'x-ng-']; | ||
| 1493 | |||
| 1494 | function getNgAttribute(element, ngAttr) { | ||
| 1495 | var attr, i, ii = ngAttrPrefixes.length; | ||
| 1496 | for (i = 0; i < ii; ++i) { | ||
| 1497 | attr = ngAttrPrefixes[i] + ngAttr; | ||
| 1498 | if (isString(attr = element.getAttribute(attr))) { | ||
| 1499 | return attr; | ||
| 1500 | } | ||
| 1501 | } | ||
| 1502 | return null; | ||
| 1503 | } | ||
| 1504 | |||
| 1505 | /** | ||
| 1506 | * @ngdoc directive | ||
| 1507 | * @name ngApp | ||
| 1508 | * @module ng | ||
| 1509 | * | ||
| 1510 | * @element ANY | ||
| 1511 | * @param {angular.Module} ngApp an optional application | ||
| 1512 | * {@link angular.module module} name to load. | ||
| 1513 | * @param {boolean=} ngStrictDi if this attribute is present on the app element, the injector will be | ||
| 1514 | * created in "strict-di" mode. This means that the application will fail to invoke functions which | ||
| 1515 | * do not use explicit function annotation (and are thus unsuitable for minification), as described | ||
| 1516 | * in {@link guide/di the Dependency Injection guide}, and useful debugging info will assist in | ||
| 1517 | * tracking down the root of these bugs. | ||
| 1518 | * | ||
| 1519 | * @description | ||
| 1520 | * | ||
| 1521 | * Use this directive to **auto-bootstrap** an AngularJS application. The `ngApp` directive | ||
| 1522 | * designates the **root element** of the application and is typically placed near the root element | ||
| 1523 | * of the page - e.g. on the `<body>` or `<html>` tags. | ||
| 1524 | * | ||
| 1525 | * There are a few things to keep in mind when using `ngApp`: | ||
| 1526 | * - only one AngularJS application can be auto-bootstrapped per HTML document. The first `ngApp` | ||
| 1527 | * found in the document will be used to define the root element to auto-bootstrap as an | ||
| 1528 | * application. To run multiple applications in an HTML document you must manually bootstrap them using | ||
| 1529 | * {@link angular.bootstrap} instead. | ||
| 1530 | * - AngularJS applications cannot be nested within each other. | ||
| 1531 | * - Do not use a directive that uses {@link ng.$compile#transclusion transclusion} on the same element as `ngApp`. | ||
| 1532 | * This includes directives such as {@link ng.ngIf `ngIf`}, {@link ng.ngInclude `ngInclude`} and | ||
| 1533 | * {@link ngRoute.ngView `ngView`}. | ||
| 1534 | * Doing this misplaces the app {@link ng.$rootElement `$rootElement`} and the app's {@link auto.$injector injector}, | ||
| 1535 | * causing animations to stop working and making the injector inaccessible from outside the app. | ||
| 1536 | * | ||
| 1537 | * You can specify an **AngularJS module** to be used as the root module for the application. This | ||
| 1538 | * module will be loaded into the {@link auto.$injector} when the application is bootstrapped. It | ||
| 1539 | * should contain the application code needed or have dependencies on other modules that will | ||
| 1540 | * contain the code. See {@link angular.module} for more information. | ||
| 1541 | * | ||
| 1542 | * In the example below if the `ngApp` directive were not placed on the `html` element then the | ||
| 1543 | * document would not be compiled, the `AppController` would not be instantiated and the `{{ a+b }}` | ||
| 1544 | * would not be resolved to `3`. | ||
| 1545 | * | ||
| 1546 | * `ngApp` is the easiest, and most common way to bootstrap an application. | ||
| 1547 | * | ||
| 1548 | <example module="ngAppDemo"> | ||
| 1549 | <file name="index.html"> | ||
| 1550 | <div ng-controller="ngAppDemoController"> | ||
| 1551 | I can add: {{a}} + {{b}} = {{ a+b }} | ||
| 1552 | </div> | ||
| 1553 | </file> | ||
| 1554 | <file name="script.js"> | ||
| 1555 | angular.module('ngAppDemo', []).controller('ngAppDemoController', function($scope) { | ||
| 1556 | $scope.a = 1; | ||
| 1557 | $scope.b = 2; | ||
| 1558 | }); | ||
| 1559 | </file> | ||
| 1560 | </example> | ||
| 1561 | * | ||
| 1562 | * Using `ngStrictDi`, you would see something like this: | ||
| 1563 | * | ||
| 1564 | <example ng-app-included="true"> | ||
| 1565 | <file name="index.html"> | ||
| 1566 | <div ng-app="ngAppStrictDemo" ng-strict-di> | ||
| 1567 | <div ng-controller="GoodController1"> | ||
| 1568 | I can add: {{a}} + {{b}} = {{ a+b }} | ||
| 1569 | |||
| 1570 | <p>This renders because the controller does not fail to | ||
| 1571 | instantiate, by using explicit annotation style (see | ||
| 1572 | script.js for details) | ||
| 1573 | </p> | ||
| 1574 | </div> | ||
| 1575 | |||
| 1576 | <div ng-controller="GoodController2"> | ||
| 1577 | Name: <input ng-model="name"><br /> | ||
| 1578 | Hello, {{name}}! | ||
| 1579 | |||
| 1580 | <p>This renders because the controller does not fail to | ||
| 1581 | instantiate, by using explicit annotation style | ||
| 1582 | (see script.js for details) | ||
| 1583 | </p> | ||
| 1584 | </div> | ||
| 1585 | |||
| 1586 | <div ng-controller="BadController"> | ||
| 1587 | I can add: {{a}} + {{b}} = {{ a+b }} | ||
| 1588 | |||
| 1589 | <p>The controller could not be instantiated, due to relying | ||
| 1590 | on automatic function annotations (which are disabled in | ||
| 1591 | strict mode). As such, the content of this section is not | ||
| 1592 | interpolated, and there should be an error in your web console. | ||
| 1593 | </p> | ||
| 1594 | </div> | ||
| 1595 | </div> | ||
| 1596 | </file> | ||
| 1597 | <file name="script.js"> | ||
| 1598 | angular.module('ngAppStrictDemo', []) | ||
| 1599 | // BadController will fail to instantiate, due to relying on automatic function annotation, | ||
| 1600 | // rather than an explicit annotation | ||
| 1601 | .controller('BadController', function($scope) { | ||
| 1602 | $scope.a = 1; | ||
| 1603 | $scope.b = 2; | ||
| 1604 | }) | ||
| 1605 | // Unlike BadController, GoodController1 and GoodController2 will not fail to be instantiated, | ||
| 1606 | // due to using explicit annotations using the array style and $inject property, respectively. | ||
| 1607 | .controller('GoodController1', ['$scope', function($scope) { | ||
| 1608 | $scope.a = 1; | ||
| 1609 | $scope.b = 2; | ||
| 1610 | }]) | ||
| 1611 | .controller('GoodController2', GoodController2); | ||
| 1612 | function GoodController2($scope) { | ||
| 1613 | $scope.name = "World"; | ||
| 1614 | } | ||
| 1615 | GoodController2.$inject = ['$scope']; | ||
| 1616 | </file> | ||
| 1617 | <file name="style.css"> | ||
| 1618 | div[ng-controller] { | ||
| 1619 | margin-bottom: 1em; | ||
| 1620 | -webkit-border-radius: 4px; | ||
| 1621 | border-radius: 4px; | ||
| 1622 | border: 1px solid; | ||
| 1623 | padding: .5em; | ||
| 1624 | } | ||
| 1625 | div[ng-controller^=Good] { | ||
| 1626 | border-color: #d6e9c6; | ||
| 1627 | background-color: #dff0d8; | ||
| 1628 | color: #3c763d; | ||
| 1629 | } | ||
| 1630 | div[ng-controller^=Bad] { | ||
| 1631 | border-color: #ebccd1; | ||
| 1632 | background-color: #f2dede; | ||
| 1633 | color: #a94442; | ||
| 1634 | margin-bottom: 0; | ||
| 1635 | } | ||
| 1636 | </file> | ||
| 1637 | </example> | ||
| 1638 | */ | ||
| 1639 | function angularInit(element, bootstrap) { | ||
| 1640 | var appElement, | ||
| 1641 | module, | ||
| 1642 | config = {}; | ||
| 1643 | |||
| 1644 | // The element `element` has priority over any other element. | ||
| 1645 | forEach(ngAttrPrefixes, function(prefix) { | ||
| 1646 | var name = prefix + 'app'; | ||
| 1647 | |||
| 1648 | if (!appElement && element.hasAttribute && element.hasAttribute(name)) { | ||
| 1649 | appElement = element; | ||
| 1650 | module = element.getAttribute(name); | ||
| 1651 | } | ||
| 1652 | }); | ||
| 1653 | forEach(ngAttrPrefixes, function(prefix) { | ||
| 1654 | var name = prefix + 'app'; | ||
| 1655 | var candidate; | ||
| 1656 | |||
| 1657 | if (!appElement && (candidate = element.querySelector('[' + name.replace(':', '\\:') + ']'))) { | ||
| 1658 | appElement = candidate; | ||
| 1659 | module = candidate.getAttribute(name); | ||
| 1660 | } | ||
| 1661 | }); | ||
| 1662 | if (appElement) { | ||
| 1663 | config.strictDi = getNgAttribute(appElement, "strict-di") !== null; | ||
| 1664 | bootstrap(appElement, module ? [module] : [], config); | ||
| 1665 | } | ||
| 1666 | } | ||
| 1667 | |||
| 1668 | /** | ||
| 1669 | * @ngdoc function | ||
| 1670 | * @name angular.bootstrap | ||
| 1671 | * @module ng | ||
| 1672 | * @description | ||
| 1673 | * Use this function to manually start up angular application. | ||
| 1674 | * | ||
| 1675 | * For more information, see the {@link guide/bootstrap Bootstrap guide}. | ||
| 1676 | * | ||
| 1677 | * Angular will detect if it has been loaded into the browser more than once and only allow the | ||
| 1678 | * first loaded script to be bootstrapped and will report a warning to the browser console for | ||
| 1679 | * each of the subsequent scripts. This prevents strange results in applications, where otherwise | ||
| 1680 | * multiple instances of Angular try to work on the DOM. | ||
| 1681 | * | ||
| 1682 | * <div class="alert alert-warning"> | ||
| 1683 | * **Note:** Protractor based end-to-end tests cannot use this function to bootstrap manually. | ||
| 1684 | * They must use {@link ng.directive:ngApp ngApp}. | ||
| 1685 | * </div> | ||
| 1686 | * | ||
| 1687 | * <div class="alert alert-warning"> | ||
| 1688 | * **Note:** Do not bootstrap the app on an element with a directive that uses {@link ng.$compile#transclusion transclusion}, | ||
| 1689 | * such as {@link ng.ngIf `ngIf`}, {@link ng.ngInclude `ngInclude`} and {@link ngRoute.ngView `ngView`}. | ||
| 1690 | * Doing this misplaces the app {@link ng.$rootElement `$rootElement`} and the app's {@link auto.$injector injector}, | ||
| 1691 | * causing animations to stop working and making the injector inaccessible from outside the app. | ||
| 1692 | * </div> | ||
| 1693 | * | ||
| 1694 | * ```html | ||
| 1695 | * <!doctype html> | ||
| 1696 | * <html> | ||
| 1697 | * <body> | ||
| 1698 | * <div ng-controller="WelcomeController"> | ||
| 1699 | * {{greeting}} | ||
| 1700 | * </div> | ||
| 1701 | * | ||
| 1702 | * <script src="angular.js"></script> | ||
| 1703 | * <script> | ||
| 1704 | * var app = angular.module('demo', []) | ||
| 1705 | * .controller('WelcomeController', function($scope) { | ||
| 1706 | * $scope.greeting = 'Welcome!'; | ||
| 1707 | * }); | ||
| 1708 | * angular.bootstrap(document, ['demo']); | ||
| 1709 | * </script> | ||
| 1710 | * </body> | ||
| 1711 | * </html> | ||
| 1712 | * ``` | ||
| 1713 | * | ||
| 1714 | * @param {DOMElement} element DOM element which is the root of angular application. | ||
| 1715 | * @param {Array<String|Function|Array>=} modules an array of modules to load into the application. | ||
| 1716 | * Each item in the array should be the name of a predefined module or a (DI annotated) | ||
| 1717 | * function that will be invoked by the injector as a `config` block. | ||
| 1718 | * See: {@link angular.module modules} | ||
| 1719 | * @param {Object=} config an object for defining configuration options for the application. The | ||
| 1720 | * following keys are supported: | ||
| 1721 | * | ||
| 1722 | * * `strictDi` - disable automatic function annotation for the application. This is meant to | ||
| 1723 | * assist in finding bugs which break minified code. Defaults to `false`. | ||
| 1724 | * | ||
| 1725 | * @returns {auto.$injector} Returns the newly created injector for this app. | ||
| 1726 | */ | ||
| 1727 | function bootstrap(element, modules, config) { | ||
| 1728 | if (!isObject(config)) config = {}; | ||
| 1729 | var defaultConfig = { | ||
| 1730 | strictDi: false | ||
| 1731 | }; | ||
| 1732 | config = extend(defaultConfig, config); | ||
| 1733 | var doBootstrap = function() { | ||
| 1734 | element = jqLite(element); | ||
| 1735 | |||
| 1736 | if (element.injector()) { | ||
| 1737 | var tag = (element[0] === window.document) ? 'document' : startingTag(element); | ||
| 1738 | // Encode angle brackets to prevent input from being sanitized to empty string #8683. | ||
| 1739 | throw ngMinErr( | ||
| 1740 | 'btstrpd', | ||
| 1741 | "App already bootstrapped with this element '{0}'", | ||
| 1742 | tag.replace(/</,'<').replace(/>/,'>')); | ||
| 1743 | } | ||
| 1744 | |||
| 1745 | modules = modules || []; | ||
| 1746 | modules.unshift(['$provide', function($provide) { | ||
| 1747 | $provide.value('$rootElement', element); | ||
| 1748 | }]); | ||
| 1749 | |||
| 1750 | if (config.debugInfoEnabled) { | ||
| 1751 | // Pushing so that this overrides `debugInfoEnabled` setting defined in user's `modules`. | ||
| 1752 | modules.push(['$compileProvider', function($compileProvider) { | ||
| 1753 | $compileProvider.debugInfoEnabled(true); | ||
| 1754 | }]); | ||
| 1755 | } | ||
| 1756 | |||
| 1757 | modules.unshift('ng'); | ||
| 1758 | var injector = createInjector(modules, config.strictDi); | ||
| 1759 | injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector', | ||
| 1760 | function bootstrapApply(scope, element, compile, injector) { | ||
| 1761 | scope.$apply(function() { | ||
| 1762 | element.data('$injector', injector); | ||
| 1763 | compile(element)(scope); | ||
| 1764 | }); | ||
| 1765 | }] | ||
| 1766 | ); | ||
| 1767 | return injector; | ||
| 1768 | }; | ||
| 1769 | |||
| 1770 | var NG_ENABLE_DEBUG_INFO = /^NG_ENABLE_DEBUG_INFO!/; | ||
| 1771 | var NG_DEFER_BOOTSTRAP = /^NG_DEFER_BOOTSTRAP!/; | ||
| 1772 | |||
| 1773 | if (window && NG_ENABLE_DEBUG_INFO.test(window.name)) { | ||
| 1774 | config.debugInfoEnabled = true; | ||
| 1775 | window.name = window.name.replace(NG_ENABLE_DEBUG_INFO, ''); | ||
| 1776 | } | ||
| 1777 | |||
| 1778 | if (window && !NG_DEFER_BOOTSTRAP.test(window.name)) { | ||
| 1779 | return doBootstrap(); | ||
| 1780 | } | ||
| 1781 | |||
| 1782 | window.name = window.name.replace(NG_DEFER_BOOTSTRAP, ''); | ||
| 1783 | angular.resumeBootstrap = function(extraModules) { | ||
| 1784 | forEach(extraModules, function(module) { | ||
| 1785 | modules.push(module); | ||
| 1786 | }); | ||
| 1787 | return doBootstrap(); | ||
| 1788 | }; | ||
| 1789 | |||
| 1790 | if (isFunction(angular.resumeDeferredBootstrap)) { | ||
| 1791 | angular.resumeDeferredBootstrap(); | ||
| 1792 | } | ||
| 1793 | } | ||
| 1794 | |||
| 1795 | /** | ||
| 1796 | * @ngdoc function | ||
| 1797 | * @name angular.reloadWithDebugInfo | ||
| 1798 | * @module ng | ||
| 1799 | * @description | ||
| 1800 | * Use this function to reload the current application with debug information turned on. | ||
| 1801 | * This takes precedence over a call to `$compileProvider.debugInfoEnabled(false)`. | ||
| 1802 | * | ||
| 1803 | * See {@link ng.$compileProvider#debugInfoEnabled} for more. | ||
| 1804 | */ | ||
| 1805 | function reloadWithDebugInfo() { | ||
| 1806 | window.name = 'NG_ENABLE_DEBUG_INFO!' + window.name; | ||
| 1807 | window.location.reload(); | ||
| 1808 | } | ||
| 1809 | |||
| 1810 | /** | ||
| 1811 | * @name angular.getTestability | ||
| 1812 | * @module ng | ||
| 1813 | * @description | ||
| 1814 | * Get the testability service for the instance of Angular on the given | ||
| 1815 | * element. | ||
| 1816 | * @param {DOMElement} element DOM element which is the root of angular application. | ||
| 1817 | */ | ||
| 1818 | function getTestability(rootElement) { | ||
| 1819 | var injector = angular.element(rootElement).injector(); | ||
| 1820 | if (!injector) { | ||
| 1821 | throw ngMinErr('test', | ||
| 1822 | 'no injector found for element argument to getTestability'); | ||
| 1823 | } | ||
| 1824 | return injector.get('$$testability'); | ||
| 1825 | } | ||
| 1826 | |||
| 1827 | var SNAKE_CASE_REGEXP = /[A-Z]/g; | ||
| 1828 | function snake_case(name, separator) { | ||
| 1829 | separator = separator || '_'; | ||
| 1830 | return name.replace(SNAKE_CASE_REGEXP, function(letter, pos) { | ||
| 1831 | return (pos ? separator : '') + letter.toLowerCase(); | ||
| 1832 | }); | ||
| 1833 | } | ||
| 1834 | |||
| 1835 | var bindJQueryFired = false; | ||
| 1836 | function bindJQuery() { | ||
| 1837 | var originalCleanData; | ||
| 1838 | |||
| 1839 | if (bindJQueryFired) { | ||
| 1840 | return; | ||
| 1841 | } | ||
| 1842 | |||
| 1843 | // bind to jQuery if present; | ||
| 1844 | var jqName = jq(); | ||
| 1845 | jQuery = isUndefined(jqName) ? window.jQuery : // use jQuery (if present) | ||
| 1846 | !jqName ? undefined : // use jqLite | ||
| 1847 | window[jqName]; // use jQuery specified by `ngJq` | ||
| 1848 | |||
| 1849 | // Use jQuery if it exists with proper functionality, otherwise default to us. | ||
| 1850 | // Angular 1.2+ requires jQuery 1.7+ for on()/off() support. | ||
| 1851 | // Angular 1.3+ technically requires at least jQuery 2.1+ but it may work with older | ||
| 1852 | // versions. It will not work for sure with jQuery <1.7, though. | ||
| 1853 | if (jQuery && jQuery.fn.on) { | ||
| 1854 | jqLite = jQuery; | ||
| 1855 | extend(jQuery.fn, { | ||
| 1856 | scope: JQLitePrototype.scope, | ||
| 1857 | isolateScope: JQLitePrototype.isolateScope, | ||
| 1858 | controller: JQLitePrototype.controller, | ||
| 1859 | injector: JQLitePrototype.injector, | ||
| 1860 | inheritedData: JQLitePrototype.inheritedData | ||
| 1861 | }); | ||
| 1862 | |||
| 1863 | // All nodes removed from the DOM via various jQuery APIs like .remove() | ||
| 1864 | // are passed through jQuery.cleanData. Monkey-patch this method to fire | ||
| 1865 | // the $destroy event on all removed nodes. | ||
| 1866 | originalCleanData = jQuery.cleanData; | ||
| 1867 | jQuery.cleanData = function(elems) { | ||
| 1868 | var events; | ||
| 1869 | for (var i = 0, elem; (elem = elems[i]) != null; i++) { | ||
| 1870 | events = jQuery._data(elem, "events"); | ||
| 1871 | if (events && events.$destroy) { | ||
| 1872 | jQuery(elem).triggerHandler('$destroy'); | ||
| 1873 | } | ||
| 1874 | } | ||
| 1875 | originalCleanData(elems); | ||
| 1876 | }; | ||
| 1877 | } else { | ||
| 1878 | jqLite = JQLite; | ||
| 1879 | } | ||
| 1880 | |||
| 1881 | angular.element = jqLite; | ||
| 1882 | |||
| 1883 | // Prevent double-proxying. | ||
| 1884 | bindJQueryFired = true; | ||
| 1885 | } | ||
| 1886 | |||
| 1887 | /** | ||
| 1888 | * throw error if the argument is falsy. | ||
| 1889 | */ | ||
| 1890 | function assertArg(arg, name, reason) { | ||
| 1891 | if (!arg) { | ||
| 1892 | throw ngMinErr('areq', "Argument '{0}' is {1}", (name || '?'), (reason || "required")); | ||
| 1893 | } | ||
| 1894 | return arg; | ||
| 1895 | } | ||
| 1896 | |||
| 1897 | function assertArgFn(arg, name, acceptArrayAnnotation) { | ||
| 1898 | if (acceptArrayAnnotation && isArray(arg)) { | ||
| 1899 | arg = arg[arg.length - 1]; | ||
| 1900 | } | ||
| 1901 | |||
| 1902 | assertArg(isFunction(arg), name, 'not a function, got ' + | ||
| 1903 | (arg && typeof arg === 'object' ? arg.constructor.name || 'Object' : typeof arg)); | ||
| 1904 | return arg; | ||
| 1905 | } | ||
| 1906 | |||
| 1907 | /** | ||
| 1908 | * throw error if the name given is hasOwnProperty | ||
| 1909 | * @param {String} name the name to test | ||
| 1910 | * @param {String} context the context in which the name is used, such as module or directive | ||
| 1911 | */ | ||
| 1912 | function assertNotHasOwnProperty(name, context) { | ||
| 1913 | if (name === 'hasOwnProperty') { | ||
| 1914 | throw ngMinErr('badname', "hasOwnProperty is not a valid {0} name", context); | ||
| 1915 | } | ||
| 1916 | } | ||
| 1917 | |||
| 1918 | /** | ||
| 1919 | * Return the value accessible from the object by path. Any undefined traversals are ignored | ||
| 1920 | * @param {Object} obj starting object | ||
| 1921 | * @param {String} path path to traverse | ||
| 1922 | * @param {boolean} [bindFnToScope=true] | ||
| 1923 | * @returns {Object} value as accessible by path | ||
| 1924 | */ | ||
| 1925 | //TODO(misko): this function needs to be removed | ||
| 1926 | function getter(obj, path, bindFnToScope) { | ||
| 1927 | if (!path) return obj; | ||
| 1928 | var keys = path.split('.'); | ||
| 1929 | var key; | ||
| 1930 | var lastInstance = obj; | ||
| 1931 | var len = keys.length; | ||
| 1932 | |||
| 1933 | for (var i = 0; i < len; i++) { | ||
| 1934 | key = keys[i]; | ||
| 1935 | if (obj) { | ||
| 1936 | obj = (lastInstance = obj)[key]; | ||
| 1937 | } | ||
| 1938 | } | ||
| 1939 | if (!bindFnToScope && isFunction(obj)) { | ||
| 1940 | return bind(lastInstance, obj); | ||
| 1941 | } | ||
| 1942 | return obj; | ||
| 1943 | } | ||
| 1944 | |||
| 1945 | /** | ||
| 1946 | * Return the DOM siblings between the first and last node in the given array. | ||
| 1947 | * @param {Array} array like object | ||
| 1948 | * @returns {Array} the inputted object or a jqLite collection containing the nodes | ||
| 1949 | */ | ||
| 1950 | function getBlockNodes(nodes) { | ||
| 1951 | // TODO(perf): update `nodes` instead of creating a new object? | ||
| 1952 | var node = nodes[0]; | ||
| 1953 | var endNode = nodes[nodes.length - 1]; | ||
| 1954 | var blockNodes; | ||
| 1955 | |||
| 1956 | for (var i = 1; node !== endNode && (node = node.nextSibling); i++) { | ||
| 1957 | if (blockNodes || nodes[i] !== node) { | ||
| 1958 | if (!blockNodes) { | ||
| 1959 | blockNodes = jqLite(slice.call(nodes, 0, i)); | ||
| 1960 | } | ||
| 1961 | blockNodes.push(node); | ||
| 1962 | } | ||
| 1963 | } | ||
| 1964 | |||
| 1965 | return blockNodes || nodes; | ||
| 1966 | } | ||
| 1967 | |||
| 1968 | |||
| 1969 | /** | ||
| 1970 | * Creates a new object without a prototype. This object is useful for lookup without having to | ||
| 1971 | * guard against prototypically inherited properties via hasOwnProperty. | ||
| 1972 | * | ||
| 1973 | * Related micro-benchmarks: | ||
| 1974 | * - http://jsperf.com/object-create2 | ||
| 1975 | * - http://jsperf.com/proto-map-lookup/2 | ||
| 1976 | * - http://jsperf.com/for-in-vs-object-keys2 | ||
| 1977 | * | ||
| 1978 | * @returns {Object} | ||
| 1979 | */ | ||
| 1980 | function createMap() { | ||
| 1981 | return Object.create(null); | ||
| 1982 | } | ||
| 1983 | |||
| 1984 | var NODE_TYPE_ELEMENT = 1; | ||
| 1985 | var NODE_TYPE_ATTRIBUTE = 2; | ||
| 1986 | var NODE_TYPE_TEXT = 3; | ||
| 1987 | var NODE_TYPE_COMMENT = 8; | ||
| 1988 | var NODE_TYPE_DOCUMENT = 9; | ||
| 1989 | var NODE_TYPE_DOCUMENT_FRAGMENT = 11; | ||
| 1990 | |||
| 1991 | /** | ||
| 1992 | * @ngdoc type | ||
| 1993 | * @name angular.Module | ||
| 1994 | * @module ng | ||
| 1995 | * @description | ||
| 1996 | * | ||
| 1997 | * Interface for configuring angular {@link angular.module modules}. | ||
| 1998 | */ | ||
| 1999 | |||
| 2000 | function setupModuleLoader(window) { | ||
| 2001 | |||
| 2002 | var $injectorMinErr = minErr('$injector'); | ||
| 2003 | var ngMinErr = minErr('ng'); | ||
| 2004 | |||
| 2005 | function ensure(obj, name, factory) { | ||
| 2006 | return obj[name] || (obj[name] = factory()); | ||
| 2007 | } | ||
| 2008 | |||
| 2009 | var angular = ensure(window, 'angular', Object); | ||
| 2010 | |||
| 2011 | // We need to expose `angular.$$minErr` to modules such as `ngResource` that reference it during bootstrap | ||
| 2012 | angular.$$minErr = angular.$$minErr || minErr; | ||
| 2013 | |||
| 2014 | return ensure(angular, 'module', function() { | ||
| 2015 | /** @type {Object.<string, angular.Module>} */ | ||
| 2016 | var modules = {}; | ||
| 2017 | |||
| 2018 | /** | ||
| 2019 | * @ngdoc function | ||
| 2020 | * @name angular.module | ||
| 2021 | * @module ng | ||
| 2022 | * @description | ||
| 2023 | * | ||
| 2024 | * The `angular.module` is a global place for creating, registering and retrieving Angular | ||
| 2025 | * modules. | ||
| 2026 | * All modules (angular core or 3rd party) that should be available to an application must be | ||
| 2027 | * registered using this mechanism. | ||
| 2028 | * | ||
| 2029 | * Passing one argument retrieves an existing {@link angular.Module}, | ||
| 2030 | * whereas passing more than one argument creates a new {@link angular.Module} | ||
| 2031 | * | ||
| 2032 | * | ||
| 2033 | * # Module | ||
| 2034 | * | ||
| 2035 | * A module is a collection of services, directives, controllers, filters, and configuration information. | ||
| 2036 | * `angular.module` is used to configure the {@link auto.$injector $injector}. | ||
| 2037 | * | ||
| 2038 | * ```js | ||
| 2039 | * // Create a new module | ||
| 2040 | * var myModule = angular.module('myModule', []); | ||
| 2041 | * | ||
| 2042 | * // register a new service | ||
| 2043 | * myModule.value('appName', 'MyCoolApp'); | ||
| 2044 | * | ||
| 2045 | * // configure existing services inside initialization blocks. | ||
| 2046 | * myModule.config(['$locationProvider', function($locationProvider) { | ||
| 2047 | * // Configure existing providers | ||
| 2048 | * $locationProvider.hashPrefix('!'); | ||
| 2049 | * }]); | ||
| 2050 | * ``` | ||
| 2051 | * | ||
| 2052 | * Then you can create an injector and load your modules like this: | ||
| 2053 | * | ||
| 2054 | * ```js | ||
| 2055 | * var injector = angular.injector(['ng', 'myModule']) | ||
| 2056 | * ``` | ||
| 2057 | * | ||
| 2058 | * However it's more likely that you'll just use | ||
| 2059 | * {@link ng.directive:ngApp ngApp} or | ||
| 2060 | * {@link angular.bootstrap} to simplify this process for you. | ||
| 2061 | * | ||
| 2062 | * @param {!string} name The name of the module to create or retrieve. | ||
| 2063 | * @param {!Array.<string>=} requires If specified then new module is being created. If | ||
| 2064 | * unspecified then the module is being retrieved for further configuration. | ||
| 2065 | * @param {Function=} configFn Optional configuration function for the module. Same as | ||
| 2066 | * {@link angular.Module#config Module#config()}. | ||
| 2067 | * @returns {angular.Module} new module with the {@link angular.Module} api. | ||
| 2068 | */ | ||
| 2069 | return function module(name, requires, configFn) { | ||
| 2070 | var assertNotHasOwnProperty = function(name, context) { | ||
| 2071 | if (name === 'hasOwnProperty') { | ||
| 2072 | throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context); | ||
| 2073 | } | ||
| 2074 | }; | ||
| 2075 | |||
| 2076 | assertNotHasOwnProperty(name, 'module'); | ||
| 2077 | if (requires && modules.hasOwnProperty(name)) { | ||
| 2078 | modules[name] = null; | ||
| 2079 | } | ||
| 2080 | return ensure(modules, name, function() { | ||
| 2081 | if (!requires) { | ||
| 2082 | throw $injectorMinErr('nomod', "Module '{0}' is not available! You either misspelled " + | ||
| 2083 | "the module name or forgot to load it. If registering a module ensure that you " + | ||
| 2084 | "specify the dependencies as the second argument.", name); | ||
| 2085 | } | ||
| 2086 | |||
| 2087 | /** @type {!Array.<Array.<*>>} */ | ||
| 2088 | var invokeQueue = []; | ||
| 2089 | |||
| 2090 | /** @type {!Array.<Function>} */ | ||
| 2091 | var configBlocks = []; | ||
| 2092 | |||
| 2093 | /** @type {!Array.<Function>} */ | ||
| 2094 | var runBlocks = []; | ||
| 2095 | |||
| 2096 | var config = invokeLater('$injector', 'invoke', 'push', configBlocks); | ||
| 2097 | |||
| 2098 | /** @type {angular.Module} */ | ||
| 2099 | var moduleInstance = { | ||
| 2100 | // Private state | ||
| 2101 | _invokeQueue: invokeQueue, | ||
| 2102 | _configBlocks: configBlocks, | ||
| 2103 | _runBlocks: runBlocks, | ||
| 2104 | |||
| 2105 | /** | ||
| 2106 | * @ngdoc property | ||
| 2107 | * @name angular.Module#requires | ||
| 2108 | * @module ng | ||
| 2109 | * | ||
| 2110 | * @description | ||
| 2111 | * Holds the list of modules which the injector will load before the current module is | ||
| 2112 | * loaded. | ||
| 2113 | */ | ||
| 2114 | requires: requires, | ||
| 2115 | |||
| 2116 | /** | ||
| 2117 | * @ngdoc property | ||
| 2118 | * @name angular.Module#name | ||
| 2119 | * @module ng | ||
| 2120 | * | ||
| 2121 | * @description | ||
| 2122 | * Name of the module. | ||
| 2123 | */ | ||
| 2124 | name: name, | ||
| 2125 | |||
| 2126 | |||
| 2127 | /** | ||
| 2128 | * @ngdoc method | ||
| 2129 | * @name angular.Module#provider | ||
| 2130 | * @module ng | ||
| 2131 | * @param {string} name service name | ||
| 2132 | * @param {Function} providerType Construction function for creating new instance of the | ||
| 2133 | * service. | ||
| 2134 | * @description | ||
| 2135 | * See {@link auto.$provide#provider $provide.provider()}. | ||
| 2136 | */ | ||
| 2137 | provider: invokeLaterAndSetModuleName('$provide', 'provider'), | ||
| 2138 | |||
| 2139 | /** | ||
| 2140 | * @ngdoc method | ||
| 2141 | * @name angular.Module#factory | ||
| 2142 | * @module ng | ||
| 2143 | * @param {string} name service name | ||
| 2144 | * @param {Function} providerFunction Function for creating new instance of the service. | ||
| 2145 | * @description | ||
| 2146 | * See {@link auto.$provide#factory $provide.factory()}. | ||
| 2147 | */ | ||
| 2148 | factory: invokeLaterAndSetModuleName('$provide', 'factory'), | ||
| 2149 | |||
| 2150 | /** | ||
| 2151 | * @ngdoc method | ||
| 2152 | * @name angular.Module#service | ||
| 2153 | * @module ng | ||
| 2154 | * @param {string} name service name | ||
| 2155 | * @param {Function} constructor A constructor function that will be instantiated. | ||
| 2156 | * @description | ||
| 2157 | * See {@link auto.$provide#service $provide.service()}. | ||
| 2158 | */ | ||
| 2159 | service: invokeLaterAndSetModuleName('$provide', 'service'), | ||
| 2160 | |||
| 2161 | /** | ||
| 2162 | * @ngdoc method | ||
| 2163 | * @name angular.Module#value | ||
| 2164 | * @module ng | ||
| 2165 | * @param {string} name service name | ||
| 2166 | * @param {*} object Service instance object. | ||
| 2167 | * @description | ||
| 2168 | * See {@link auto.$provide#value $provide.value()}. | ||
| 2169 | */ | ||
| 2170 | value: invokeLater('$provide', 'value'), | ||
| 2171 | |||
| 2172 | /** | ||
| 2173 | * @ngdoc method | ||
| 2174 | * @name angular.Module#constant | ||
| 2175 | * @module ng | ||
| 2176 | * @param {string} name constant name | ||
| 2177 | * @param {*} object Constant value. | ||
| 2178 | * @description | ||
| 2179 | * Because the constants are fixed, they get applied before other provide methods. | ||
| 2180 | * See {@link auto.$provide#constant $provide.constant()}. | ||
| 2181 | */ | ||
| 2182 | constant: invokeLater('$provide', 'constant', 'unshift'), | ||
| 2183 | |||
| 2184 | /** | ||
| 2185 | * @ngdoc method | ||
| 2186 | * @name angular.Module#decorator | ||
| 2187 | * @module ng | ||
| 2188 | * @param {string} name The name of the service to decorate. | ||
| 2189 | * @param {Function} decorFn This function will be invoked when the service needs to be | ||
| 2190 | * instantiated and should return the decorated service instance. | ||
| 2191 | * @description | ||
| 2192 | * See {@link auto.$provide#decorator $provide.decorator()}. | ||
| 2193 | */ | ||
| 2194 | decorator: invokeLaterAndSetModuleName('$provide', 'decorator'), | ||
| 2195 | |||
| 2196 | /** | ||
| 2197 | * @ngdoc method | ||
| 2198 | * @name angular.Module#animation | ||
| 2199 | * @module ng | ||
| 2200 | * @param {string} name animation name | ||
| 2201 | * @param {Function} animationFactory Factory function for creating new instance of an | ||
| 2202 | * animation. | ||
| 2203 | * @description | ||
| 2204 | * | ||
| 2205 | * **NOTE**: animations take effect only if the **ngAnimate** module is loaded. | ||
| 2206 | * | ||
| 2207 | * | ||
| 2208 | * Defines an animation hook that can be later used with | ||
| 2209 | * {@link $animate $animate} service and directives that use this service. | ||
| 2210 | * | ||
| 2211 | * ```js | ||
| 2212 | * module.animation('.animation-name', function($inject1, $inject2) { | ||
| 2213 | * return { | ||
| 2214 | * eventName : function(element, done) { | ||
| 2215 | * //code to run the animation | ||
| 2216 | * //once complete, then run done() | ||
| 2217 | * return function cancellationFunction(element) { | ||
| 2218 | * //code to cancel the animation | ||
| 2219 | * } | ||
| 2220 | * } | ||
| 2221 | * } | ||
| 2222 | * }) | ||
| 2223 | * ``` | ||
| 2224 | * | ||
| 2225 | * See {@link ng.$animateProvider#register $animateProvider.register()} and | ||
| 2226 | * {@link ngAnimate ngAnimate module} for more information. | ||
| 2227 | */ | ||
| 2228 | animation: invokeLaterAndSetModuleName('$animateProvider', 'register'), | ||
| 2229 | |||
| 2230 | /** | ||
| 2231 | * @ngdoc method | ||
| 2232 | * @name angular.Module#filter | ||
| 2233 | * @module ng | ||
| 2234 | * @param {string} name Filter name - this must be a valid angular expression identifier | ||
| 2235 | * @param {Function} filterFactory Factory function for creating new instance of filter. | ||
| 2236 | * @description | ||
| 2237 | * See {@link ng.$filterProvider#register $filterProvider.register()}. | ||
| 2238 | * | ||
| 2239 | * <div class="alert alert-warning"> | ||
| 2240 | * **Note:** Filter names must be valid angular {@link expression} identifiers, such as `uppercase` or `orderBy`. | ||
| 2241 | * Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace | ||
| 2242 | * your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores | ||
| 2243 | * (`myapp_subsection_filterx`). | ||
| 2244 | * </div> | ||
| 2245 | */ | ||
| 2246 | filter: invokeLaterAndSetModuleName('$filterProvider', 'register'), | ||
| 2247 | |||
| 2248 | /** | ||
| 2249 | * @ngdoc method | ||
| 2250 | * @name angular.Module#controller | ||
| 2251 | * @module ng | ||
| 2252 | * @param {string|Object} name Controller name, or an object map of controllers where the | ||
| 2253 | * keys are the names and the values are the constructors. | ||
| 2254 | * @param {Function} constructor Controller constructor function. | ||
| 2255 | * @description | ||
| 2256 | * See {@link ng.$controllerProvider#register $controllerProvider.register()}. | ||
| 2257 | */ | ||
| 2258 | controller: invokeLaterAndSetModuleName('$controllerProvider', 'register'), | ||
| 2259 | |||
| 2260 | /** | ||
| 2261 | * @ngdoc method | ||
| 2262 | * @name angular.Module#directive | ||
| 2263 | * @module ng | ||
| 2264 | * @param {string|Object} name Directive name, or an object map of directives where the | ||
| 2265 | * keys are the names and the values are the factories. | ||
| 2266 | * @param {Function} directiveFactory Factory function for creating new instance of | ||
| 2267 | * directives. | ||
| 2268 | * @description | ||
| 2269 | * See {@link ng.$compileProvider#directive $compileProvider.directive()}. | ||
| 2270 | */ | ||
| 2271 | directive: invokeLaterAndSetModuleName('$compileProvider', 'directive'), | ||
| 2272 | |||
| 2273 | /** | ||
| 2274 | * @ngdoc method | ||
| 2275 | * @name angular.Module#component | ||
| 2276 | * @module ng | ||
| 2277 | * @param {string} name Name of the component in camel-case (i.e. myComp which will match as my-comp) | ||
| 2278 | * @param {Object} options Component definition object (a simplified | ||
| 2279 | * {@link ng.$compile#directive-definition-object directive definition object}) | ||
| 2280 | * | ||
| 2281 | * @description | ||
| 2282 | * See {@link ng.$compileProvider#component $compileProvider.component()}. | ||
| 2283 | */ | ||
| 2284 | component: invokeLaterAndSetModuleName('$compileProvider', 'component'), | ||
| 2285 | |||
| 2286 | /** | ||
| 2287 | * @ngdoc method | ||
| 2288 | * @name angular.Module#config | ||
| 2289 | * @module ng | ||
| 2290 | * @param {Function} configFn Execute this function on module load. Useful for service | ||
| 2291 | * configuration. | ||
| 2292 | * @description | ||
| 2293 | * Use this method to register work which needs to be performed on module loading. | ||
| 2294 | * For more about how to configure services, see | ||
| 2295 | * {@link providers#provider-recipe Provider Recipe}. | ||
| 2296 | */ | ||
| 2297 | config: config, | ||
| 2298 | |||
| 2299 | /** | ||
| 2300 | * @ngdoc method | ||
| 2301 | * @name angular.Module#run | ||
| 2302 | * @module ng | ||
| 2303 | * @param {Function} initializationFn Execute this function after injector creation. | ||
| 2304 | * Useful for application initialization. | ||
| 2305 | * @description | ||
| 2306 | * Use this method to register work which should be performed when the injector is done | ||
| 2307 | * loading all modules. | ||
| 2308 | */ | ||
| 2309 | run: function(block) { | ||
| 2310 | runBlocks.push(block); | ||
| 2311 | return this; | ||
| 2312 | } | ||
| 2313 | }; | ||
| 2314 | |||
| 2315 | if (configFn) { | ||
| 2316 | config(configFn); | ||
| 2317 | } | ||
| 2318 | |||
| 2319 | return moduleInstance; | ||
| 2320 | |||
| 2321 | /** | ||
| 2322 | * @param {string} provider | ||
| 2323 | * @param {string} method | ||
| 2324 | * @param {String=} insertMethod | ||
| 2325 | * @returns {angular.Module} | ||
| 2326 | */ | ||
| 2327 | function invokeLater(provider, method, insertMethod, queue) { | ||
| 2328 | if (!queue) queue = invokeQueue; | ||
| 2329 | return function() { | ||
| 2330 | queue[insertMethod || 'push']([provider, method, arguments]); | ||
| 2331 | return moduleInstance; | ||
| 2332 | }; | ||
| 2333 | } | ||
| 2334 | |||
| 2335 | /** | ||
| 2336 | * @param {string} provider | ||
| 2337 | * @param {string} method | ||
| 2338 | * @returns {angular.Module} | ||
| 2339 | */ | ||
| 2340 | function invokeLaterAndSetModuleName(provider, method) { | ||
| 2341 | return function(recipeName, factoryFunction) { | ||
| 2342 | if (factoryFunction && isFunction(factoryFunction)) factoryFunction.$$moduleName = name; | ||
| 2343 | invokeQueue.push([provider, method, arguments]); | ||
| 2344 | return moduleInstance; | ||
| 2345 | }; | ||
| 2346 | } | ||
| 2347 | }); | ||
| 2348 | }; | ||
| 2349 | }); | ||
| 2350 | |||
| 2351 | } | ||
| 2352 | |||
| 2353 | /* global shallowCopy: true */ | ||
| 2354 | |||
| 2355 | /** | ||
| 2356 | * Creates a shallow copy of an object, an array or a primitive. | ||
| 2357 | * | ||
| 2358 | * Assumes that there are no proto properties for objects. | ||
| 2359 | */ | ||
| 2360 | function shallowCopy(src, dst) { | ||
| 2361 | if (isArray(src)) { | ||
| 2362 | dst = dst || []; | ||
| 2363 | |||
| 2364 | for (var i = 0, ii = src.length; i < ii; i++) { | ||
| 2365 | dst[i] = src[i]; | ||
| 2366 | } | ||
| 2367 | } else if (isObject(src)) { | ||
| 2368 | dst = dst || {}; | ||
| 2369 | |||
| 2370 | for (var key in src) { | ||
| 2371 | if (!(key.charAt(0) === '$' && key.charAt(1) === '$')) { | ||
| 2372 | dst[key] = src[key]; | ||
| 2373 | } | ||
| 2374 | } | ||
| 2375 | } | ||
| 2376 | |||
| 2377 | return dst || src; | ||
| 2378 | } | ||
| 2379 | |||
| 2380 | /* global toDebugString: true */ | ||
| 2381 | |||
| 2382 | function serializeObject(obj) { | ||
| 2383 | var seen = []; | ||
| 2384 | |||
| 2385 | return JSON.stringify(obj, function(key, val) { | ||
| 2386 | val = toJsonReplacer(key, val); | ||
| 2387 | if (isObject(val)) { | ||
| 2388 | |||
| 2389 | if (seen.indexOf(val) >= 0) return '...'; | ||
| 2390 | |||
| 2391 | seen.push(val); | ||
| 2392 | } | ||
| 2393 | return val; | ||
| 2394 | }); | ||
| 2395 | } | ||
| 2396 | |||
| 2397 | function toDebugString(obj) { | ||
| 2398 | if (typeof obj === 'function') { | ||
| 2399 | return obj.toString().replace(/ \{[\s\S]*$/, ''); | ||
| 2400 | } else if (isUndefined(obj)) { | ||
| 2401 | return 'undefined'; | ||
| 2402 | } else if (typeof obj !== 'string') { | ||
| 2403 | return serializeObject(obj); | ||
| 2404 | } | ||
| 2405 | return obj; | ||
| 2406 | } | ||
| 2407 | |||
| 2408 | /* global angularModule: true, | ||
| 2409 | version: true, | ||
| 2410 | |||
| 2411 | $CompileProvider, | ||
| 2412 | |||
| 2413 | htmlAnchorDirective, | ||
| 2414 | inputDirective, | ||
| 2415 | inputDirective, | ||
| 2416 | formDirective, | ||
| 2417 | scriptDirective, | ||
| 2418 | selectDirective, | ||
| 2419 | styleDirective, | ||
| 2420 | optionDirective, | ||
| 2421 | ngBindDirective, | ||
| 2422 | ngBindHtmlDirective, | ||
| 2423 | ngBindTemplateDirective, | ||
| 2424 | ngClassDirective, | ||
| 2425 | ngClassEvenDirective, | ||
| 2426 | ngClassOddDirective, | ||
| 2427 | ngCloakDirective, | ||
| 2428 | ngControllerDirective, | ||
| 2429 | ngFormDirective, | ||
| 2430 | ngHideDirective, | ||
| 2431 | ngIfDirective, | ||
| 2432 | ngIncludeDirective, | ||
| 2433 | ngIncludeFillContentDirective, | ||
| 2434 | ngInitDirective, | ||
| 2435 | ngNonBindableDirective, | ||
| 2436 | ngPluralizeDirective, | ||
| 2437 | ngRepeatDirective, | ||
| 2438 | ngShowDirective, | ||
| 2439 | ngStyleDirective, | ||
| 2440 | ngSwitchDirective, | ||
| 2441 | ngSwitchWhenDirective, | ||
| 2442 | ngSwitchDefaultDirective, | ||
| 2443 | ngOptionsDirective, | ||
| 2444 | ngTranscludeDirective, | ||
| 2445 | ngModelDirective, | ||
| 2446 | ngListDirective, | ||
| 2447 | ngChangeDirective, | ||
| 2448 | patternDirective, | ||
| 2449 | patternDirective, | ||
| 2450 | requiredDirective, | ||
| 2451 | requiredDirective, | ||
| 2452 | minlengthDirective, | ||
| 2453 | minlengthDirective, | ||
| 2454 | maxlengthDirective, | ||
| 2455 | maxlengthDirective, | ||
| 2456 | ngValueDirective, | ||
| 2457 | ngModelOptionsDirective, | ||
| 2458 | ngAttributeAliasDirectives, | ||
| 2459 | ngEventDirectives, | ||
| 2460 | |||
| 2461 | $AnchorScrollProvider, | ||
| 2462 | $AnimateProvider, | ||
| 2463 | $CoreAnimateCssProvider, | ||
| 2464 | $$CoreAnimateJsProvider, | ||
| 2465 | $$CoreAnimateQueueProvider, | ||
| 2466 | $$AnimateRunnerFactoryProvider, | ||
| 2467 | $$AnimateAsyncRunFactoryProvider, | ||
| 2468 | $BrowserProvider, | ||
| 2469 | $CacheFactoryProvider, | ||
| 2470 | $ControllerProvider, | ||
| 2471 | $DateProvider, | ||
| 2472 | $DocumentProvider, | ||
| 2473 | $ExceptionHandlerProvider, | ||
| 2474 | $FilterProvider, | ||
| 2475 | $$ForceReflowProvider, | ||
| 2476 | $InterpolateProvider, | ||
| 2477 | $IntervalProvider, | ||
| 2478 | $$HashMapProvider, | ||
| 2479 | $HttpProvider, | ||
| 2480 | $HttpParamSerializerProvider, | ||
| 2481 | $HttpParamSerializerJQLikeProvider, | ||
| 2482 | $HttpBackendProvider, | ||
| 2483 | $xhrFactoryProvider, | ||
| 2484 | $jsonpCallbacksProvider, | ||
| 2485 | $LocationProvider, | ||
| 2486 | $LogProvider, | ||
| 2487 | $ParseProvider, | ||
| 2488 | $RootScopeProvider, | ||
| 2489 | $QProvider, | ||
| 2490 | $$QProvider, | ||
| 2491 | $$SanitizeUriProvider, | ||
| 2492 | $SceProvider, | ||
| 2493 | $SceDelegateProvider, | ||
| 2494 | $SnifferProvider, | ||
| 2495 | $TemplateCacheProvider, | ||
| 2496 | $TemplateRequestProvider, | ||
| 2497 | $$TestabilityProvider, | ||
| 2498 | $TimeoutProvider, | ||
| 2499 | $$RAFProvider, | ||
| 2500 | $WindowProvider, | ||
| 2501 | $$jqLiteProvider, | ||
| 2502 | $$CookieReaderProvider | ||
| 2503 | */ | ||
| 2504 | |||
| 2505 | |||
| 2506 | /** | ||
| 2507 | * @ngdoc object | ||
| 2508 | * @name angular.version | ||
| 2509 | * @module ng | ||
| 2510 | * @description | ||
| 2511 | * An object that contains information about the current AngularJS version. | ||
| 2512 | * | ||
| 2513 | * This object has the following properties: | ||
| 2514 | * | ||
| 2515 | * - `full` – `{string}` – Full version string, such as "0.9.18". | ||
| 2516 | * - `major` – `{number}` – Major version number, such as "0". | ||
| 2517 | * - `minor` – `{number}` – Minor version number, such as "9". | ||
| 2518 | * - `dot` – `{number}` – Dot version number, such as "18". | ||
| 2519 | * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat". | ||
| 2520 | */ | ||
| 2521 | var version = { | ||
| 2522 | full: '1.5.8', // all of these placeholder strings will be replaced by grunt's | ||
| 2523 | major: 1, // package task | ||
| 2524 | minor: 5, | ||
| 2525 | dot: 8, | ||
| 2526 | codeName: 'arbitrary-fallbacks' | ||
| 2527 | }; | ||
| 2528 | |||
| 2529 | |||
| 2530 | function publishExternalAPI(angular) { | ||
| 2531 | extend(angular, { | ||
| 2532 | 'bootstrap': bootstrap, | ||
| 2533 | 'copy': copy, | ||
| 2534 | 'extend': extend, | ||
| 2535 | 'merge': merge, | ||
| 2536 | 'equals': equals, | ||
| 2537 | 'element': jqLite, | ||
| 2538 | 'forEach': forEach, | ||
| 2539 | 'injector': createInjector, | ||
| 2540 | 'noop': noop, | ||
| 2541 | 'bind': bind, | ||
| 2542 | 'toJson': toJson, | ||
| 2543 | 'fromJson': fromJson, | ||
| 2544 | 'identity': identity, | ||
| 2545 | 'isUndefined': isUndefined, | ||
| 2546 | 'isDefined': isDefined, | ||
| 2547 | 'isString': isString, | ||
| 2548 | 'isFunction': isFunction, | ||
| 2549 | 'isObject': isObject, | ||
| 2550 | 'isNumber': isNumber, | ||
| 2551 | 'isElement': isElement, | ||
| 2552 | 'isArray': isArray, | ||
| 2553 | 'version': version, | ||
| 2554 | 'isDate': isDate, | ||
| 2555 | 'lowercase': lowercase, | ||
| 2556 | 'uppercase': uppercase, | ||
| 2557 | 'callbacks': {$$counter: 0}, | ||
| 2558 | 'getTestability': getTestability, | ||
| 2559 | '$$minErr': minErr, | ||
| 2560 | '$$csp': csp, | ||
| 2561 | 'reloadWithDebugInfo': reloadWithDebugInfo | ||
| 2562 | }); | ||
| 2563 | |||
| 2564 | angularModule = setupModuleLoader(window); | ||
| 2565 | |||
| 2566 | angularModule('ng', ['ngLocale'], ['$provide', | ||
| 2567 | function ngModule($provide) { | ||
| 2568 | // $$sanitizeUriProvider needs to be before $compileProvider as it is used by it. | ||
| 2569 | $provide.provider({ | ||
| 2570 | $$sanitizeUri: $$SanitizeUriProvider | ||
| 2571 | }); | ||
| 2572 | $provide.provider('$compile', $CompileProvider). | ||
| 2573 | directive({ | ||
| 2574 | a: htmlAnchorDirective, | ||
| 2575 | input: inputDirective, | ||
| 2576 | textarea: inputDirective, | ||
| 2577 | form: formDirective, | ||
| 2578 | script: scriptDirective, | ||
| 2579 | select: selectDirective, | ||
| 2580 | style: styleDirective, | ||
| 2581 | option: optionDirective, | ||
| 2582 | ngBind: ngBindDirective, | ||
| 2583 | ngBindHtml: ngBindHtmlDirective, | ||
| 2584 | ngBindTemplate: ngBindTemplateDirective, | ||
| 2585 | ngClass: ngClassDirective, | ||
| 2586 | ngClassEven: ngClassEvenDirective, | ||
| 2587 | ngClassOdd: ngClassOddDirective, | ||
| 2588 | ngCloak: ngCloakDirective, | ||
| 2589 | ngController: ngControllerDirective, | ||
| 2590 | ngForm: ngFormDirective, | ||
| 2591 | ngHide: ngHideDirective, | ||
| 2592 | ngIf: ngIfDirective, | ||
| 2593 | ngInclude: ngIncludeDirective, | ||
| 2594 | ngInit: ngInitDirective, | ||
| 2595 | ngNonBindable: ngNonBindableDirective, | ||
| 2596 | ngPluralize: ngPluralizeDirective, | ||
| 2597 | ngRepeat: ngRepeatDirective, | ||
| 2598 | ngShow: ngShowDirective, | ||
| 2599 | ngStyle: ngStyleDirective, | ||
| 2600 | ngSwitch: ngSwitchDirective, | ||
| 2601 | ngSwitchWhen: ngSwitchWhenDirective, | ||
| 2602 | ngSwitchDefault: ngSwitchDefaultDirective, | ||
| 2603 | ngOptions: ngOptionsDirective, | ||
| 2604 | ngTransclude: ngTranscludeDirective, | ||
| 2605 | ngModel: ngModelDirective, | ||
| 2606 | ngList: ngListDirective, | ||
| 2607 | ngChange: ngChangeDirective, | ||
| 2608 | pattern: patternDirective, | ||
| 2609 | ngPattern: patternDirective, | ||
| 2610 | required: requiredDirective, | ||
| 2611 | ngRequired: requiredDirective, | ||
| 2612 | minlength: minlengthDirective, | ||
| 2613 | ngMinlength: minlengthDirective, | ||
| 2614 | maxlength: maxlengthDirective, | ||
| 2615 | ngMaxlength: maxlengthDirective, | ||
| 2616 | ngValue: ngValueDirective, | ||
| 2617 | ngModelOptions: ngModelOptionsDirective | ||
| 2618 | }). | ||
| 2619 | directive({ | ||
| 2620 | ngInclude: ngIncludeFillContentDirective | ||
| 2621 | }). | ||
| 2622 | directive(ngAttributeAliasDirectives). | ||
| 2623 | directive(ngEventDirectives); | ||
| 2624 | $provide.provider({ | ||
| 2625 | $anchorScroll: $AnchorScrollProvider, | ||
| 2626 | $animate: $AnimateProvider, | ||
| 2627 | $animateCss: $CoreAnimateCssProvider, | ||
| 2628 | $$animateJs: $$CoreAnimateJsProvider, | ||
| 2629 | $$animateQueue: $$CoreAnimateQueueProvider, | ||
| 2630 | $$AnimateRunner: $$AnimateRunnerFactoryProvider, | ||
| 2631 | $$animateAsyncRun: $$AnimateAsyncRunFactoryProvider, | ||
| 2632 | $browser: $BrowserProvider, | ||
| 2633 | $cacheFactory: $CacheFactoryProvider, | ||
| 2634 | $controller: $ControllerProvider, | ||
| 2635 | $document: $DocumentProvider, | ||
| 2636 | $exceptionHandler: $ExceptionHandlerProvider, | ||
| 2637 | $filter: $FilterProvider, | ||
| 2638 | $$forceReflow: $$ForceReflowProvider, | ||
| 2639 | $interpolate: $InterpolateProvider, | ||
| 2640 | $interval: $IntervalProvider, | ||
| 2641 | $http: $HttpProvider, | ||
| 2642 | $httpParamSerializer: $HttpParamSerializerProvider, | ||
| 2643 | $httpParamSerializerJQLike: $HttpParamSerializerJQLikeProvider, | ||
| 2644 | $httpBackend: $HttpBackendProvider, | ||
| 2645 | $xhrFactory: $xhrFactoryProvider, | ||
| 2646 | $jsonpCallbacks: $jsonpCallbacksProvider, | ||
| 2647 | $location: $LocationProvider, | ||
| 2648 | $log: $LogProvider, | ||
| 2649 | $parse: $ParseProvider, | ||
| 2650 | $rootScope: $RootScopeProvider, | ||
| 2651 | $q: $QProvider, | ||
| 2652 | $$q: $$QProvider, | ||
| 2653 | $sce: $SceProvider, | ||
| 2654 | $sceDelegate: $SceDelegateProvider, | ||
| 2655 | $sniffer: $SnifferProvider, | ||
| 2656 | $templateCache: $TemplateCacheProvider, | ||
| 2657 | $templateRequest: $TemplateRequestProvider, | ||
| 2658 | $$testability: $$TestabilityProvider, | ||
| 2659 | $timeout: $TimeoutProvider, | ||
| 2660 | $window: $WindowProvider, | ||
| 2661 | $$rAF: $$RAFProvider, | ||
| 2662 | $$jqLite: $$jqLiteProvider, | ||
| 2663 | $$HashMap: $$HashMapProvider, | ||
| 2664 | $$cookieReader: $$CookieReaderProvider | ||
| 2665 | }); | ||
| 2666 | } | ||
| 2667 | ]); | ||
| 2668 | } | ||
| 2669 | |||
| 2670 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||
| 2671 | * Any commits to this file should be reviewed with security in mind. * | ||
| 2672 | * Changes to this file can potentially create security vulnerabilities. * | ||
| 2673 | * An approval from 2 Core members with history of modifying * | ||
| 2674 | * this file is required. * | ||
| 2675 | * * | ||
| 2676 | * Does the change somehow allow for arbitrary javascript to be executed? * | ||
| 2677 | * Or allows for someone to change the prototype of built-in objects? * | ||
| 2678 | * Or gives undesired access to variables likes document or window? * | ||
| 2679 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | ||
| 2680 | |||
| 2681 | /* global JQLitePrototype: true, | ||
| 2682 | addEventListenerFn: true, | ||
| 2683 | removeEventListenerFn: true, | ||
| 2684 | BOOLEAN_ATTR: true, | ||
| 2685 | ALIASED_ATTR: true, | ||
| 2686 | */ | ||
| 2687 | |||
| 2688 | ////////////////////////////////// | ||
| 2689 | //JQLite | ||
| 2690 | ////////////////////////////////// | ||
| 2691 | |||
| 2692 | /** | ||
| 2693 | * @ngdoc function | ||
| 2694 | * @name angular.element | ||
| 2695 | * @module ng | ||
| 2696 | * @kind function | ||
| 2697 | * | ||
| 2698 | * @description | ||
| 2699 | * Wraps a raw DOM element or HTML string as a [jQuery](http://jquery.com) element. | ||
| 2700 | * | ||
| 2701 | * If jQuery is available, `angular.element` is an alias for the | ||
| 2702 | * [jQuery](http://api.jquery.com/jQuery/) function. If jQuery is not available, `angular.element` | ||
| 2703 | * delegates to Angular's built-in subset of jQuery, called "jQuery lite" or **jqLite**. | ||
| 2704 | * | ||
| 2705 | * jqLite is a tiny, API-compatible subset of jQuery that allows | ||
| 2706 | * Angular to manipulate the DOM in a cross-browser compatible way. jqLite implements only the most | ||
| 2707 | * commonly needed functionality with the goal of having a very small footprint. | ||
| 2708 | * | ||
| 2709 | * To use `jQuery`, simply ensure it is loaded before the `angular.js` file. You can also use the | ||
| 2710 | * {@link ngJq `ngJq`} directive to specify that jqlite should be used over jQuery, or to use a | ||
| 2711 | * specific version of jQuery if multiple versions exist on the page. | ||
| 2712 | * | ||
| 2713 | * <div class="alert alert-info">**Note:** All element references in Angular are always wrapped with jQuery or | ||
| 2714 | * jqLite (such as the element argument in a directive's compile / link function). They are never raw DOM references.</div> | ||
| 2715 | * | ||
| 2716 | * <div class="alert alert-warning">**Note:** Keep in mind that this function will not find elements | ||
| 2717 | * by tag name / CSS selector. For lookups by tag name, try instead `angular.element(document).find(...)` | ||
| 2718 | * or `$document.find()`, or use the standard DOM APIs, e.g. `document.querySelectorAll()`.</div> | ||
| 2719 | * | ||
| 2720 | * ## Angular's jqLite | ||
| 2721 | * jqLite provides only the following jQuery methods: | ||
| 2722 | * | ||
| 2723 | * - [`addClass()`](http://api.jquery.com/addClass/) - Does not support a function as first argument | ||
| 2724 | * - [`after()`](http://api.jquery.com/after/) | ||
| 2725 | * - [`append()`](http://api.jquery.com/append/) | ||
| 2726 | * - [`attr()`](http://api.jquery.com/attr/) - Does not support functions as parameters | ||
| 2727 | * - [`bind()`](http://api.jquery.com/bind/) - Does not support namespaces, selectors or eventData | ||
| 2728 | * - [`children()`](http://api.jquery.com/children/) - Does not support selectors | ||
| 2729 | * - [`clone()`](http://api.jquery.com/clone/) | ||
| 2730 | * - [`contents()`](http://api.jquery.com/contents/) | ||
| 2731 | * - [`css()`](http://api.jquery.com/css/) - Only retrieves inline-styles, does not call `getComputedStyle()`. | ||
| 2732 | * As a setter, does not convert numbers to strings or append 'px', and also does not have automatic property prefixing. | ||
| 2733 | * - [`data()`](http://api.jquery.com/data/) | ||
| 2734 | * - [`detach()`](http://api.jquery.com/detach/) | ||
| 2735 | * - [`empty()`](http://api.jquery.com/empty/) | ||
| 2736 | * - [`eq()`](http://api.jquery.com/eq/) | ||
| 2737 | * - [`find()`](http://api.jquery.com/find/) - Limited to lookups by tag name | ||
| 2738 | * - [`hasClass()`](http://api.jquery.com/hasClass/) | ||
| 2739 | * - [`html()`](http://api.jquery.com/html/) | ||
| 2740 | * - [`next()`](http://api.jquery.com/next/) - Does not support selectors | ||
| 2741 | * - [`on()`](http://api.jquery.com/on/) - Does not support namespaces, selectors or eventData | ||
| 2742 | * - [`off()`](http://api.jquery.com/off/) - Does not support namespaces, selectors or event object as parameter | ||
| 2743 | * - [`one()`](http://api.jquery.com/one/) - Does not support namespaces or selectors | ||
| 2744 | * - [`parent()`](http://api.jquery.com/parent/) - Does not support selectors | ||
| 2745 | * - [`prepend()`](http://api.jquery.com/prepend/) | ||
| 2746 | * - [`prop()`](http://api.jquery.com/prop/) | ||
| 2747 | * - [`ready()`](http://api.jquery.com/ready/) | ||
| 2748 | * - [`remove()`](http://api.jquery.com/remove/) | ||
| 2749 | * - [`removeAttr()`](http://api.jquery.com/removeAttr/) | ||
| 2750 | * - [`removeClass()`](http://api.jquery.com/removeClass/) - Does not support a function as first argument | ||
| 2751 | * - [`removeData()`](http://api.jquery.com/removeData/) | ||
| 2752 | * - [`replaceWith()`](http://api.jquery.com/replaceWith/) | ||
| 2753 | * - [`text()`](http://api.jquery.com/text/) | ||
| 2754 | * - [`toggleClass()`](http://api.jquery.com/toggleClass/) - Does not support a function as first argument | ||
| 2755 | * - [`triggerHandler()`](http://api.jquery.com/triggerHandler/) - Passes a dummy event object to handlers | ||
| 2756 | * - [`unbind()`](http://api.jquery.com/unbind/) - Does not support namespaces or event object as parameter | ||
| 2757 | * - [`val()`](http://api.jquery.com/val/) | ||
| 2758 | * - [`wrap()`](http://api.jquery.com/wrap/) | ||
| 2759 | * | ||
| 2760 | * ## jQuery/jqLite Extras | ||
| 2761 | * Angular also provides the following additional methods and events to both jQuery and jqLite: | ||
| 2762 | * | ||
| 2763 | * ### Events | ||
| 2764 | * - `$destroy` - AngularJS intercepts all jqLite/jQuery's DOM destruction apis and fires this event | ||
| 2765 | * on all DOM nodes being removed. This can be used to clean up any 3rd party bindings to the DOM | ||
| 2766 | * element before it is removed. | ||
| 2767 | * | ||
| 2768 | * ### Methods | ||
| 2769 | * - `controller(name)` - retrieves the controller of the current element or its parent. By default | ||
| 2770 | * retrieves controller associated with the `ngController` directive. If `name` is provided as | ||
| 2771 | * camelCase directive name, then the controller for this directive will be retrieved (e.g. | ||
| 2772 | * `'ngModel'`). | ||
| 2773 | * - `injector()` - retrieves the injector of the current element or its parent. | ||
| 2774 | * - `scope()` - retrieves the {@link ng.$rootScope.Scope scope} of the current | ||
| 2775 | * element or its parent. Requires {@link guide/production#disabling-debug-data Debug Data} to | ||
| 2776 | * be enabled. | ||
| 2777 | * - `isolateScope()` - retrieves an isolate {@link ng.$rootScope.Scope scope} if one is attached directly to the | ||
| 2778 | * current element. This getter should be used only on elements that contain a directive which starts a new isolate | ||
| 2779 | * scope. Calling `scope()` on this element always returns the original non-isolate scope. | ||
| 2780 | * Requires {@link guide/production#disabling-debug-data Debug Data} to be enabled. | ||
| 2781 | * - `inheritedData()` - same as `data()`, but walks up the DOM until a value is found or the top | ||
| 2782 | * parent element is reached. | ||
| 2783 | * | ||
| 2784 | * @knownIssue You cannot spy on `angular.element` if you are using Jasmine version 1.x. See | ||
| 2785 | * https://github.com/angular/angular.js/issues/14251 for more information. | ||
| 2786 | * | ||
| 2787 | * @param {string|DOMElement} element HTML string or DOMElement to be wrapped into jQuery. | ||
| 2788 | * @returns {Object} jQuery object. | ||
| 2789 | */ | ||
| 2790 | |||
| 2791 | JQLite.expando = 'ng339'; | ||
| 2792 | |||
| 2793 | var jqCache = JQLite.cache = {}, | ||
| 2794 | jqId = 1, | ||
| 2795 | addEventListenerFn = function(element, type, fn) { | ||
| 2796 | element.addEventListener(type, fn, false); | ||
| 2797 | }, | ||
| 2798 | removeEventListenerFn = function(element, type, fn) { | ||
| 2799 | element.removeEventListener(type, fn, false); | ||
| 2800 | }; | ||
| 2801 | |||
| 2802 | /* | ||
| 2803 | * !!! This is an undocumented "private" function !!! | ||
| 2804 | */ | ||
| 2805 | JQLite._data = function(node) { | ||
| 2806 | //jQuery always returns an object on cache miss | ||
| 2807 | return this.cache[node[this.expando]] || {}; | ||
| 2808 | }; | ||
| 2809 | |||
| 2810 | function jqNextId() { return ++jqId; } | ||
| 2811 | |||
| 2812 | |||
| 2813 | var SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g; | ||
| 2814 | var MOZ_HACK_REGEXP = /^moz([A-Z])/; | ||
| 2815 | var MOUSE_EVENT_MAP= { mouseleave: "mouseout", mouseenter: "mouseover"}; | ||
| 2816 | var jqLiteMinErr = minErr('jqLite'); | ||
| 2817 | |||
| 2818 | /** | ||
| 2819 | * Converts snake_case to camelCase. | ||
| 2820 | * Also there is special case for Moz prefix starting with upper case letter. | ||
| 2821 | * @param name Name to normalize | ||
| 2822 | */ | ||
| 2823 | function camelCase(name) { | ||
| 2824 | return name. | ||
| 2825 | replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) { | ||
| 2826 | return offset ? letter.toUpperCase() : letter; | ||
| 2827 | }). | ||
| 2828 | replace(MOZ_HACK_REGEXP, 'Moz$1'); | ||
| 2829 | } | ||
| 2830 | |||
| 2831 | var SINGLE_TAG_REGEXP = /^<([\w-]+)\s*\/?>(?:<\/\1>|)$/; | ||
| 2832 | var HTML_REGEXP = /<|&#?\w+;/; | ||
| 2833 | var TAG_NAME_REGEXP = /<([\w:-]+)/; | ||
| 2834 | var XHTML_TAG_REGEXP = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi; | ||
| 2835 | |||
| 2836 | var wrapMap = { | ||
| 2837 | 'option': [1, '<select multiple="multiple">', '</select>'], | ||
| 2838 | |||
| 2839 | 'thead': [1, '<table>', '</table>'], | ||
| 2840 | 'col': [2, '<table><colgroup>', '</colgroup></table>'], | ||
| 2841 | 'tr': [2, '<table><tbody>', '</tbody></table>'], | ||
| 2842 | 'td': [3, '<table><tbody><tr>', '</tr></tbody></table>'], | ||
| 2843 | '_default': [0, "", ""] | ||
| 2844 | }; | ||
| 2845 | |||
| 2846 | wrapMap.optgroup = wrapMap.option; | ||
| 2847 | wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; | ||
| 2848 | wrapMap.th = wrapMap.td; | ||
| 2849 | |||
| 2850 | |||
| 2851 | function jqLiteIsTextNode(html) { | ||
| 2852 | return !HTML_REGEXP.test(html); | ||
| 2853 | } | ||
| 2854 | |||
| 2855 | function jqLiteAcceptsData(node) { | ||
| 2856 | // The window object can accept data but has no nodeType | ||
| 2857 | // Otherwise we are only interested in elements (1) and documents (9) | ||
| 2858 | var nodeType = node.nodeType; | ||
| 2859 | return nodeType === NODE_TYPE_ELEMENT || !nodeType || nodeType === NODE_TYPE_DOCUMENT; | ||
| 2860 | } | ||
| 2861 | |||
| 2862 | function jqLiteHasData(node) { | ||
| 2863 | for (var key in jqCache[node.ng339]) { | ||
| 2864 | return true; | ||
| 2865 | } | ||
| 2866 | return false; | ||
| 2867 | } | ||
| 2868 | |||
| 2869 | function jqLiteCleanData(nodes) { | ||
| 2870 | for (var i = 0, ii = nodes.length; i < ii; i++) { | ||
| 2871 | jqLiteRemoveData(nodes[i]); | ||
| 2872 | } | ||
| 2873 | } | ||
| 2874 | |||
| 2875 | function jqLiteBuildFragment(html, context) { | ||
| 2876 | var tmp, tag, wrap, | ||
| 2877 | fragment = context.createDocumentFragment(), | ||
| 2878 | nodes = [], i; | ||
| 2879 | |||
| 2880 | if (jqLiteIsTextNode(html)) { | ||
| 2881 | // Convert non-html into a text node | ||
| 2882 | nodes.push(context.createTextNode(html)); | ||
| 2883 | } else { | ||
| 2884 | // Convert html into DOM nodes | ||
| 2885 | tmp = fragment.appendChild(context.createElement("div")); | ||
| 2886 | tag = (TAG_NAME_REGEXP.exec(html) || ["", ""])[1].toLowerCase(); | ||
| 2887 | wrap = wrapMap[tag] || wrapMap._default; | ||
| 2888 | tmp.innerHTML = wrap[1] + html.replace(XHTML_TAG_REGEXP, "<$1></$2>") + wrap[2]; | ||
| 2889 | |||
| 2890 | // Descend through wrappers to the right content | ||
| 2891 | i = wrap[0]; | ||
| 2892 | while (i--) { | ||
| 2893 | tmp = tmp.lastChild; | ||
| 2894 | } | ||
| 2895 | |||
| 2896 | nodes = concat(nodes, tmp.childNodes); | ||
| 2897 | |||
| 2898 | tmp = fragment.firstChild; | ||
| 2899 | tmp.textContent = ""; | ||
| 2900 | } | ||
| 2901 | |||
| 2902 | // Remove wrapper from fragment | ||
| 2903 | fragment.textContent = ""; | ||
| 2904 | fragment.innerHTML = ""; // Clear inner HTML | ||
| 2905 | forEach(nodes, function(node) { | ||
| 2906 | fragment.appendChild(node); | ||
| 2907 | }); | ||
| 2908 | |||
| 2909 | return fragment; | ||
| 2910 | } | ||
| 2911 | |||
| 2912 | function jqLiteParseHTML(html, context) { | ||
| 2913 | context = context || window.document; | ||
| 2914 | var parsed; | ||
| 2915 | |||
| 2916 | if ((parsed = SINGLE_TAG_REGEXP.exec(html))) { | ||
| 2917 | return [context.createElement(parsed[1])]; | ||
| 2918 | } | ||
| 2919 | |||
| 2920 | if ((parsed = jqLiteBuildFragment(html, context))) { | ||
| 2921 | return parsed.childNodes; | ||
| 2922 | } | ||
| 2923 | |||
| 2924 | return []; | ||
| 2925 | } | ||
| 2926 | |||
| 2927 | function jqLiteWrapNode(node, wrapper) { | ||
| 2928 | var parent = node.parentNode; | ||
| 2929 | |||
| 2930 | if (parent) { | ||
| 2931 | parent.replaceChild(wrapper, node); | ||
| 2932 | } | ||
| 2933 | |||
| 2934 | wrapper.appendChild(node); | ||
| 2935 | } | ||
| 2936 | |||
| 2937 | |||
| 2938 | // IE9-11 has no method "contains" in SVG element and in Node.prototype. Bug #10259. | ||
| 2939 | var jqLiteContains = window.Node.prototype.contains || function(arg) { | ||
| 2940 | // jshint bitwise: false | ||
| 2941 | return !!(this.compareDocumentPosition(arg) & 16); | ||
| 2942 | // jshint bitwise: true | ||
| 2943 | }; | ||
| 2944 | |||
| 2945 | ///////////////////////////////////////////// | ||
| 2946 | function JQLite(element) { | ||
| 2947 | if (element instanceof JQLite) { | ||
| 2948 | return element; | ||
| 2949 | } | ||
| 2950 | |||
| 2951 | var argIsString; | ||
| 2952 | |||
| 2953 | if (isString(element)) { | ||
| 2954 | element = trim(element); | ||
| 2955 | argIsString = true; | ||
| 2956 | } | ||
| 2957 | if (!(this instanceof JQLite)) { | ||
| 2958 | if (argIsString && element.charAt(0) != '<') { | ||
| 2959 | throw jqLiteMinErr('nosel', 'Looking up elements via selectors is not supported by jqLite! See: http://docs.angularjs.org/api/angular.element'); | ||
| 2960 | } | ||
| 2961 | return new JQLite(element); | ||
| 2962 | } | ||
| 2963 | |||
| 2964 | if (argIsString) { | ||
| 2965 | jqLiteAddNodes(this, jqLiteParseHTML(element)); | ||
| 2966 | } else { | ||
| 2967 | jqLiteAddNodes(this, element); | ||
| 2968 | } | ||
| 2969 | } | ||
| 2970 | |||
| 2971 | function jqLiteClone(element) { | ||
| 2972 | return element.cloneNode(true); | ||
| 2973 | } | ||
| 2974 | |||
| 2975 | function jqLiteDealoc(element, onlyDescendants) { | ||
| 2976 | if (!onlyDescendants) jqLiteRemoveData(element); | ||
| 2977 | |||
| 2978 | if (element.querySelectorAll) { | ||
| 2979 | var descendants = element.querySelectorAll('*'); | ||
| 2980 | for (var i = 0, l = descendants.length; i < l; i++) { | ||
| 2981 | jqLiteRemoveData(descendants[i]); | ||
| 2982 | } | ||
| 2983 | } | ||
| 2984 | } | ||
| 2985 | |||
| 2986 | function jqLiteOff(element, type, fn, unsupported) { | ||
| 2987 | if (isDefined(unsupported)) throw jqLiteMinErr('offargs', 'jqLite#off() does not support the `selector` argument'); | ||
| 2988 | |||
| 2989 | var expandoStore = jqLiteExpandoStore(element); | ||
| 2990 | var events = expandoStore && expandoStore.events; | ||
| 2991 | var handle = expandoStore && expandoStore.handle; | ||
| 2992 | |||
| 2993 | if (!handle) return; //no listeners registered | ||
| 2994 | |||
| 2995 | if (!type) { | ||
| 2996 | for (type in events) { | ||
| 2997 | if (type !== '$destroy') { | ||
| 2998 | removeEventListenerFn(element, type, handle); | ||
| 2999 | } | ||
| 3000 | delete events[type]; | ||
| 3001 | } | ||
| 3002 | } else { | ||
| 3003 | |||
| 3004 | var removeHandler = function(type) { | ||
| 3005 | var listenerFns = events[type]; | ||
| 3006 | if (isDefined(fn)) { | ||
| 3007 | arrayRemove(listenerFns || [], fn); | ||
| 3008 | } | ||
| 3009 | if (!(isDefined(fn) && listenerFns && listenerFns.length > 0)) { | ||
| 3010 | removeEventListenerFn(element, type, handle); | ||
| 3011 | delete events[type]; | ||
| 3012 | } | ||
| 3013 | }; | ||
| 3014 | |||
| 3015 | forEach(type.split(' '), function(type) { | ||
| 3016 | removeHandler(type); | ||
| 3017 | if (MOUSE_EVENT_MAP[type]) { | ||
| 3018 | removeHandler(MOUSE_EVENT_MAP[type]); | ||
| 3019 | } | ||
| 3020 | }); | ||
| 3021 | } | ||
| 3022 | } | ||
| 3023 | |||
| 3024 | function jqLiteRemoveData(element, name) { | ||
| 3025 | var expandoId = element.ng339; | ||
| 3026 | var expandoStore = expandoId && jqCache[expandoId]; | ||
| 3027 | |||
| 3028 | if (expandoStore) { | ||
| 3029 | if (name) { | ||
| 3030 | delete expandoStore.data[name]; | ||
| 3031 | return; | ||
| 3032 | } | ||
| 3033 | |||
| 3034 | if (expandoStore.handle) { | ||
| 3035 | if (expandoStore.events.$destroy) { | ||
| 3036 | expandoStore.handle({}, '$destroy'); | ||
| 3037 | } | ||
| 3038 | jqLiteOff(element); | ||
| 3039 | } | ||
| 3040 | delete jqCache[expandoId]; | ||
| 3041 | element.ng339 = undefined; // don't delete DOM expandos. IE and Chrome don't like it | ||
| 3042 | } | ||
| 3043 | } | ||
| 3044 | |||
| 3045 | |||
| 3046 | function jqLiteExpandoStore(element, createIfNecessary) { | ||
| 3047 | var expandoId = element.ng339, | ||
| 3048 | expandoStore = expandoId && jqCache[expandoId]; | ||
| 3049 | |||
| 3050 | if (createIfNecessary && !expandoStore) { | ||
| 3051 | element.ng339 = expandoId = jqNextId(); | ||
| 3052 | expandoStore = jqCache[expandoId] = {events: {}, data: {}, handle: undefined}; | ||
| 3053 | } | ||
| 3054 | |||
| 3055 | return expandoStore; | ||
| 3056 | } | ||
| 3057 | |||
| 3058 | |||
| 3059 | function jqLiteData(element, key, value) { | ||
| 3060 | if (jqLiteAcceptsData(element)) { | ||
| 3061 | |||
| 3062 | var isSimpleSetter = isDefined(value); | ||
| 3063 | var isSimpleGetter = !isSimpleSetter && key && !isObject(key); | ||
| 3064 | var massGetter = !key; | ||
| 3065 | var expandoStore = jqLiteExpandoStore(element, !isSimpleGetter); | ||
| 3066 | var data = expandoStore && expandoStore.data; | ||
| 3067 | |||
| 3068 | if (isSimpleSetter) { // data('key', value) | ||
| 3069 | data[key] = value; | ||
| 3070 | } else { | ||
| 3071 | if (massGetter) { // data() | ||
| 3072 | return data; | ||
| 3073 | } else { | ||
| 3074 | if (isSimpleGetter) { // data('key') | ||
| 3075 | // don't force creation of expandoStore if it doesn't exist yet | ||
| 3076 | return data && data[key]; | ||
| 3077 | } else { // mass-setter: data({key1: val1, key2: val2}) | ||
| 3078 | extend(data, key); | ||
| 3079 | } | ||
| 3080 | } | ||
| 3081 | } | ||
| 3082 | } | ||
| 3083 | } | ||
| 3084 | |||
| 3085 | function jqLiteHasClass(element, selector) { | ||
| 3086 | if (!element.getAttribute) return false; | ||
| 3087 | return ((" " + (element.getAttribute('class') || '') + " ").replace(/[\n\t]/g, " "). | ||
| 3088 | indexOf(" " + selector + " ") > -1); | ||
| 3089 | } | ||
| 3090 | |||
| 3091 | function jqLiteRemoveClass(element, cssClasses) { | ||
| 3092 | if (cssClasses && element.setAttribute) { | ||
| 3093 | forEach(cssClasses.split(' '), function(cssClass) { | ||
| 3094 | element.setAttribute('class', trim( | ||
| 3095 | (" " + (element.getAttribute('class') || '') + " ") | ||
| 3096 | .replace(/[\n\t]/g, " ") | ||
| 3097 | .replace(" " + trim(cssClass) + " ", " ")) | ||
| 3098 | ); | ||
| 3099 | }); | ||
| 3100 | } | ||
| 3101 | } | ||
| 3102 | |||
| 3103 | function jqLiteAddClass(element, cssClasses) { | ||
| 3104 | if (cssClasses && element.setAttribute) { | ||
| 3105 | var existingClasses = (' ' + (element.getAttribute('class') || '') + ' ') | ||
| 3106 | .replace(/[\n\t]/g, " "); | ||
| 3107 | |||
| 3108 | forEach(cssClasses.split(' '), function(cssClass) { | ||
| 3109 | cssClass = trim(cssClass); | ||
| 3110 | if (existingClasses.indexOf(' ' + cssClass + ' ') === -1) { | ||
| 3111 | existingClasses += cssClass + ' '; | ||
| 3112 | } | ||
| 3113 | }); | ||
| 3114 | |||
| 3115 | element.setAttribute('class', trim(existingClasses)); | ||
| 3116 | } | ||
| 3117 | } | ||
| 3118 | |||
| 3119 | |||
| 3120 | function jqLiteAddNodes(root, elements) { | ||
| 3121 | // THIS CODE IS VERY HOT. Don't make changes without benchmarking. | ||
| 3122 | |||
| 3123 | if (elements) { | ||
| 3124 | |||
| 3125 | // if a Node (the most common case) | ||
| 3126 | if (elements.nodeType) { | ||
| 3127 | root[root.length++] = elements; | ||
| 3128 | } else { | ||
| 3129 | var length = elements.length; | ||
| 3130 | |||
| 3131 | // if an Array or NodeList and not a Window | ||
| 3132 | if (typeof length === 'number' && elements.window !== elements) { | ||
| 3133 | if (length) { | ||
| 3134 | for (var i = 0; i < length; i++) { | ||
| 3135 | root[root.length++] = elements[i]; | ||
| 3136 | } | ||
| 3137 | } | ||
| 3138 | } else { | ||
| 3139 | root[root.length++] = elements; | ||
| 3140 | } | ||
| 3141 | } | ||
| 3142 | } | ||
| 3143 | } | ||
| 3144 | |||
| 3145 | |||
| 3146 | function jqLiteController(element, name) { | ||
| 3147 | return jqLiteInheritedData(element, '$' + (name || 'ngController') + 'Controller'); | ||
| 3148 | } | ||
| 3149 | |||
| 3150 | function jqLiteInheritedData(element, name, value) { | ||
| 3151 | // if element is the document object work with the html element instead | ||
| 3152 | // this makes $(document).scope() possible | ||
| 3153 | if (element.nodeType == NODE_TYPE_DOCUMENT) { | ||
| 3154 | element = element.documentElement; | ||
| 3155 | } | ||
| 3156 | var names = isArray(name) ? name : [name]; | ||
| 3157 | |||
| 3158 | while (element) { | ||
| 3159 | for (var i = 0, ii = names.length; i < ii; i++) { | ||
| 3160 | if (isDefined(value = jqLite.data(element, names[i]))) return value; | ||
| 3161 | } | ||
| 3162 | |||
| 3163 | // If dealing with a document fragment node with a host element, and no parent, use the host | ||
| 3164 | // element as the parent. This enables directives within a Shadow DOM or polyfilled Shadow DOM | ||
| 3165 | // to lookup parent controllers. | ||
| 3166 | element = element.parentNode || (element.nodeType === NODE_TYPE_DOCUMENT_FRAGMENT && element.host); | ||
| 3167 | } | ||
| 3168 | } | ||
| 3169 | |||
| 3170 | function jqLiteEmpty(element) { | ||
| 3171 | jqLiteDealoc(element, true); | ||
| 3172 | while (element.firstChild) { | ||
| 3173 | element.removeChild(element.firstChild); | ||
| 3174 | } | ||
| 3175 | } | ||
| 3176 | |||
| 3177 | function jqLiteRemove(element, keepData) { | ||
| 3178 | if (!keepData) jqLiteDealoc(element); | ||
| 3179 | var parent = element.parentNode; | ||
| 3180 | if (parent) parent.removeChild(element); | ||
| 3181 | } | ||
| 3182 | |||
| 3183 | |||
| 3184 | function jqLiteDocumentLoaded(action, win) { | ||
| 3185 | win = win || window; | ||
| 3186 | if (win.document.readyState === 'complete') { | ||
| 3187 | // Force the action to be run async for consistent behavior | ||
| 3188 | // from the action's point of view | ||
| 3189 | // i.e. it will definitely not be in a $apply | ||
| 3190 | win.setTimeout(action); | ||
| 3191 | } else { | ||
| 3192 | // No need to unbind this handler as load is only ever called once | ||
| 3193 | jqLite(win).on('load', action); | ||
| 3194 | } | ||
| 3195 | } | ||
| 3196 | |||
| 3197 | ////////////////////////////////////////// | ||
| 3198 | // Functions which are declared directly. | ||
| 3199 | ////////////////////////////////////////// | ||
| 3200 | var JQLitePrototype = JQLite.prototype = { | ||
| 3201 | ready: function(fn) { | ||
| 3202 | var fired = false; | ||
| 3203 | |||
| 3204 | function trigger() { | ||
| 3205 | if (fired) return; | ||
| 3206 | fired = true; | ||
| 3207 | fn(); | ||
| 3208 | } | ||
| 3209 | |||
| 3210 | // check if document is already loaded | ||
| 3211 | if (window.document.readyState === 'complete') { | ||
| 3212 | window.setTimeout(trigger); | ||
| 3213 | } else { | ||
| 3214 | this.on('DOMContentLoaded', trigger); // works for modern browsers and IE9 | ||
| 3215 | // we can not use jqLite since we are not done loading and jQuery could be loaded later. | ||
| 3216 | // jshint -W064 | ||
| 3217 | JQLite(window).on('load', trigger); // fallback to window.onload for others | ||
| 3218 | // jshint +W064 | ||
| 3219 | } | ||
| 3220 | }, | ||
| 3221 | toString: function() { | ||
| 3222 | var value = []; | ||
| 3223 | forEach(this, function(e) { value.push('' + e);}); | ||
| 3224 | return '[' + value.join(', ') + ']'; | ||
| 3225 | }, | ||
| 3226 | |||
| 3227 | eq: function(index) { | ||
| 3228 | return (index >= 0) ? jqLite(this[index]) : jqLite(this[this.length + index]); | ||
| 3229 | }, | ||
| 3230 | |||
| 3231 | length: 0, | ||
| 3232 | push: push, | ||
| 3233 | sort: [].sort, | ||
| 3234 | splice: [].splice | ||
| 3235 | }; | ||
| 3236 | |||
| 3237 | ////////////////////////////////////////// | ||
| 3238 | // Functions iterating getter/setters. | ||
| 3239 | // these functions return self on setter and | ||
| 3240 | // value on get. | ||
| 3241 | ////////////////////////////////////////// | ||
| 3242 | var BOOLEAN_ATTR = {}; | ||
| 3243 | forEach('multiple,selected,checked,disabled,readOnly,required,open'.split(','), function(value) { | ||
| 3244 | BOOLEAN_ATTR[lowercase(value)] = value; | ||
| 3245 | }); | ||
| 3246 | var BOOLEAN_ELEMENTS = {}; | ||
| 3247 | forEach('input,select,option,textarea,button,form,details'.split(','), function(value) { | ||
| 3248 | BOOLEAN_ELEMENTS[value] = true; | ||
| 3249 | }); | ||
| 3250 | var ALIASED_ATTR = { | ||
| 3251 | 'ngMinlength': 'minlength', | ||
| 3252 | 'ngMaxlength': 'maxlength', | ||
| 3253 | 'ngMin': 'min', | ||
| 3254 | 'ngMax': 'max', | ||
| 3255 | 'ngPattern': 'pattern' | ||
| 3256 | }; | ||
| 3257 | |||
| 3258 | function getBooleanAttrName(element, name) { | ||
| 3259 | // check dom last since we will most likely fail on name | ||
| 3260 | var booleanAttr = BOOLEAN_ATTR[name.toLowerCase()]; | ||
| 3261 | |||
| 3262 | // booleanAttr is here twice to minimize DOM access | ||
| 3263 | return booleanAttr && BOOLEAN_ELEMENTS[nodeName_(element)] && booleanAttr; | ||
| 3264 | } | ||
| 3265 | |||
| 3266 | function getAliasedAttrName(name) { | ||
| 3267 | return ALIASED_ATTR[name]; | ||
| 3268 | } | ||
| 3269 | |||
| 3270 | forEach({ | ||
| 3271 | data: jqLiteData, | ||
| 3272 | removeData: jqLiteRemoveData, | ||
| 3273 | hasData: jqLiteHasData, | ||
| 3274 | cleanData: jqLiteCleanData | ||
| 3275 | }, function(fn, name) { | ||
| 3276 | JQLite[name] = fn; | ||
| 3277 | }); | ||
| 3278 | |||
| 3279 | forEach({ | ||
| 3280 | data: jqLiteData, | ||
| 3281 | inheritedData: jqLiteInheritedData, | ||
| 3282 | |||
| 3283 | scope: function(element) { | ||
| 3284 | // Can't use jqLiteData here directly so we stay compatible with jQuery! | ||
| 3285 | return jqLite.data(element, '$scope') || jqLiteInheritedData(element.parentNode || element, ['$isolateScope', '$scope']); | ||
| 3286 | }, | ||
| 3287 | |||
| 3288 | isolateScope: function(element) { | ||
| 3289 | // Can't use jqLiteData here directly so we stay compatible with jQuery! | ||
| 3290 | return jqLite.data(element, '$isolateScope') || jqLite.data(element, '$isolateScopeNoTemplate'); | ||
| 3291 | }, | ||
| 3292 | |||
| 3293 | controller: jqLiteController, | ||
| 3294 | |||
| 3295 | injector: function(element) { | ||
| 3296 | return jqLiteInheritedData(element, '$injector'); | ||
| 3297 | }, | ||
| 3298 | |||
| 3299 | removeAttr: function(element, name) { | ||
| 3300 | element.removeAttribute(name); | ||
| 3301 | }, | ||
| 3302 | |||
| 3303 | hasClass: jqLiteHasClass, | ||
| 3304 | |||
| 3305 | css: function(element, name, value) { | ||
| 3306 | name = camelCase(name); | ||
| 3307 | |||
| 3308 | if (isDefined(value)) { | ||
| 3309 | element.style[name] = value; | ||
| 3310 | } else { | ||
| 3311 | return element.style[name]; | ||
| 3312 | } | ||
| 3313 | }, | ||
| 3314 | |||
| 3315 | attr: function(element, name, value) { | ||
| 3316 | var nodeType = element.nodeType; | ||
| 3317 | if (nodeType === NODE_TYPE_TEXT || nodeType === NODE_TYPE_ATTRIBUTE || nodeType === NODE_TYPE_COMMENT) { | ||
| 3318 | return; | ||
| 3319 | } | ||
| 3320 | var lowercasedName = lowercase(name); | ||
| 3321 | if (BOOLEAN_ATTR[lowercasedName]) { | ||
| 3322 | if (isDefined(value)) { | ||
| 3323 | if (!!value) { | ||
| 3324 | element[name] = true; | ||
| 3325 | element.setAttribute(name, lowercasedName); | ||
| 3326 | } else { | ||
| 3327 | element[name] = false; | ||
| 3328 | element.removeAttribute(lowercasedName); | ||
| 3329 | } | ||
| 3330 | } else { | ||
| 3331 | return (element[name] || | ||
| 3332 | (element.attributes.getNamedItem(name) || noop).specified) | ||
| 3333 | ? lowercasedName | ||
| 3334 | : undefined; | ||
| 3335 | } | ||
| 3336 | } else if (isDefined(value)) { | ||
| 3337 | element.setAttribute(name, value); | ||
| 3338 | } else if (element.getAttribute) { | ||
| 3339 | // the extra argument "2" is to get the right thing for a.href in IE, see jQuery code | ||
| 3340 | // some elements (e.g. Document) don't have get attribute, so return undefined | ||
| 3341 | var ret = element.getAttribute(name, 2); | ||
| 3342 | // normalize non-existing attributes to undefined (as jQuery) | ||
| 3343 | return ret === null ? undefined : ret; | ||
| 3344 | } | ||
| 3345 | }, | ||
| 3346 | |||
| 3347 | prop: function(element, name, value) { | ||
| 3348 | if (isDefined(value)) { | ||
| 3349 | element[name] = value; | ||
| 3350 | } else { | ||
| 3351 | return element[name]; | ||
| 3352 | } | ||
| 3353 | }, | ||
| 3354 | |||
| 3355 | text: (function() { | ||
| 3356 | getText.$dv = ''; | ||
| 3357 | return getText; | ||
| 3358 | |||
| 3359 | function getText(element, value) { | ||
| 3360 | if (isUndefined(value)) { | ||
| 3361 | var nodeType = element.nodeType; | ||
| 3362 | return (nodeType === NODE_TYPE_ELEMENT || nodeType === NODE_TYPE_TEXT) ? element.textContent : ''; | ||
| 3363 | } | ||
| 3364 | element.textContent = value; | ||
| 3365 | } | ||
| 3366 | })(), | ||
| 3367 | |||
| 3368 | val: function(element, value) { | ||
| 3369 | if (isUndefined(value)) { | ||
| 3370 | if (element.multiple && nodeName_(element) === 'select') { | ||
| 3371 | var result = []; | ||
| 3372 | forEach(element.options, function(option) { | ||
| 3373 | if (option.selected) { | ||
| 3374 | result.push(option.value || option.text); | ||
| 3375 | } | ||
| 3376 | }); | ||
| 3377 | return result.length === 0 ? null : result; | ||
| 3378 | } | ||
| 3379 | return element.value; | ||
| 3380 | } | ||
| 3381 | element.value = value; | ||
| 3382 | }, | ||
| 3383 | |||
| 3384 | html: function(element, value) { | ||
| 3385 | if (isUndefined(value)) { | ||
| 3386 | return element.innerHTML; | ||
| 3387 | } | ||
| 3388 | jqLiteDealoc(element, true); | ||
| 3389 | element.innerHTML = value; | ||
| 3390 | }, | ||
| 3391 | |||
| 3392 | empty: jqLiteEmpty | ||
| 3393 | }, function(fn, name) { | ||
| 3394 | /** | ||
| 3395 | * Properties: writes return selection, reads return first value | ||
| 3396 | */ | ||
| 3397 | JQLite.prototype[name] = function(arg1, arg2) { | ||
| 3398 | var i, key; | ||
| 3399 | var nodeCount = this.length; | ||
| 3400 | |||
| 3401 | // jqLiteHasClass has only two arguments, but is a getter-only fn, so we need to special-case it | ||
| 3402 | // in a way that survives minification. | ||
| 3403 | // jqLiteEmpty takes no arguments but is a setter. | ||
| 3404 | if (fn !== jqLiteEmpty && | ||
| 3405 | (isUndefined((fn.length == 2 && (fn !== jqLiteHasClass && fn !== jqLiteController)) ? arg1 : arg2))) { | ||
| 3406 | if (isObject(arg1)) { | ||
| 3407 | |||
| 3408 | // we are a write, but the object properties are the key/values | ||
| 3409 | for (i = 0; i < nodeCount; i++) { | ||
| 3410 | if (fn === jqLiteData) { | ||
| 3411 | // data() takes the whole object in jQuery | ||
| 3412 | fn(this[i], arg1); | ||
| 3413 | } else { | ||
| 3414 | for (key in arg1) { | ||
| 3415 | fn(this[i], key, arg1[key]); | ||
| 3416 | } | ||
| 3417 | } | ||
| 3418 | } | ||
| 3419 | // return self for chaining | ||
| 3420 | return this; | ||
| 3421 | } else { | ||
| 3422 | // we are a read, so read the first child. | ||
| 3423 | // TODO: do we still need this? | ||
| 3424 | var value = fn.$dv; | ||
| 3425 | // Only if we have $dv do we iterate over all, otherwise it is just the first element. | ||
| 3426 | var jj = (isUndefined(value)) ? Math.min(nodeCount, 1) : nodeCount; | ||
| 3427 | for (var j = 0; j < jj; j++) { | ||
| 3428 | var nodeValue = fn(this[j], arg1, arg2); | ||
| 3429 | value = value ? value + nodeValue : nodeValue; | ||
| 3430 | } | ||
| 3431 | return value; | ||
| 3432 | } | ||
| 3433 | } else { | ||
| 3434 | // we are a write, so apply to all children | ||
| 3435 | for (i = 0; i < nodeCount; i++) { | ||
| 3436 | fn(this[i], arg1, arg2); | ||
| 3437 | } | ||
| 3438 | // return self for chaining | ||
| 3439 | return this; | ||
| 3440 | } | ||
| 3441 | }; | ||
| 3442 | }); | ||
| 3443 | |||
| 3444 | function createEventHandler(element, events) { | ||
| 3445 | var eventHandler = function(event, type) { | ||
| 3446 | // jQuery specific api | ||
| 3447 | event.isDefaultPrevented = function() { | ||
| 3448 | return event.defaultPrevented; | ||
| 3449 | }; | ||
| 3450 | |||
| 3451 | var eventFns = events[type || event.type]; | ||
| 3452 | var eventFnsLength = eventFns ? eventFns.length : 0; | ||
| 3453 | |||
| 3454 | if (!eventFnsLength) return; | ||
| 3455 | |||
| 3456 | if (isUndefined(event.immediatePropagationStopped)) { | ||
| 3457 | var originalStopImmediatePropagation = event.stopImmediatePropagation; | ||
| 3458 | event.stopImmediatePropagation = function() { | ||
| 3459 | event.immediatePropagationStopped = true; | ||
| 3460 | |||
| 3461 | if (event.stopPropagation) { | ||
| 3462 | event.stopPropagation(); | ||
| 3463 | } | ||
| 3464 | |||
| 3465 | if (originalStopImmediatePropagation) { | ||
| 3466 | originalStopImmediatePropagation.call(event); | ||
| 3467 | } | ||
| 3468 | }; | ||
| 3469 | } | ||
| 3470 | |||
| 3471 | event.isImmediatePropagationStopped = function() { | ||
| 3472 | return event.immediatePropagationStopped === true; | ||
| 3473 | }; | ||
| 3474 | |||
| 3475 | // Some events have special handlers that wrap the real handler | ||
| 3476 | var handlerWrapper = eventFns.specialHandlerWrapper || defaultHandlerWrapper; | ||
| 3477 | |||
| 3478 | // Copy event handlers in case event handlers array is modified during execution. | ||
| 3479 | if ((eventFnsLength > 1)) { | ||
| 3480 | eventFns = shallowCopy(eventFns); | ||
| 3481 | } | ||
| 3482 | |||
| 3483 | for (var i = 0; i < eventFnsLength; i++) { | ||
| 3484 | if (!event.isImmediatePropagationStopped()) { | ||
| 3485 | handlerWrapper(element, event, eventFns[i]); | ||
| 3486 | } | ||
| 3487 | } | ||
| 3488 | }; | ||
| 3489 | |||
| 3490 | // TODO: this is a hack for angularMocks/clearDataCache that makes it possible to deregister all | ||
| 3491 | // events on `element` | ||
| 3492 | eventHandler.elem = element; | ||
| 3493 | return eventHandler; | ||
| 3494 | } | ||
| 3495 | |||
| 3496 | function defaultHandlerWrapper(element, event, handler) { | ||
| 3497 | handler.call(element, event); | ||
| 3498 | } | ||
| 3499 | |||
| 3500 | function specialMouseHandlerWrapper(target, event, handler) { | ||
| 3501 | // Refer to jQuery's implementation of mouseenter & mouseleave | ||
| 3502 | // Read about mouseenter and mouseleave: | ||
| 3503 | // http://www.quirksmode.org/js/events_mouse.html#link8 | ||
| 3504 | var related = event.relatedTarget; | ||
| 3505 | // For mousenter/leave call the handler if related is outside the target. | ||
| 3506 | // NB: No relatedTarget if the mouse left/entered the browser window | ||
| 3507 | if (!related || (related !== target && !jqLiteContains.call(target, related))) { | ||
| 3508 | handler.call(target, event); | ||
| 3509 | } | ||
| 3510 | } | ||
| 3511 | |||
| 3512 | ////////////////////////////////////////// | ||
| 3513 | // Functions iterating traversal. | ||
| 3514 | // These functions chain results into a single | ||
| 3515 | // selector. | ||
| 3516 | ////////////////////////////////////////// | ||
| 3517 | forEach({ | ||
| 3518 | removeData: jqLiteRemoveData, | ||
| 3519 | |||
| 3520 | on: function jqLiteOn(element, type, fn, unsupported) { | ||
| 3521 | if (isDefined(unsupported)) throw jqLiteMinErr('onargs', 'jqLite#on() does not support the `selector` or `eventData` parameters'); | ||
| 3522 | |||
| 3523 | // Do not add event handlers to non-elements because they will not be cleaned up. | ||
| 3524 | if (!jqLiteAcceptsData(element)) { | ||
| 3525 | return; | ||
| 3526 | } | ||
| 3527 | |||
| 3528 | var expandoStore = jqLiteExpandoStore(element, true); | ||
| 3529 | var events = expandoStore.events; | ||
| 3530 | var handle = expandoStore.handle; | ||
| 3531 | |||
| 3532 | if (!handle) { | ||
| 3533 | handle = expandoStore.handle = createEventHandler(element, events); | ||
| 3534 | } | ||
| 3535 | |||
| 3536 | // http://jsperf.com/string-indexof-vs-split | ||
| 3537 | var types = type.indexOf(' ') >= 0 ? type.split(' ') : [type]; | ||
| 3538 | var i = types.length; | ||
| 3539 | |||
| 3540 | var addHandler = function(type, specialHandlerWrapper, noEventListener) { | ||
| 3541 | var eventFns = events[type]; | ||
| 3542 | |||
| 3543 | if (!eventFns) { | ||
| 3544 | eventFns = events[type] = []; | ||
| 3545 | eventFns.specialHandlerWrapper = specialHandlerWrapper; | ||
| 3546 | if (type !== '$destroy' && !noEventListener) { | ||
| 3547 | addEventListenerFn(element, type, handle); | ||
| 3548 | } | ||
| 3549 | } | ||
| 3550 | |||
| 3551 | eventFns.push(fn); | ||
| 3552 | }; | ||
| 3553 | |||
| 3554 | while (i--) { | ||
| 3555 | type = types[i]; | ||
| 3556 | if (MOUSE_EVENT_MAP[type]) { | ||
| 3557 | addHandler(MOUSE_EVENT_MAP[type], specialMouseHandlerWrapper); | ||
| 3558 | addHandler(type, undefined, true); | ||
| 3559 | } else { | ||
| 3560 | addHandler(type); | ||
| 3561 | } | ||
| 3562 | } | ||
| 3563 | }, | ||
| 3564 | |||
| 3565 | off: jqLiteOff, | ||
| 3566 | |||
| 3567 | one: function(element, type, fn) { | ||
| 3568 | element = jqLite(element); | ||
| 3569 | |||
| 3570 | //add the listener twice so that when it is called | ||
| 3571 | //you can remove the original function and still be | ||
| 3572 | //able to call element.off(ev, fn) normally | ||
| 3573 | element.on(type, function onFn() { | ||
| 3574 | element.off(type, fn); | ||
| 3575 | element.off(type, onFn); | ||
| 3576 | }); | ||
| 3577 | element.on(type, fn); | ||
| 3578 | }, | ||
| 3579 | |||
| 3580 | replaceWith: function(element, replaceNode) { | ||
| 3581 | var index, parent = element.parentNode; | ||
| 3582 | jqLiteDealoc(element); | ||
| 3583 | forEach(new JQLite(replaceNode), function(node) { | ||
| 3584 | if (index) { | ||
| 3585 | parent.insertBefore(node, index.nextSibling); | ||
| 3586 | } else { | ||
| 3587 | parent.replaceChild(node, element); | ||
| 3588 | } | ||
| 3589 | index = node; | ||
| 3590 | }); | ||
| 3591 | }, | ||
| 3592 | |||
| 3593 | children: function(element) { | ||
| 3594 | var children = []; | ||
| 3595 | forEach(element.childNodes, function(element) { | ||
| 3596 | if (element.nodeType === NODE_TYPE_ELEMENT) { | ||
| 3597 | children.push(element); | ||
| 3598 | } | ||
| 3599 | }); | ||
| 3600 | return children; | ||
| 3601 | }, | ||
| 3602 | |||
| 3603 | contents: function(element) { | ||
| 3604 | return element.contentDocument || element.childNodes || []; | ||
| 3605 | }, | ||
| 3606 | |||
| 3607 | append: function(element, node) { | ||
| 3608 | var nodeType = element.nodeType; | ||
| 3609 | if (nodeType !== NODE_TYPE_ELEMENT && nodeType !== NODE_TYPE_DOCUMENT_FRAGMENT) return; | ||
| 3610 | |||
| 3611 | node = new JQLite(node); | ||
| 3612 | |||
| 3613 | for (var i = 0, ii = node.length; i < ii; i++) { | ||
| 3614 | var child = node[i]; | ||
| 3615 | element.appendChild(child); | ||
| 3616 | } | ||
| 3617 | }, | ||
| 3618 | |||
| 3619 | prepend: function(element, node) { | ||
| 3620 | if (element.nodeType === NODE_TYPE_ELEMENT) { | ||
| 3621 | var index = element.firstChild; | ||
| 3622 | forEach(new JQLite(node), function(child) { | ||
| 3623 | element.insertBefore(child, index); | ||
| 3624 | }); | ||
| 3625 | } | ||
| 3626 | }, | ||
| 3627 | |||
| 3628 | wrap: function(element, wrapNode) { | ||
| 3629 | jqLiteWrapNode(element, jqLite(wrapNode).eq(0).clone()[0]); | ||
| 3630 | }, | ||
| 3631 | |||
| 3632 | remove: jqLiteRemove, | ||
| 3633 | |||
| 3634 | detach: function(element) { | ||
| 3635 | jqLiteRemove(element, true); | ||
| 3636 | }, | ||
| 3637 | |||
| 3638 | after: function(element, newElement) { | ||
| 3639 | var index = element, parent = element.parentNode; | ||
| 3640 | newElement = new JQLite(newElement); | ||
| 3641 | |||
| 3642 | for (var i = 0, ii = newElement.length; i < ii; i++) { | ||
| 3643 | var node = newElement[i]; | ||
| 3644 | parent.insertBefore(node, index.nextSibling); | ||
| 3645 | index = node; | ||
| 3646 | } | ||
| 3647 | }, | ||
| 3648 | |||
| 3649 | addClass: jqLiteAddClass, | ||
| 3650 | removeClass: jqLiteRemoveClass, | ||
| 3651 | |||
| 3652 | toggleClass: function(element, selector, condition) { | ||
| 3653 | if (selector) { | ||
| 3654 | forEach(selector.split(' '), function(className) { | ||
| 3655 | var classCondition = condition; | ||
| 3656 | if (isUndefined(classCondition)) { | ||
| 3657 | classCondition = !jqLiteHasClass(element, className); | ||
| 3658 | } | ||
| 3659 | (classCondition ? jqLiteAddClass : jqLiteRemoveClass)(element, className); | ||
| 3660 | }); | ||
| 3661 | } | ||
| 3662 | }, | ||
| 3663 | |||
| 3664 | parent: function(element) { | ||
| 3665 | var parent = element.parentNode; | ||
| 3666 | return parent && parent.nodeType !== NODE_TYPE_DOCUMENT_FRAGMENT ? parent : null; | ||
| 3667 | }, | ||
| 3668 | |||
| 3669 | next: function(element) { | ||
| 3670 | return element.nextElementSibling; | ||
| 3671 | }, | ||
| 3672 | |||
| 3673 | find: function(element, selector) { | ||
| 3674 | if (element.getElementsByTagName) { | ||
| 3675 | return element.getElementsByTagName(selector); | ||
| 3676 | } else { | ||
| 3677 | return []; | ||
| 3678 | } | ||
| 3679 | }, | ||
| 3680 | |||
| 3681 | clone: jqLiteClone, | ||
| 3682 | |||
| 3683 | triggerHandler: function(element, event, extraParameters) { | ||
| 3684 | |||
| 3685 | var dummyEvent, eventFnsCopy, handlerArgs; | ||
| 3686 | var eventName = event.type || event; | ||
| 3687 | var expandoStore = jqLiteExpandoStore(element); | ||
| 3688 | var events = expandoStore && expandoStore.events; | ||
| 3689 | var eventFns = events && events[eventName]; | ||
| 3690 | |||
| 3691 | if (eventFns) { | ||
| 3692 | // Create a dummy event to pass to the handlers | ||
| 3693 | dummyEvent = { | ||
| 3694 | preventDefault: function() { this.defaultPrevented = true; }, | ||
| 3695 | isDefaultPrevented: function() { return this.defaultPrevented === true; }, | ||
| 3696 | stopImmediatePropagation: function() { this.immediatePropagationStopped = true; }, | ||
| 3697 | isImmediatePropagationStopped: function() { return this.immediatePropagationStopped === true; }, | ||
| 3698 | stopPropagation: noop, | ||
| 3699 | type: eventName, | ||
| 3700 | target: element | ||
| 3701 | }; | ||
| 3702 | |||
| 3703 | // If a custom event was provided then extend our dummy event with it | ||
| 3704 | if (event.type) { | ||
| 3705 | dummyEvent = extend(dummyEvent, event); | ||
| 3706 | } | ||
| 3707 | |||
| 3708 | // Copy event handlers in case event handlers array is modified during execution. | ||
| 3709 | eventFnsCopy = shallowCopy(eventFns); | ||
| 3710 | handlerArgs = extraParameters ? [dummyEvent].concat(extraParameters) : [dummyEvent]; | ||
| 3711 | |||
| 3712 | forEach(eventFnsCopy, function(fn) { | ||
| 3713 | if (!dummyEvent.isImmediatePropagationStopped()) { | ||
| 3714 | fn.apply(element, handlerArgs); | ||
| 3715 | } | ||
| 3716 | }); | ||
| 3717 | } | ||
| 3718 | } | ||
| 3719 | }, function(fn, name) { | ||
| 3720 | /** | ||
| 3721 | * chaining functions | ||
| 3722 | */ | ||
| 3723 | JQLite.prototype[name] = function(arg1, arg2, arg3) { | ||
| 3724 | var value; | ||
| 3725 | |||
| 3726 | for (var i = 0, ii = this.length; i < ii; i++) { | ||
| 3727 | if (isUndefined(value)) { | ||
| 3728 | value = fn(this[i], arg1, arg2, arg3); | ||
| 3729 | if (isDefined(value)) { | ||
| 3730 | // any function which returns a value needs to be wrapped | ||
| 3731 | value = jqLite(value); | ||
| 3732 | } | ||
| 3733 | } else { | ||
| 3734 | jqLiteAddNodes(value, fn(this[i], arg1, arg2, arg3)); | ||
| 3735 | } | ||
| 3736 | } | ||
| 3737 | return isDefined(value) ? value : this; | ||
| 3738 | }; | ||
| 3739 | |||
| 3740 | // bind legacy bind/unbind to on/off | ||
| 3741 | JQLite.prototype.bind = JQLite.prototype.on; | ||
| 3742 | JQLite.prototype.unbind = JQLite.prototype.off; | ||
| 3743 | }); | ||
| 3744 | |||
| 3745 | |||
| 3746 | // Provider for private $$jqLite service | ||
| 3747 | function $$jqLiteProvider() { | ||
| 3748 | this.$get = function $$jqLite() { | ||
| 3749 | return extend(JQLite, { | ||
| 3750 | hasClass: function(node, classes) { | ||
| 3751 | if (node.attr) node = node[0]; | ||
| 3752 | return jqLiteHasClass(node, classes); | ||
| 3753 | }, | ||
| 3754 | addClass: function(node, classes) { | ||
| 3755 | if (node.attr) node = node[0]; | ||
| 3756 | return jqLiteAddClass(node, classes); | ||
| 3757 | }, | ||
| 3758 | removeClass: function(node, classes) { | ||
| 3759 | if (node.attr) node = node[0]; | ||
| 3760 | return jqLiteRemoveClass(node, classes); | ||
| 3761 | } | ||
| 3762 | }); | ||
| 3763 | }; | ||
| 3764 | } | ||
| 3765 | |||
| 3766 | /** | ||
| 3767 | * Computes a hash of an 'obj'. | ||
| 3768 | * Hash of a: | ||
| 3769 | * string is string | ||
| 3770 | * number is number as string | ||
| 3771 | * object is either result of calling $$hashKey function on the object or uniquely generated id, | ||
| 3772 | * that is also assigned to the $$hashKey property of the object. | ||
| 3773 | * | ||
| 3774 | * @param obj | ||
| 3775 | * @returns {string} hash string such that the same input will have the same hash string. | ||
| 3776 | * The resulting string key is in 'type:hashKey' format. | ||
| 3777 | */ | ||
| 3778 | function hashKey(obj, nextUidFn) { | ||
| 3779 | var key = obj && obj.$$hashKey; | ||
| 3780 | |||
| 3781 | if (key) { | ||
| 3782 | if (typeof key === 'function') { | ||
| 3783 | key = obj.$$hashKey(); | ||
| 3784 | } | ||
| 3785 | return key; | ||
| 3786 | } | ||
| 3787 | |||
| 3788 | var objType = typeof obj; | ||
| 3789 | if (objType == 'function' || (objType == 'object' && obj !== null)) { | ||
| 3790 | key = obj.$$hashKey = objType + ':' + (nextUidFn || nextUid)(); | ||
| 3791 | } else { | ||
| 3792 | key = objType + ':' + obj; | ||
| 3793 | } | ||
| 3794 | |||
| 3795 | return key; | ||
| 3796 | } | ||
| 3797 | |||
| 3798 | /** | ||
| 3799 | * HashMap which can use objects as keys | ||
| 3800 | */ | ||
| 3801 | function HashMap(array, isolatedUid) { | ||
| 3802 | if (isolatedUid) { | ||
| 3803 | var uid = 0; | ||
| 3804 | this.nextUid = function() { | ||
| 3805 | return ++uid; | ||
| 3806 | }; | ||
| 3807 | } | ||
| 3808 | forEach(array, this.put, this); | ||
| 3809 | } | ||
| 3810 | HashMap.prototype = { | ||
| 3811 | /** | ||
| 3812 | * Store key value pair | ||
| 3813 | * @param key key to store can be any type | ||
| 3814 | * @param value value to store can be any type | ||
| 3815 | */ | ||
| 3816 | put: function(key, value) { | ||
| 3817 | this[hashKey(key, this.nextUid)] = value; | ||
| 3818 | }, | ||
| 3819 | |||
| 3820 | /** | ||
| 3821 | * @param key | ||
| 3822 | * @returns {Object} the value for the key | ||
| 3823 | */ | ||
| 3824 | get: function(key) { | ||
| 3825 | return this[hashKey(key, this.nextUid)]; | ||
| 3826 | }, | ||
| 3827 | |||
| 3828 | /** | ||
| 3829 | * Remove the key/value pair | ||
| 3830 | * @param key | ||
| 3831 | */ | ||
| 3832 | remove: function(key) { | ||
| 3833 | var value = this[key = hashKey(key, this.nextUid)]; | ||
| 3834 | delete this[key]; | ||
| 3835 | return value; | ||
| 3836 | } | ||
| 3837 | }; | ||
| 3838 | |||
| 3839 | var $$HashMapProvider = [function() { | ||
| 3840 | this.$get = [function() { | ||
| 3841 | return HashMap; | ||
| 3842 | }]; | ||
| 3843 | }]; | ||
| 3844 | |||
| 3845 | /** | ||
| 3846 | * @ngdoc function | ||
| 3847 | * @module ng | ||
| 3848 | * @name angular.injector | ||
| 3849 | * @kind function | ||
| 3850 | * | ||
| 3851 | * @description | ||
| 3852 | * Creates an injector object that can be used for retrieving services as well as for | ||
| 3853 | * dependency injection (see {@link guide/di dependency injection}). | ||
| 3854 | * | ||
| 3855 | * @param {Array.<string|Function>} modules A list of module functions or their aliases. See | ||
| 3856 | * {@link angular.module}. The `ng` module must be explicitly added. | ||
| 3857 | * @param {boolean=} [strictDi=false] Whether the injector should be in strict mode, which | ||
| 3858 | * disallows argument name annotation inference. | ||
| 3859 | * @returns {injector} Injector object. See {@link auto.$injector $injector}. | ||
| 3860 | * | ||
| 3861 | * @example | ||
| 3862 | * Typical usage | ||
| 3863 | * ```js | ||
| 3864 | * // create an injector | ||
| 3865 | * var $injector = angular.injector(['ng']); | ||
| 3866 | * | ||
| 3867 | * // use the injector to kick off your application | ||
| 3868 | * // use the type inference to auto inject arguments, or use implicit injection | ||
| 3869 | * $injector.invoke(function($rootScope, $compile, $document) { | ||
| 3870 | * $compile($document)($rootScope); | ||
| 3871 | * $rootScope.$digest(); | ||
| 3872 | * }); | ||
| 3873 | * ``` | ||
| 3874 | * | ||
| 3875 | * Sometimes you want to get access to the injector of a currently running Angular app | ||
| 3876 | * from outside Angular. Perhaps, you want to inject and compile some markup after the | ||
| 3877 | * application has been bootstrapped. You can do this using the extra `injector()` added | ||
| 3878 | * to JQuery/jqLite elements. See {@link angular.element}. | ||
| 3879 | * | ||
| 3880 | * *This is fairly rare but could be the case if a third party library is injecting the | ||
| 3881 | * markup.* | ||
| 3882 | * | ||
| 3883 | * In the following example a new block of HTML containing a `ng-controller` | ||
| 3884 | * directive is added to the end of the document body by JQuery. We then compile and link | ||
| 3885 | * it into the current AngularJS scope. | ||
| 3886 | * | ||
| 3887 | * ```js | ||
| 3888 | * var $div = $('<div ng-controller="MyCtrl">{{content.label}}</div>'); | ||
| 3889 | * $(document.body).append($div); | ||
| 3890 | * | ||
| 3891 | * angular.element(document).injector().invoke(function($compile) { | ||
| 3892 | * var scope = angular.element($div).scope(); | ||
| 3893 | * $compile($div)(scope); | ||
| 3894 | * }); | ||
| 3895 | * ``` | ||
| 3896 | */ | ||
| 3897 | |||
| 3898 | |||
| 3899 | /** | ||
| 3900 | * @ngdoc module | ||
| 3901 | * @name auto | ||
| 3902 | * @installation | ||
| 3903 | * @description | ||
| 3904 | * | ||
| 3905 | * Implicit module which gets automatically added to each {@link auto.$injector $injector}. | ||
| 3906 | */ | ||
| 3907 | |||
| 3908 | var ARROW_ARG = /^([^\(]+?)=>/; | ||
| 3909 | var FN_ARGS = /^[^\(]*\(\s*([^\)]*)\)/m; | ||
| 3910 | var FN_ARG_SPLIT = /,/; | ||
| 3911 | var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/; | ||
| 3912 | var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg; | ||
| 3913 | var $injectorMinErr = minErr('$injector'); | ||
| 3914 | |||
| 3915 | function stringifyFn(fn) { | ||
| 3916 | // Support: Chrome 50-51 only | ||
| 3917 | // Creating a new string by adding `' '` at the end, to hack around some bug in Chrome v50/51 | ||
| 3918 | // (See https://github.com/angular/angular.js/issues/14487.) | ||
| 3919 | // TODO (gkalpak): Remove workaround when Chrome v52 is released | ||
| 3920 | return Function.prototype.toString.call(fn) + ' '; | ||
| 3921 | } | ||
| 3922 | |||
| 3923 | function extractArgs(fn) { | ||
| 3924 | var fnText = stringifyFn(fn).replace(STRIP_COMMENTS, ''), | ||
| 3925 | args = fnText.match(ARROW_ARG) || fnText.match(FN_ARGS); | ||
| 3926 | return args; | ||
| 3927 | } | ||
| 3928 | |||
| 3929 | function anonFn(fn) { | ||
| 3930 | // For anonymous functions, showing at the very least the function signature can help in | ||
| 3931 | // debugging. | ||
| 3932 | var args = extractArgs(fn); | ||
| 3933 | if (args) { | ||
| 3934 | return 'function(' + (args[1] || '').replace(/[\s\r\n]+/, ' ') + ')'; | ||
| 3935 | } | ||
| 3936 | return 'fn'; | ||
| 3937 | } | ||
| 3938 | |||
| 3939 | function annotate(fn, strictDi, name) { | ||
| 3940 | var $inject, | ||
| 3941 | argDecl, | ||
| 3942 | last; | ||
| 3943 | |||
| 3944 | if (typeof fn === 'function') { | ||
| 3945 | if (!($inject = fn.$inject)) { | ||
| 3946 | $inject = []; | ||
| 3947 | if (fn.length) { | ||
| 3948 | if (strictDi) { | ||
| 3949 | if (!isString(name) || !name) { | ||
| 3950 | name = fn.name || anonFn(fn); | ||
| 3951 | } | ||
| 3952 | throw $injectorMinErr('strictdi', | ||
| 3953 | '{0} is not using explicit annotation and cannot be invoked in strict mode', name); | ||
| 3954 | } | ||
| 3955 | argDecl = extractArgs(fn); | ||
| 3956 | forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg) { | ||
| 3957 | arg.replace(FN_ARG, function(all, underscore, name) { | ||
| 3958 | $inject.push(name); | ||
| 3959 | }); | ||
| 3960 | }); | ||
| 3961 | } | ||
| 3962 | fn.$inject = $inject; | ||
| 3963 | } | ||
| 3964 | } else if (isArray(fn)) { | ||
| 3965 | last = fn.length - 1; | ||
| 3966 | assertArgFn(fn[last], 'fn'); | ||
| 3967 | $inject = fn.slice(0, last); | ||
| 3968 | } else { | ||
| 3969 | assertArgFn(fn, 'fn', true); | ||
| 3970 | } | ||
| 3971 | return $inject; | ||
| 3972 | } | ||
| 3973 | |||
| 3974 | /////////////////////////////////////// | ||
| 3975 | |||
| 3976 | /** | ||
| 3977 | * @ngdoc service | ||
| 3978 | * @name $injector | ||
| 3979 | * | ||
| 3980 | * @description | ||
| 3981 | * | ||
| 3982 | * `$injector` is used to retrieve object instances as defined by | ||
| 3983 | * {@link auto.$provide provider}, instantiate types, invoke methods, | ||
| 3984 | * and load modules. | ||
| 3985 | * | ||
| 3986 | * The following always holds true: | ||
| 3987 | * | ||
| 3988 | * ```js | ||
| 3989 | * var $injector = angular.injector(); | ||
| 3990 | * expect($injector.get('$injector')).toBe($injector); | ||
| 3991 | * expect($injector.invoke(function($injector) { | ||
| 3992 | * return $injector; | ||
| 3993 | * })).toBe($injector); | ||
| 3994 | * ``` | ||
| 3995 | * | ||
| 3996 | * # Injection Function Annotation | ||
| 3997 | * | ||
| 3998 | * JavaScript does not have annotations, and annotations are needed for dependency injection. The | ||
| 3999 | * following are all valid ways of annotating function with injection arguments and are equivalent. | ||
| 4000 | * | ||
| 4001 | * ```js | ||
| 4002 | * // inferred (only works if code not minified/obfuscated) | ||
| 4003 | * $injector.invoke(function(serviceA){}); | ||
| 4004 | * | ||
| 4005 | * // annotated | ||
| 4006 | * function explicit(serviceA) {}; | ||
| 4007 | * explicit.$inject = ['serviceA']; | ||
| 4008 | * $injector.invoke(explicit); | ||
| 4009 | * | ||
| 4010 | * // inline | ||
| 4011 | * $injector.invoke(['serviceA', function(serviceA){}]); | ||
| 4012 | * ``` | ||
| 4013 | * | ||
| 4014 | * ## Inference | ||
| 4015 | * | ||
| 4016 | * In JavaScript calling `toString()` on a function returns the function definition. The definition | ||
| 4017 | * can then be parsed and the function arguments can be extracted. This method of discovering | ||
| 4018 | * annotations is disallowed when the injector is in strict mode. | ||
| 4019 | * *NOTE:* This does not work with minification, and obfuscation tools since these tools change the | ||
| 4020 | * argument names. | ||
| 4021 | * | ||
| 4022 | * ## `$inject` Annotation | ||
| 4023 | * By adding an `$inject` property onto a function the injection parameters can be specified. | ||
| 4024 | * | ||
| 4025 | * ## Inline | ||
| 4026 | * As an array of injection names, where the last item in the array is the function to call. | ||
| 4027 | */ | ||
| 4028 | |||
| 4029 | /** | ||
| 4030 | * @ngdoc method | ||
| 4031 | * @name $injector#get | ||
| 4032 | * | ||
| 4033 | * @description | ||
| 4034 | * Return an instance of the service. | ||
| 4035 | * | ||
| 4036 | * @param {string} name The name of the instance to retrieve. | ||
| 4037 | * @param {string=} caller An optional string to provide the origin of the function call for error messages. | ||
| 4038 | * @return {*} The instance. | ||
| 4039 | */ | ||
| 4040 | |||
| 4041 | /** | ||
| 4042 | * @ngdoc method | ||
| 4043 | * @name $injector#invoke | ||
| 4044 | * | ||
| 4045 | * @description | ||
| 4046 | * Invoke the method and supply the method arguments from the `$injector`. | ||
| 4047 | * | ||
| 4048 | * @param {Function|Array.<string|Function>} fn The injectable function to invoke. Function parameters are | ||
| 4049 | * injected according to the {@link guide/di $inject Annotation} rules. | ||
| 4050 | * @param {Object=} self The `this` for the invoked method. | ||
| 4051 | * @param {Object=} locals Optional object. If preset then any argument names are read from this | ||
| 4052 | * object first, before the `$injector` is consulted. | ||
| 4053 | * @returns {*} the value returned by the invoked `fn` function. | ||
| 4054 | */ | ||
| 4055 | |||
| 4056 | /** | ||
| 4057 | * @ngdoc method | ||
| 4058 | * @name $injector#has | ||
| 4059 | * | ||
| 4060 | * @description | ||
| 4061 | * Allows the user to query if the particular service exists. | ||
| 4062 | * | ||
| 4063 | * @param {string} name Name of the service to query. | ||
| 4064 | * @returns {boolean} `true` if injector has given service. | ||
| 4065 | */ | ||
| 4066 | |||
| 4067 | /** | ||
| 4068 | * @ngdoc method | ||
| 4069 | * @name $injector#instantiate | ||
| 4070 | * @description | ||
| 4071 | * Create a new instance of JS type. The method takes a constructor function, invokes the new | ||
| 4072 | * operator, and supplies all of the arguments to the constructor function as specified by the | ||
| 4073 | * constructor annotation. | ||
| 4074 | * | ||
| 4075 | * @param {Function} Type Annotated constructor function. | ||
| 4076 | * @param {Object=} locals Optional object. If preset then any argument names are read from this | ||
| 4077 | * object first, before the `$injector` is consulted. | ||
| 4078 | * @returns {Object} new instance of `Type`. | ||
| 4079 | */ | ||
| 4080 | |||
| 4081 | /** | ||
| 4082 | * @ngdoc method | ||
| 4083 | * @name $injector#annotate | ||
| 4084 | * | ||
| 4085 | * @description | ||
| 4086 | * Returns an array of service names which the function is requesting for injection. This API is | ||
| 4087 | * used by the injector to determine which services need to be injected into the function when the | ||
| 4088 | * function is invoked. There are three ways in which the function can be annotated with the needed | ||
| 4089 | * dependencies. | ||
| 4090 | * | ||
| 4091 | * # Argument names | ||
| 4092 | * | ||
| 4093 | * The simplest form is to extract the dependencies from the arguments of the function. This is done | ||
| 4094 | * by converting the function into a string using `toString()` method and extracting the argument | ||
| 4095 | * names. | ||
| 4096 | * ```js | ||
| 4097 | * // Given | ||
| 4098 | * function MyController($scope, $route) { | ||
| 4099 | * // ... | ||
| 4100 | * } | ||
| 4101 | * | ||
| 4102 | * // Then | ||
| 4103 | * expect(injector.annotate(MyController)).toEqual(['$scope', '$route']); | ||
| 4104 | * ``` | ||
| 4105 | * | ||
| 4106 | * You can disallow this method by using strict injection mode. | ||
| 4107 | * | ||
| 4108 | * This method does not work with code minification / obfuscation. For this reason the following | ||
| 4109 | * annotation strategies are supported. | ||
| 4110 | * | ||
| 4111 | * # The `$inject` property | ||
| 4112 | * | ||
| 4113 | * If a function has an `$inject` property and its value is an array of strings, then the strings | ||
| 4114 | * represent names of services to be injected into the function. | ||
| 4115 | * ```js | ||
| 4116 | * // Given | ||
| 4117 | * var MyController = function(obfuscatedScope, obfuscatedRoute) { | ||
| 4118 | * // ... | ||
| 4119 | * } | ||
| 4120 | * // Define function dependencies | ||
| 4121 | * MyController['$inject'] = ['$scope', '$route']; | ||
| 4122 | * | ||
| 4123 | * // Then | ||
| 4124 | * expect(injector.annotate(MyController)).toEqual(['$scope', '$route']); | ||
| 4125 | * ``` | ||
| 4126 | * | ||
| 4127 | * # The array notation | ||
| 4128 | * | ||
| 4129 | * It is often desirable to inline Injected functions and that's when setting the `$inject` property | ||
| 4130 | * is very inconvenient. In these situations using the array notation to specify the dependencies in | ||
| 4131 | * a way that survives minification is a better choice: | ||
| 4132 | * | ||
| 4133 | * ```js | ||
| 4134 | * // We wish to write this (not minification / obfuscation safe) | ||
| 4135 | * injector.invoke(function($compile, $rootScope) { | ||
| 4136 | * // ... | ||
| 4137 | * }); | ||
| 4138 | * | ||
| 4139 | * // We are forced to write break inlining | ||
| 4140 | * var tmpFn = function(obfuscatedCompile, obfuscatedRootScope) { | ||
| 4141 | * // ... | ||
| 4142 | * }; | ||
| 4143 | * tmpFn.$inject = ['$compile', '$rootScope']; | ||
| 4144 | * injector.invoke(tmpFn); | ||
| 4145 | * | ||
| 4146 | * // To better support inline function the inline annotation is supported | ||
| 4147 | * injector.invoke(['$compile', '$rootScope', function(obfCompile, obfRootScope) { | ||
| 4148 | * // ... | ||
| 4149 | * }]); | ||
| 4150 | * | ||
| 4151 | * // Therefore | ||
| 4152 | * expect(injector.annotate( | ||
| 4153 | * ['$compile', '$rootScope', function(obfus_$compile, obfus_$rootScope) {}]) | ||
| 4154 | * ).toEqual(['$compile', '$rootScope']); | ||
| 4155 | * ``` | ||
| 4156 | * | ||
| 4157 | * @param {Function|Array.<string|Function>} fn Function for which dependent service names need to | ||
| 4158 | * be retrieved as described above. | ||
| 4159 | * | ||
| 4160 | * @param {boolean=} [strictDi=false] Disallow argument name annotation inference. | ||
| 4161 | * | ||
| 4162 | * @returns {Array.<string>} The names of the services which the function requires. | ||
| 4163 | */ | ||
| 4164 | |||
| 4165 | |||
| 4166 | |||
| 4167 | |||
| 4168 | /** | ||
| 4169 | * @ngdoc service | ||
| 4170 | * @name $provide | ||
| 4171 | * | ||
| 4172 | * @description | ||
| 4173 | * | ||
| 4174 | * The {@link auto.$provide $provide} service has a number of methods for registering components | ||
| 4175 | * with the {@link auto.$injector $injector}. Many of these functions are also exposed on | ||
| 4176 | * {@link angular.Module}. | ||
| 4177 | * | ||
| 4178 | * An Angular **service** is a singleton object created by a **service factory**. These **service | ||
| 4179 | * factories** are functions which, in turn, are created by a **service provider**. | ||
| 4180 | * The **service providers** are constructor functions. When instantiated they must contain a | ||
| 4181 | * property called `$get`, which holds the **service factory** function. | ||
| 4182 | * | ||
| 4183 | * When you request a service, the {@link auto.$injector $injector} is responsible for finding the | ||
| 4184 | * correct **service provider**, instantiating it and then calling its `$get` **service factory** | ||
| 4185 | * function to get the instance of the **service**. | ||
| 4186 | * | ||
| 4187 | * Often services have no configuration options and there is no need to add methods to the service | ||
| 4188 | * provider. The provider will be no more than a constructor function with a `$get` property. For | ||
| 4189 | * these cases the {@link auto.$provide $provide} service has additional helper methods to register | ||
| 4190 | * services without specifying a provider. | ||
| 4191 | * | ||
| 4192 | * * {@link auto.$provide#provider provider(name, provider)} - registers a **service provider** with the | ||
| 4193 | * {@link auto.$injector $injector} | ||
| 4194 | * * {@link auto.$provide#constant constant(name, obj)} - registers a value/object that can be accessed by | ||
| 4195 | * providers and services. | ||
| 4196 | * * {@link auto.$provide#value value(name, obj)} - registers a value/object that can only be accessed by | ||
| 4197 | * services, not providers. | ||
| 4198 | * * {@link auto.$provide#factory factory(name, fn)} - registers a service **factory function** | ||
| 4199 | * that will be wrapped in a **service provider** object, whose `$get` property will contain the | ||
| 4200 | * given factory function. | ||
| 4201 | * * {@link auto.$provide#service service(name, Fn)} - registers a **constructor function** | ||
| 4202 | * that will be wrapped in a **service provider** object, whose `$get` property will instantiate | ||
| 4203 | * a new object using the given constructor function. | ||
| 4204 | * * {@link auto.$provide#decorator decorator(name, decorFn)} - registers a **decorator function** that | ||
| 4205 | * will be able to modify or replace the implementation of another service. | ||
| 4206 | * | ||
| 4207 | * See the individual methods for more information and examples. | ||
| 4208 | */ | ||
| 4209 | |||
| 4210 | /** | ||
| 4211 | * @ngdoc method | ||
| 4212 | * @name $provide#provider | ||
| 4213 | * @description | ||
| 4214 | * | ||
| 4215 | * Register a **provider function** with the {@link auto.$injector $injector}. Provider functions | ||
| 4216 | * are constructor functions, whose instances are responsible for "providing" a factory for a | ||
| 4217 | * service. | ||
| 4218 | * | ||
| 4219 | * Service provider names start with the name of the service they provide followed by `Provider`. | ||
| 4220 | * For example, the {@link ng.$log $log} service has a provider called | ||
| 4221 | * {@link ng.$logProvider $logProvider}. | ||
| 4222 | * | ||
| 4223 | * Service provider objects can have additional methods which allow configuration of the provider | ||
| 4224 | * and its service. Importantly, you can configure what kind of service is created by the `$get` | ||
| 4225 | * method, or how that service will act. For example, the {@link ng.$logProvider $logProvider} has a | ||
| 4226 | * method {@link ng.$logProvider#debugEnabled debugEnabled} | ||
| 4227 | * which lets you specify whether the {@link ng.$log $log} service will log debug messages to the | ||
| 4228 | * console or not. | ||
| 4229 | * | ||
| 4230 | * @param {string} name The name of the instance. NOTE: the provider will be available under `name + | ||
| 4231 | 'Provider'` key. | ||
| 4232 | * @param {(Object|function())} provider If the provider is: | ||
| 4233 | * | ||
| 4234 | * - `Object`: then it should have a `$get` method. The `$get` method will be invoked using | ||
| 4235 | * {@link auto.$injector#invoke $injector.invoke()} when an instance needs to be created. | ||
| 4236 | * - `Constructor`: a new instance of the provider will be created using | ||
| 4237 | * {@link auto.$injector#instantiate $injector.instantiate()}, then treated as `object`. | ||
| 4238 | * | ||
| 4239 | * @returns {Object} registered provider instance | ||
| 4240 | |||
| 4241 | * @example | ||
| 4242 | * | ||
| 4243 | * The following example shows how to create a simple event tracking service and register it using | ||
| 4244 | * {@link auto.$provide#provider $provide.provider()}. | ||
| 4245 | * | ||
| 4246 | * ```js | ||
| 4247 | * // Define the eventTracker provider | ||
| 4248 | * function EventTrackerProvider() { | ||
| 4249 | * var trackingUrl = '/track'; | ||
| 4250 | * | ||
| 4251 | * // A provider method for configuring where the tracked events should been saved | ||
| 4252 | * this.setTrackingUrl = function(url) { | ||
| 4253 | * trackingUrl = url; | ||
| 4254 | * }; | ||
| 4255 | * | ||
| 4256 | * // The service factory function | ||
| 4257 | * this.$get = ['$http', function($http) { | ||
| 4258 | * var trackedEvents = {}; | ||
| 4259 | * return { | ||
| 4260 | * // Call this to track an event | ||
| 4261 | * event: function(event) { | ||
| 4262 | * var count = trackedEvents[event] || 0; | ||
| 4263 | * count += 1; | ||
| 4264 | * trackedEvents[event] = count; | ||
| 4265 | * return count; | ||
| 4266 | * }, | ||
| 4267 | * // Call this to save the tracked events to the trackingUrl | ||
| 4268 | * save: function() { | ||
| 4269 | * $http.post(trackingUrl, trackedEvents); | ||
| 4270 | * } | ||
| 4271 | * }; | ||
| 4272 | * }]; | ||
| 4273 | * } | ||
| 4274 | * | ||
| 4275 | * describe('eventTracker', function() { | ||
| 4276 | * var postSpy; | ||
| 4277 | * | ||
| 4278 | * beforeEach(module(function($provide) { | ||
| 4279 | * // Register the eventTracker provider | ||
| 4280 | * $provide.provider('eventTracker', EventTrackerProvider); | ||
| 4281 | * })); | ||
| 4282 | * | ||
| 4283 | * beforeEach(module(function(eventTrackerProvider) { | ||
| 4284 | * // Configure eventTracker provider | ||
| 4285 | * eventTrackerProvider.setTrackingUrl('/custom-track'); | ||
| 4286 | * })); | ||
| 4287 | * | ||
| 4288 | * it('tracks events', inject(function(eventTracker) { | ||
| 4289 | * expect(eventTracker.event('login')).toEqual(1); | ||
| 4290 | * expect(eventTracker.event('login')).toEqual(2); | ||
| 4291 | * })); | ||
| 4292 | * | ||
| 4293 | * it('saves to the tracking url', inject(function(eventTracker, $http) { | ||
| 4294 | * postSpy = spyOn($http, 'post'); | ||
| 4295 | * eventTracker.event('login'); | ||
| 4296 | * eventTracker.save(); | ||
| 4297 | * expect(postSpy).toHaveBeenCalled(); | ||
| 4298 | * expect(postSpy.mostRecentCall.args[0]).not.toEqual('/track'); | ||
| 4299 | * expect(postSpy.mostRecentCall.args[0]).toEqual('/custom-track'); | ||
| 4300 | * expect(postSpy.mostRecentCall.args[1]).toEqual({ 'login': 1 }); | ||
| 4301 | * })); | ||
| 4302 | * }); | ||
| 4303 | * ``` | ||
| 4304 | */ | ||
| 4305 | |||
| 4306 | /** | ||
| 4307 | * @ngdoc method | ||
| 4308 | * @name $provide#factory | ||
| 4309 | * @description | ||
| 4310 | * | ||
| 4311 | * Register a **service factory**, which will be called to return the service instance. | ||
| 4312 | * This is short for registering a service where its provider consists of only a `$get` property, | ||
| 4313 | * which is the given service factory function. | ||
| 4314 | * You should use {@link auto.$provide#factory $provide.factory(getFn)} if you do not need to | ||
| 4315 | * configure your service in a provider. | ||
| 4316 | * | ||
| 4317 | * @param {string} name The name of the instance. | ||
| 4318 | * @param {Function|Array.<string|Function>} $getFn The injectable $getFn for the instance creation. | ||
| 4319 | * Internally this is a short hand for `$provide.provider(name, {$get: $getFn})`. | ||
| 4320 | * @returns {Object} registered provider instance | ||
| 4321 | * | ||
| 4322 | * @example | ||
| 4323 | * Here is an example of registering a service | ||
| 4324 | * ```js | ||
| 4325 | * $provide.factory('ping', ['$http', function($http) { | ||
| 4326 | * return function ping() { | ||
| 4327 | * return $http.send('/ping'); | ||
| 4328 | * }; | ||
| 4329 | * }]); | ||
| 4330 | * ``` | ||
| 4331 | * You would then inject and use this service like this: | ||
| 4332 | * ```js | ||
| 4333 | * someModule.controller('Ctrl', ['ping', function(ping) { | ||
| 4334 | * ping(); | ||
| 4335 | * }]); | ||
| 4336 | * ``` | ||
| 4337 | */ | ||
| 4338 | |||
| 4339 | |||
| 4340 | /** | ||
| 4341 | * @ngdoc method | ||
| 4342 | * @name $provide#service | ||
| 4343 | * @description | ||
| 4344 | * | ||
| 4345 | * Register a **service constructor**, which will be invoked with `new` to create the service | ||
| 4346 | * instance. | ||
| 4347 | * This is short for registering a service where its provider's `$get` property is a factory | ||
| 4348 | * function that returns an instance instantiated by the injector from the service constructor | ||
| 4349 | * function. | ||
| 4350 | * | ||
| 4351 | * Internally it looks a bit like this: | ||
| 4352 | * | ||
| 4353 | * ``` | ||
| 4354 | * { | ||
| 4355 | * $get: function() { | ||
| 4356 | * return $injector.instantiate(constructor); | ||
| 4357 | * } | ||
| 4358 | * } | ||
| 4359 | * ``` | ||
| 4360 | * | ||
| 4361 | * | ||
| 4362 | * You should use {@link auto.$provide#service $provide.service(class)} if you define your service | ||
| 4363 | * as a type/class. | ||
| 4364 | * | ||
| 4365 | * @param {string} name The name of the instance. | ||
| 4366 | * @param {Function|Array.<string|Function>} constructor An injectable class (constructor function) | ||
| 4367 | * that will be instantiated. | ||
| 4368 | * @returns {Object} registered provider instance | ||
| 4369 | * | ||
| 4370 | * @example | ||
| 4371 | * Here is an example of registering a service using | ||
| 4372 | * {@link auto.$provide#service $provide.service(class)}. | ||
| 4373 | * ```js | ||
| 4374 | * var Ping = function($http) { | ||
| 4375 | * this.$http = $http; | ||
| 4376 | * }; | ||
| 4377 | * | ||
| 4378 | * Ping.$inject = ['$http']; | ||
| 4379 | * | ||
| 4380 | * Ping.prototype.send = function() { | ||
| 4381 | * return this.$http.get('/ping'); | ||
| 4382 | * }; | ||
| 4383 | * $provide.service('ping', Ping); | ||
| 4384 | * ``` | ||
| 4385 | * You would then inject and use this service like this: | ||
| 4386 | * ```js | ||
| 4387 | * someModule.controller('Ctrl', ['ping', function(ping) { | ||
| 4388 | * ping.send(); | ||
| 4389 | * }]); | ||
| 4390 | * ``` | ||
| 4391 | */ | ||
| 4392 | |||
| 4393 | |||
| 4394 | /** | ||
| 4395 | * @ngdoc method | ||
| 4396 | * @name $provide#value | ||
| 4397 | * @description | ||
| 4398 | * | ||
| 4399 | * Register a **value service** with the {@link auto.$injector $injector}, such as a string, a | ||
| 4400 | * number, an array, an object or a function. This is short for registering a service where its | ||
| 4401 | * provider's `$get` property is a factory function that takes no arguments and returns the **value | ||
| 4402 | * service**. That also means it is not possible to inject other services into a value service. | ||
| 4403 | * | ||
| 4404 | * Value services are similar to constant services, except that they cannot be injected into a | ||
| 4405 | * module configuration function (see {@link angular.Module#config}) but they can be overridden by | ||
| 4406 | * an Angular {@link auto.$provide#decorator decorator}. | ||
| 4407 | * | ||
| 4408 | * @param {string} name The name of the instance. | ||
| 4409 | * @param {*} value The value. | ||
| 4410 | * @returns {Object} registered provider instance | ||
| 4411 | * | ||
| 4412 | * @example | ||
| 4413 | * Here are some examples of creating value services. | ||
| 4414 | * ```js | ||
| 4415 | * $provide.value('ADMIN_USER', 'admin'); | ||
| 4416 | * | ||
| 4417 | * $provide.value('RoleLookup', { admin: 0, writer: 1, reader: 2 }); | ||
| 4418 | * | ||
| 4419 | * $provide.value('halfOf', function(value) { | ||
| 4420 | * return value / 2; | ||
| 4421 | * }); | ||
| 4422 | * ``` | ||
| 4423 | */ | ||
| 4424 | |||
| 4425 | |||
| 4426 | /** | ||
| 4427 | * @ngdoc method | ||
| 4428 | * @name $provide#constant | ||
| 4429 | * @description | ||
| 4430 | * | ||
| 4431 | * Register a **constant service** with the {@link auto.$injector $injector}, such as a string, | ||
| 4432 | * a number, an array, an object or a function. Like the {@link auto.$provide#value value}, it is not | ||
| 4433 | * possible to inject other services into a constant. | ||
| 4434 | * | ||
| 4435 | * But unlike {@link auto.$provide#value value}, a constant can be | ||
| 4436 | * injected into a module configuration function (see {@link angular.Module#config}) and it cannot | ||
| 4437 | * be overridden by an Angular {@link auto.$provide#decorator decorator}. | ||
| 4438 | * | ||
| 4439 | * @param {string} name The name of the constant. | ||
| 4440 | * @param {*} value The constant value. | ||
| 4441 | * @returns {Object} registered instance | ||
| 4442 | * | ||
| 4443 | * @example | ||
| 4444 | * Here a some examples of creating constants: | ||
| 4445 | * ```js | ||
| 4446 | * $provide.constant('SHARD_HEIGHT', 306); | ||
| 4447 | * | ||
| 4448 | * $provide.constant('MY_COLOURS', ['red', 'blue', 'grey']); | ||
| 4449 | * | ||
| 4450 | * $provide.constant('double', function(value) { | ||
| 4451 | * return value * 2; | ||
| 4452 | * }); | ||
| 4453 | * ``` | ||
| 4454 | */ | ||
| 4455 | |||
| 4456 | |||
| 4457 | /** | ||
| 4458 | * @ngdoc method | ||
| 4459 | * @name $provide#decorator | ||
| 4460 | * @description | ||
| 4461 | * | ||
| 4462 | * Register a **decorator function** with the {@link auto.$injector $injector}. A decorator function | ||
| 4463 | * intercepts the creation of a service, allowing it to override or modify the behavior of the | ||
| 4464 | * service. The return value of the decorator function may be the original service, or a new service | ||
| 4465 | * that replaces (or wraps and delegates to) the original service. | ||
| 4466 | * | ||
| 4467 | * You can find out more about using decorators in the {@link guide/decorators} guide. | ||
| 4468 | * | ||
| 4469 | * @param {string} name The name of the service to decorate. | ||
| 4470 | * @param {Function|Array.<string|Function>} decorator This function will be invoked when the service needs to be | ||
| 4471 | * provided and should return the decorated service instance. The function is called using | ||
| 4472 | * the {@link auto.$injector#invoke injector.invoke} method and is therefore fully injectable. | ||
| 4473 | * Local injection arguments: | ||
| 4474 | * | ||
| 4475 | * * `$delegate` - The original service instance, which can be replaced, monkey patched, configured, | ||
| 4476 | * decorated or delegated to. | ||
| 4477 | * | ||
| 4478 | * @example | ||
| 4479 | * Here we decorate the {@link ng.$log $log} service to convert warnings to errors by intercepting | ||
| 4480 | * calls to {@link ng.$log#error $log.warn()}. | ||
| 4481 | * ```js | ||
| 4482 | * $provide.decorator('$log', ['$delegate', function($delegate) { | ||
| 4483 | * $delegate.warn = $delegate.error; | ||
| 4484 | * return $delegate; | ||
| 4485 | * }]); | ||
| 4486 | * ``` | ||
| 4487 | */ | ||
| 4488 | |||
| 4489 | |||
| 4490 | function createInjector(modulesToLoad, strictDi) { | ||
| 4491 | strictDi = (strictDi === true); | ||
| 4492 | var INSTANTIATING = {}, | ||
| 4493 | providerSuffix = 'Provider', | ||
| 4494 | path = [], | ||
| 4495 | loadedModules = new HashMap([], true), | ||
| 4496 | providerCache = { | ||
| 4497 | $provide: { | ||
| 4498 | provider: supportObject(provider), | ||
| 4499 | factory: supportObject(factory), | ||
| 4500 | service: supportObject(service), | ||
| 4501 | value: supportObject(value), | ||
| 4502 | constant: supportObject(constant), | ||
| 4503 | decorator: decorator | ||
| 4504 | } | ||
| 4505 | }, | ||
| 4506 | providerInjector = (providerCache.$injector = | ||
| 4507 | createInternalInjector(providerCache, function(serviceName, caller) { | ||
| 4508 | if (angular.isString(caller)) { | ||
| 4509 | path.push(caller); | ||
| 4510 | } | ||
| 4511 | throw $injectorMinErr('unpr', "Unknown provider: {0}", path.join(' <- ')); | ||
| 4512 | })), | ||
| 4513 | instanceCache = {}, | ||
| 4514 | protoInstanceInjector = | ||
| 4515 | createInternalInjector(instanceCache, function(serviceName, caller) { | ||
| 4516 | var provider = providerInjector.get(serviceName + providerSuffix, caller); | ||
| 4517 | return instanceInjector.invoke( | ||
| 4518 | provider.$get, provider, undefined, serviceName); | ||
| 4519 | }), | ||
| 4520 | instanceInjector = protoInstanceInjector; | ||
| 4521 | |||
| 4522 | providerCache['$injector' + providerSuffix] = { $get: valueFn(protoInstanceInjector) }; | ||
| 4523 | var runBlocks = loadModules(modulesToLoad); | ||
| 4524 | instanceInjector = protoInstanceInjector.get('$injector'); | ||
| 4525 | instanceInjector.strictDi = strictDi; | ||
| 4526 | forEach(runBlocks, function(fn) { if (fn) instanceInjector.invoke(fn); }); | ||
| 4527 | |||
| 4528 | return instanceInjector; | ||
| 4529 | |||
| 4530 | //////////////////////////////////// | ||
| 4531 | // $provider | ||
| 4532 | //////////////////////////////////// | ||
| 4533 | |||
| 4534 | function supportObject(delegate) { | ||
| 4535 | return function(key, value) { | ||
| 4536 | if (isObject(key)) { | ||
| 4537 | forEach(key, reverseParams(delegate)); | ||
| 4538 | } else { | ||
| 4539 | return delegate(key, value); | ||
| 4540 | } | ||
| 4541 | }; | ||
| 4542 | } | ||
| 4543 | |||
| 4544 | function provider(name, provider_) { | ||
| 4545 | assertNotHasOwnProperty(name, 'service'); | ||
| 4546 | if (isFunction(provider_) || isArray(provider_)) { | ||
| 4547 | provider_ = providerInjector.instantiate(provider_); | ||
| 4548 | } | ||
| 4549 | if (!provider_.$get) { | ||
| 4550 | throw $injectorMinErr('pget', "Provider '{0}' must define $get factory method.", name); | ||
| 4551 | } | ||
| 4552 | return providerCache[name + providerSuffix] = provider_; | ||
| 4553 | } | ||
| 4554 | |||
| 4555 | function enforceReturnValue(name, factory) { | ||
| 4556 | return function enforcedReturnValue() { | ||
| 4557 | var result = instanceInjector.invoke(factory, this); | ||
| 4558 | if (isUndefined(result)) { | ||
| 4559 | throw $injectorMinErr('undef', "Provider '{0}' must return a value from $get factory method.", name); | ||
| 4560 | } | ||
| 4561 | return result; | ||
| 4562 | }; | ||
| 4563 | } | ||
| 4564 | |||
| 4565 | function factory(name, factoryFn, enforce) { | ||
| 4566 | return provider(name, { | ||
| 4567 | $get: enforce !== false ? enforceReturnValue(name, factoryFn) : factoryFn | ||
| 4568 | }); | ||
| 4569 | } | ||
| 4570 | |||
| 4571 | function service(name, constructor) { | ||
| 4572 | return factory(name, ['$injector', function($injector) { | ||
| 4573 | return $injector.instantiate(constructor); | ||
| 4574 | }]); | ||
| 4575 | } | ||
| 4576 | |||
| 4577 | function value(name, val) { return factory(name, valueFn(val), false); } | ||
| 4578 | |||
| 4579 | function constant(name, value) { | ||
| 4580 | assertNotHasOwnProperty(name, 'constant'); | ||
| 4581 | providerCache[name] = value; | ||
| 4582 | instanceCache[name] = value; | ||
| 4583 | } | ||
| 4584 | |||
| 4585 | function decorator(serviceName, decorFn) { | ||
| 4586 | var origProvider = providerInjector.get(serviceName + providerSuffix), | ||
| 4587 | orig$get = origProvider.$get; | ||
| 4588 | |||
| 4589 | origProvider.$get = function() { | ||
| 4590 | var origInstance = instanceInjector.invoke(orig$get, origProvider); | ||
| 4591 | return instanceInjector.invoke(decorFn, null, {$delegate: origInstance}); | ||
| 4592 | }; | ||
| 4593 | } | ||
| 4594 | |||
| 4595 | //////////////////////////////////// | ||
| 4596 | // Module Loading | ||
| 4597 | //////////////////////////////////// | ||
| 4598 | function loadModules(modulesToLoad) { | ||
| 4599 | assertArg(isUndefined(modulesToLoad) || isArray(modulesToLoad), 'modulesToLoad', 'not an array'); | ||
| 4600 | var runBlocks = [], moduleFn; | ||
| 4601 | forEach(modulesToLoad, function(module) { | ||
| 4602 | if (loadedModules.get(module)) return; | ||
| 4603 | loadedModules.put(module, true); | ||
| 4604 | |||
| 4605 | function runInvokeQueue(queue) { | ||
| 4606 | var i, ii; | ||
| 4607 | for (i = 0, ii = queue.length; i < ii; i++) { | ||
| 4608 | var invokeArgs = queue[i], | ||
| 4609 | provider = providerInjector.get(invokeArgs[0]); | ||
| 4610 | |||
| 4611 | provider[invokeArgs[1]].apply(provider, invokeArgs[2]); | ||
| 4612 | } | ||
| 4613 | } | ||
| 4614 | |||
| 4615 | try { | ||
| 4616 | if (isString(module)) { | ||
| 4617 | moduleFn = angularModule(module); | ||
| 4618 | runBlocks = runBlocks.concat(loadModules(moduleFn.requires)).concat(moduleFn._runBlocks); | ||
| 4619 | runInvokeQueue(moduleFn._invokeQueue); | ||
| 4620 | runInvokeQueue(moduleFn._configBlocks); | ||
| 4621 | } else if (isFunction(module)) { | ||
| 4622 | runBlocks.push(providerInjector.invoke(module)); | ||
| 4623 | } else if (isArray(module)) { | ||
| 4624 | runBlocks.push(providerInjector.invoke(module)); | ||
| 4625 | } else { | ||
| 4626 | assertArgFn(module, 'module'); | ||
| 4627 | } | ||
| 4628 | } catch (e) { | ||
| 4629 | if (isArray(module)) { | ||
| 4630 | module = module[module.length - 1]; | ||
| 4631 | } | ||
| 4632 | if (e.message && e.stack && e.stack.indexOf(e.message) == -1) { | ||
| 4633 | // Safari & FF's stack traces don't contain error.message content | ||
| 4634 | // unlike those of Chrome and IE | ||
| 4635 | // So if stack doesn't contain message, we create a new string that contains both. | ||
| 4636 | // Since error.stack is read-only in Safari, I'm overriding e and not e.stack here. | ||
| 4637 | /* jshint -W022 */ | ||
| 4638 | e = e.message + '\n' + e.stack; | ||
| 4639 | } | ||
| 4640 | throw $injectorMinErr('modulerr', "Failed to instantiate module {0} due to:\n{1}", | ||
| 4641 | module, e.stack || e.message || e); | ||
| 4642 | } | ||
| 4643 | }); | ||
| 4644 | return runBlocks; | ||
| 4645 | } | ||
| 4646 | |||
| 4647 | //////////////////////////////////// | ||
| 4648 | // internal Injector | ||
| 4649 | //////////////////////////////////// | ||
| 4650 | |||
| 4651 | function createInternalInjector(cache, factory) { | ||
| 4652 | |||
| 4653 | function getService(serviceName, caller) { | ||
| 4654 | if (cache.hasOwnProperty(serviceName)) { | ||
| 4655 | if (cache[serviceName] === INSTANTIATING) { | ||
| 4656 | throw $injectorMinErr('cdep', 'Circular dependency found: {0}', | ||
| 4657 | serviceName + ' <- ' + path.join(' <- ')); | ||
| 4658 | } | ||
| 4659 | return cache[serviceName]; | ||
| 4660 | } else { | ||
| 4661 | try { | ||
| 4662 | path.unshift(serviceName); | ||
| 4663 | cache[serviceName] = INSTANTIATING; | ||
| 4664 | return cache[serviceName] = factory(serviceName, caller); | ||
| 4665 | } catch (err) { | ||
| 4666 | if (cache[serviceName] === INSTANTIATING) { | ||
| 4667 | delete cache[serviceName]; | ||
| 4668 | } | ||
| 4669 | throw err; | ||
| 4670 | } finally { | ||
| 4671 | path.shift(); | ||
| 4672 | } | ||
| 4673 | } | ||
| 4674 | } | ||
| 4675 | |||
| 4676 | |||
| 4677 | function injectionArgs(fn, locals, serviceName) { | ||
| 4678 | var args = [], | ||
| 4679 | $inject = createInjector.$$annotate(fn, strictDi, serviceName); | ||
| 4680 | |||
| 4681 | for (var i = 0, length = $inject.length; i < length; i++) { | ||
| 4682 | var key = $inject[i]; | ||
| 4683 | if (typeof key !== 'string') { | ||
| 4684 | throw $injectorMinErr('itkn', | ||
| 4685 | 'Incorrect injection token! Expected service name as string, got {0}', key); | ||
| 4686 | } | ||
| 4687 | args.push(locals && locals.hasOwnProperty(key) ? locals[key] : | ||
| 4688 | getService(key, serviceName)); | ||
| 4689 | } | ||
| 4690 | return args; | ||
| 4691 | } | ||
| 4692 | |||
| 4693 | function isClass(func) { | ||
| 4694 | // IE 9-11 do not support classes and IE9 leaks with the code below. | ||
| 4695 | if (msie <= 11) { | ||
| 4696 | return false; | ||
| 4697 | } | ||
| 4698 | // Support: Edge 12-13 only | ||
| 4699 | // See: https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/6156135/ | ||
| 4700 | return typeof func === 'function' | ||
| 4701 | && /^(?:class\b|constructor\()/.test(stringifyFn(func)); | ||
| 4702 | } | ||
| 4703 | |||
| 4704 | function invoke(fn, self, locals, serviceName) { | ||
| 4705 | if (typeof locals === 'string') { | ||
| 4706 | serviceName = locals; | ||
| 4707 | locals = null; | ||
| 4708 | } | ||
| 4709 | |||
| 4710 | var args = injectionArgs(fn, locals, serviceName); | ||
| 4711 | if (isArray(fn)) { | ||
| 4712 | fn = fn[fn.length - 1]; | ||
| 4713 | } | ||
| 4714 | |||
| 4715 | if (!isClass(fn)) { | ||
| 4716 | // http://jsperf.com/angularjs-invoke-apply-vs-switch | ||
| 4717 | // #5388 | ||
| 4718 | return fn.apply(self, args); | ||
| 4719 | } else { | ||
| 4720 | args.unshift(null); | ||
| 4721 | return new (Function.prototype.bind.apply(fn, args))(); | ||
| 4722 | } | ||
| 4723 | } | ||
| 4724 | |||
| 4725 | |||
| 4726 | function instantiate(Type, locals, serviceName) { | ||
| 4727 | // Check if Type is annotated and use just the given function at n-1 as parameter | ||
| 4728 | // e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]); | ||
| 4729 | var ctor = (isArray(Type) ? Type[Type.length - 1] : Type); | ||
| 4730 | var args = injectionArgs(Type, locals, serviceName); | ||
| 4731 | // Empty object at position 0 is ignored for invocation with `new`, but required. | ||
| 4732 | args.unshift(null); | ||
| 4733 | return new (Function.prototype.bind.apply(ctor, args))(); | ||
| 4734 | } | ||
| 4735 | |||
| 4736 | |||
| 4737 | return { | ||
| 4738 | invoke: invoke, | ||
| 4739 | instantiate: instantiate, | ||
| 4740 | get: getService, | ||
| 4741 | annotate: createInjector.$$annotate, | ||
| 4742 | has: function(name) { | ||
| 4743 | return providerCache.hasOwnProperty(name + providerSuffix) || cache.hasOwnProperty(name); | ||
| 4744 | } | ||
| 4745 | }; | ||
| 4746 | } | ||
| 4747 | } | ||
| 4748 | |||
| 4749 | createInjector.$$annotate = annotate; | ||
| 4750 | |||
| 4751 | /** | ||
| 4752 | * @ngdoc provider | ||
| 4753 | * @name $anchorScrollProvider | ||
| 4754 | * | ||
| 4755 | * @description | ||
| 4756 | * Use `$anchorScrollProvider` to disable automatic scrolling whenever | ||
| 4757 | * {@link ng.$location#hash $location.hash()} changes. | ||
| 4758 | */ | ||
| 4759 | function $AnchorScrollProvider() { | ||
| 4760 | |||
| 4761 | var autoScrollingEnabled = true; | ||
| 4762 | |||
| 4763 | /** | ||
| 4764 | * @ngdoc method | ||
| 4765 | * @name $anchorScrollProvider#disableAutoScrolling | ||
| 4766 | * | ||
| 4767 | * @description | ||
| 4768 | * By default, {@link ng.$anchorScroll $anchorScroll()} will automatically detect changes to | ||
| 4769 | * {@link ng.$location#hash $location.hash()} and scroll to the element matching the new hash.<br /> | ||
| 4770 | * Use this method to disable automatic scrolling. | ||
| 4771 | * | ||
| 4772 | * If automatic scrolling is disabled, one must explicitly call | ||
| 4773 | * {@link ng.$anchorScroll $anchorScroll()} in order to scroll to the element related to the | ||
| 4774 | * current hash. | ||
| 4775 | */ | ||
| 4776 | this.disableAutoScrolling = function() { | ||
| 4777 | autoScrollingEnabled = false; | ||
| 4778 | }; | ||
| 4779 | |||
| 4780 | /** | ||
| 4781 | * @ngdoc service | ||
| 4782 | * @name $anchorScroll | ||
| 4783 | * @kind function | ||
| 4784 | * @requires $window | ||
| 4785 | * @requires $location | ||
| 4786 | * @requires $rootScope | ||
| 4787 | * | ||
| 4788 | * @description | ||
| 4789 | * When called, it scrolls to the element related to the specified `hash` or (if omitted) to the | ||
| 4790 | * current value of {@link ng.$location#hash $location.hash()}, according to the rules specified | ||
| 4791 | * in the | ||
| 4792 | * [HTML5 spec](http://www.w3.org/html/wg/drafts/html/master/browsers.html#an-indicated-part-of-the-document). | ||
| 4793 | * | ||
| 4794 | * It also watches the {@link ng.$location#hash $location.hash()} and automatically scrolls to | ||
| 4795 | * match any anchor whenever it changes. This can be disabled by calling | ||
| 4796 | * {@link ng.$anchorScrollProvider#disableAutoScrolling $anchorScrollProvider.disableAutoScrolling()}. | ||
| 4797 | * | ||
| 4798 | * Additionally, you can use its {@link ng.$anchorScroll#yOffset yOffset} property to specify a | ||
| 4799 | * vertical scroll-offset (either fixed or dynamic). | ||
| 4800 | * | ||
| 4801 | * @param {string=} hash The hash specifying the element to scroll to. If omitted, the value of | ||
| 4802 | * {@link ng.$location#hash $location.hash()} will be used. | ||
| 4803 | * | ||
| 4804 | * @property {(number|function|jqLite)} yOffset | ||
| 4805 | * If set, specifies a vertical scroll-offset. This is often useful when there are fixed | ||
| 4806 | * positioned elements at the top of the page, such as navbars, headers etc. | ||
| 4807 | * | ||
| 4808 | * `yOffset` can be specified in various ways: | ||
| 4809 | * - **number**: A fixed number of pixels to be used as offset.<br /><br /> | ||
| 4810 | * - **function**: A getter function called everytime `$anchorScroll()` is executed. Must return | ||
| 4811 | * a number representing the offset (in pixels).<br /><br /> | ||
| 4812 | * - **jqLite**: A jqLite/jQuery element to be used for specifying the offset. The distance from | ||
| 4813 | * the top of the page to the element's bottom will be used as offset.<br /> | ||
| 4814 | * **Note**: The element will be taken into account only as long as its `position` is set to | ||
| 4815 | * `fixed`. This option is useful, when dealing with responsive navbars/headers that adjust | ||
| 4816 | * their height and/or positioning according to the viewport's size. | ||
| 4817 | * | ||
| 4818 | * <br /> | ||
| 4819 | * <div class="alert alert-warning"> | ||
| 4820 | * In order for `yOffset` to work properly, scrolling should take place on the document's root and | ||
| 4821 | * not some child element. | ||
| 4822 | * </div> | ||
| 4823 | * | ||
| 4824 | * @example | ||
| 4825 | <example module="anchorScrollExample"> | ||
| 4826 | <file name="index.html"> | ||
| 4827 | <div id="scrollArea" ng-controller="ScrollController"> | ||
| 4828 | <a ng-click="gotoBottom()">Go to bottom</a> | ||
| 4829 | <a id="bottom"></a> You're at the bottom! | ||
| 4830 | </div> | ||
| 4831 | </file> | ||
| 4832 | <file name="script.js"> | ||
| 4833 | angular.module('anchorScrollExample', []) | ||
| 4834 | .controller('ScrollController', ['$scope', '$location', '$anchorScroll', | ||
| 4835 | function ($scope, $location, $anchorScroll) { | ||
| 4836 | $scope.gotoBottom = function() { | ||
| 4837 | // set the location.hash to the id of | ||
| 4838 | // the element you wish to scroll to. | ||
| 4839 | $location.hash('bottom'); | ||
| 4840 | |||
| 4841 | // call $anchorScroll() | ||
| 4842 | $anchorScroll(); | ||
| 4843 | }; | ||
| 4844 | }]); | ||
| 4845 | </file> | ||
| 4846 | <file name="style.css"> | ||
| 4847 | #scrollArea { | ||
| 4848 | height: 280px; | ||
| 4849 | overflow: auto; | ||
| 4850 | } | ||
| 4851 | |||
| 4852 | #bottom { | ||
| 4853 | display: block; | ||
| 4854 | margin-top: 2000px; | ||
| 4855 | } | ||
| 4856 | </file> | ||
| 4857 | </example> | ||
| 4858 | * | ||
| 4859 | * <hr /> | ||
| 4860 | * The example below illustrates the use of a vertical scroll-offset (specified as a fixed value). | ||
| 4861 | * See {@link ng.$anchorScroll#yOffset $anchorScroll.yOffset} for more details. | ||
| 4862 | * | ||
| 4863 | * @example | ||
| 4864 | <example module="anchorScrollOffsetExample"> | ||
| 4865 | <file name="index.html"> | ||
| 4866 | <div class="fixed-header" ng-controller="headerCtrl"> | ||
| 4867 | <a href="" ng-click="gotoAnchor(x)" ng-repeat="x in [1,2,3,4,5]"> | ||
| 4868 | Go to anchor {{x}} | ||
| 4869 | </a> | ||
| 4870 | </div> | ||
| 4871 | <div id="anchor{{x}}" class="anchor" ng-repeat="x in [1,2,3,4,5]"> | ||
| 4872 | Anchor {{x}} of 5 | ||
| 4873 | </div> | ||
| 4874 | </file> | ||
| 4875 | <file name="script.js"> | ||
| 4876 | angular.module('anchorScrollOffsetExample', []) | ||
| 4877 | .run(['$anchorScroll', function($anchorScroll) { | ||
| 4878 | $anchorScroll.yOffset = 50; // always scroll by 50 extra pixels | ||
| 4879 | }]) | ||
| 4880 | .controller('headerCtrl', ['$anchorScroll', '$location', '$scope', | ||
| 4881 | function ($anchorScroll, $location, $scope) { | ||
| 4882 | $scope.gotoAnchor = function(x) { | ||
| 4883 | var newHash = 'anchor' + x; | ||
| 4884 | if ($location.hash() !== newHash) { | ||
| 4885 | // set the $location.hash to `newHash` and | ||
| 4886 | // $anchorScroll will automatically scroll to it | ||
| 4887 | $location.hash('anchor' + x); | ||
| 4888 | } else { | ||
| 4889 | // call $anchorScroll() explicitly, | ||
| 4890 | // since $location.hash hasn't changed | ||
| 4891 | $anchorScroll(); | ||
| 4892 | } | ||
| 4893 | }; | ||
| 4894 | } | ||
| 4895 | ]); | ||
| 4896 | </file> | ||
| 4897 | <file name="style.css"> | ||
| 4898 | body { | ||
| 4899 | padding-top: 50px; | ||
| 4900 | } | ||
| 4901 | |||
| 4902 | .anchor { | ||
| 4903 | border: 2px dashed DarkOrchid; | ||
| 4904 | padding: 10px 10px 200px 10px; | ||
| 4905 | } | ||
| 4906 | |||
| 4907 | .fixed-header { | ||
| 4908 | background-color: rgba(0, 0, 0, 0.2); | ||
| 4909 | height: 50px; | ||
| 4910 | position: fixed; | ||
| 4911 | top: 0; left: 0; right: 0; | ||
| 4912 | } | ||
| 4913 | |||
| 4914 | .fixed-header > a { | ||
| 4915 | display: inline-block; | ||
| 4916 | margin: 5px 15px; | ||
| 4917 | } | ||
| 4918 | </file> | ||
| 4919 | </example> | ||
| 4920 | */ | ||
| 4921 | this.$get = ['$window', '$location', '$rootScope', function($window, $location, $rootScope) { | ||
| 4922 | var document = $window.document; | ||
| 4923 | |||
| 4924 | // Helper function to get first anchor from a NodeList | ||
| 4925 | // (using `Array#some()` instead of `angular#forEach()` since it's more performant | ||
| 4926 | // and working in all supported browsers.) | ||
| 4927 | function getFirstAnchor(list) { | ||
| 4928 | var result = null; | ||
| 4929 | Array.prototype.some.call(list, function(element) { | ||
| 4930 | if (nodeName_(element) === 'a') { | ||
| 4931 | result = element; | ||
| 4932 | return true; | ||
| 4933 | } | ||
| 4934 | }); | ||
| 4935 | return result; | ||
| 4936 | } | ||
| 4937 | |||
| 4938 | function getYOffset() { | ||
| 4939 | |||
| 4940 | var offset = scroll.yOffset; | ||
| 4941 | |||
| 4942 | if (isFunction(offset)) { | ||
| 4943 | offset = offset(); | ||
| 4944 | } else if (isElement(offset)) { | ||
| 4945 | var elem = offset[0]; | ||
| 4946 | var style = $window.getComputedStyle(elem); | ||
| 4947 | if (style.position !== 'fixed') { | ||
| 4948 | offset = 0; | ||
| 4949 | } else { | ||
| 4950 | offset = elem.getBoundingClientRect().bottom; | ||
| 4951 | } | ||
| 4952 | } else if (!isNumber(offset)) { | ||
| 4953 | offset = 0; | ||
| 4954 | } | ||
| 4955 | |||
| 4956 | return offset; | ||
| 4957 | } | ||
| 4958 | |||
| 4959 | function scrollTo(elem) { | ||
| 4960 | if (elem) { | ||
| 4961 | elem.scrollIntoView(); | ||
| 4962 | |||
| 4963 | var offset = getYOffset(); | ||
| 4964 | |||
| 4965 | if (offset) { | ||
| 4966 | // `offset` is the number of pixels we should scroll UP in order to align `elem` properly. | ||
| 4967 | // This is true ONLY if the call to `elem.scrollIntoView()` initially aligns `elem` at the | ||
| 4968 | // top of the viewport. | ||
| 4969 | // | ||
| 4970 | // IF the number of pixels from the top of `elem` to the end of the page's content is less | ||
| 4971 | // than the height of the viewport, then `elem.scrollIntoView()` will align the `elem` some | ||
| 4972 | // way down the page. | ||
| 4973 | // | ||
| 4974 | // This is often the case for elements near the bottom of the page. | ||
| 4975 | // | ||
| 4976 | // In such cases we do not need to scroll the whole `offset` up, just the difference between | ||
| 4977 | // the top of the element and the offset, which is enough to align the top of `elem` at the | ||
| 4978 | // desired position. | ||
| 4979 | var elemTop = elem.getBoundingClientRect().top; | ||
| 4980 | $window.scrollBy(0, elemTop - offset); | ||
| 4981 | } | ||
| 4982 | } else { | ||
| 4983 | $window.scrollTo(0, 0); | ||
| 4984 | } | ||
| 4985 | } | ||
| 4986 | |||
| 4987 | function scroll(hash) { | ||
| 4988 | hash = isString(hash) ? hash : $location.hash(); | ||
| 4989 | var elm; | ||
| 4990 | |||
| 4991 | // empty hash, scroll to the top of the page | ||
| 4992 | if (!hash) scrollTo(null); | ||
| 4993 | |||
| 4994 | // element with given id | ||
| 4995 | else if ((elm = document.getElementById(hash))) scrollTo(elm); | ||
| 4996 | |||
| 4997 | // first anchor with given name :-D | ||
| 4998 | else if ((elm = getFirstAnchor(document.getElementsByName(hash)))) scrollTo(elm); | ||
| 4999 | |||
26769 more lines aren’t shown here.
| @@ -786,25 +786,25 @@ $.fn.disable = function() { · 785 unmodified lines | |||
| 786 | 786 | ||
| 787 | $.fn.visible = function() { | 787 | $.fn.visible = function() { |
| 788 | return this.each(function() { | 788 | return this.each(function() { |
| 789 | this.css("visibility", "visible"); | 789 | $(this).css("visibility", "visible"); |
| 790 | }); | 790 | }); |
| 791 | } | 791 | } |
| 792 | 792 | ||
| 793 | $.fn.invisible = function() { | 793 | $.fn.invisible = function() { |
| 794 | return this.each(function() { | 794 | return this.each(function() { |
| 795 | this.css("visibility", "hidden"); | 795 | $(this).css("visibility", "hidden"); |
| 796 | }); | 796 | }); |
| 797 | } | 797 | } |
| 798 | 798 | ||
| 799 | $.fn.readCookie = function(name) { | 799 | $.fn.readCookie = function(name) { |
| 800 | this.val(Cookies.get(name)); | 800 | $(this).val(Cookies.get(name)); |
| 801 | } | 801 | } |
| 802 | 802 | ||
| 803 | $.fn.writeCookie = function(name, expiration) { | 803 | $.fn.writeCookie = function(name, expiration) { |
| 804 | if (expiration) // Date or number of days | 804 | if (expiration) // Date or number of days |
| 805 | Cookies.set(name, this.val(), { expires: expiration }); | 805 | Cookies.set(name, $(this).val(), { expires: expiration }); |
| 806 | else | 806 | else |
| 807 | Cookies.set(name, this.val()); | 807 | Cookies.set(name, $(this).val()); |
| 808 | } | 808 | } |
| 809 | 809 | ||
| 810 | $.fn.removeCookie = function(name) { | 810 | $.fn.removeCookie = function(name) { |
| @@ -0,0 +1,16617 @@ | |||
| 1 | /*! jQuery UI - v1.11.4 - 2016-03-31 | ||
| 2 | * http://jqueryui.com | ||
| 3 | * Includes: core.js, widget.js, mouse.js, position.js, draggable.js, droppable.js, resizable.js, selectable.js, sortable.js, accordion.js, autocomplete.js, button.js, datepicker.js, dialog.js, menu.js, progressbar.js, selectmenu.js, slider.js, spinner.js, tabs.js, tooltip.js, effect.js, effect-blind.js, effect-bounce.js, effect-clip.js, effect-drop.js, effect-explode.js, effect-fade.js, effect-fold.js, effect-highlight.js, effect-puff.js, effect-pulsate.js, effect-scale.js, effect-shake.js, effect-size.js, effect-slide.js, effect-transfer.js | ||
| 4 | * Copyright jQuery Foundation and other contributors; Licensed MIT */ | ||
| 5 | |||
| 6 | (function( factory ) { | ||
| 7 | if ( typeof define === "function" && define.amd ) { | ||
| 8 | |||
| 9 | // AMD. Register as an anonymous module. | ||
| 10 | define([ "jquery" ], factory ); | ||
| 11 | } else { | ||
| 12 | |||
| 13 | // Browser globals | ||
| 14 | factory( jQuery ); | ||
| 15 | } | ||
| 16 | }(function( $ ) { | ||
| 17 | /*! | ||
| 18 | * jQuery UI Core 1.11.4 | ||
| 19 | * http://jqueryui.com | ||
| 20 | * | ||
| 21 | * Copyright jQuery Foundation and other contributors | ||
| 22 | * Released under the MIT license. | ||
| 23 | * http://jquery.org/license | ||
| 24 | * | ||
| 25 | * http://api.jqueryui.com/category/ui-core/ | ||
| 26 | */ | ||
| 27 | |||
| 28 | |||
| 29 | // $.ui might exist from components with no dependencies, e.g., $.ui.position | ||
| 30 | $.ui = $.ui || {}; | ||
| 31 | |||
| 32 | $.extend( $.ui, { | ||
| 33 | version: "1.11.4", | ||
| 34 | |||
| 35 | keyCode: { | ||
| 36 | BACKSPACE: 8, | ||
| 37 | COMMA: 188, | ||
| 38 | DELETE: 46, | ||
| 39 | DOWN: 40, | ||
| 40 | END: 35, | ||
| 41 | ENTER: 13, | ||
| 42 | ESCAPE: 27, | ||
| 43 | HOME: 36, | ||
| 44 | LEFT: 37, | ||
| 45 | PAGE_DOWN: 34, | ||
| 46 | PAGE_UP: 33, | ||
| 47 | PERIOD: 190, | ||
| 48 | RIGHT: 39, | ||
| 49 | SPACE: 32, | ||
| 50 | TAB: 9, | ||
| 51 | UP: 38 | ||
| 52 | } | ||
| 53 | }); | ||
| 54 | |||
| 55 | // plugins | ||
| 56 | $.fn.extend({ | ||
| 57 | scrollParent: function( includeHidden ) { | ||
| 58 | var position = this.css( "position" ), | ||
| 59 | excludeStaticParent = position === "absolute", | ||
| 60 | overflowRegex = includeHidden ? /(auto|scroll|hidden)/ : /(auto|scroll)/, | ||
| 61 | scrollParent = this.parents().filter( function() { | ||
| 62 | var parent = $( this ); | ||
| 63 | if ( excludeStaticParent && parent.css( "position" ) === "static" ) { | ||
| 64 | return false; | ||
| 65 | } | ||
| 66 | return overflowRegex.test( parent.css( "overflow" ) + parent.css( "overflow-y" ) + parent.css( "overflow-x" ) ); | ||
| 67 | }).eq( 0 ); | ||
| 68 | |||
| 69 | return position === "fixed" || !scrollParent.length ? $( this[ 0 ].ownerDocument || document ) : scrollParent; | ||
| 70 | }, | ||
| 71 | |||
| 72 | uniqueId: (function() { | ||
| 73 | var uuid = 0; | ||
| 74 | |||
| 75 | return function() { | ||
| 76 | return this.each(function() { | ||
| 77 | if ( !this.id ) { | ||
| 78 | this.id = "ui-id-" + ( ++uuid ); | ||
| 79 | } | ||
| 80 | }); | ||
| 81 | }; | ||
| 82 | })(), | ||
| 83 | |||
| 84 | removeUniqueId: function() { | ||
| 85 | return this.each(function() { | ||
| 86 | if ( /^ui-id-\d+$/.test( this.id ) ) { | ||
| 87 | $( this ).removeAttr( "id" ); | ||
| 88 | } | ||
| 89 | }); | ||
| 90 | } | ||
| 91 | }); | ||
| 92 | |||
| 93 | // selectors | ||
| 94 | function focusable( element, isTabIndexNotNaN ) { | ||
| 95 | var map, mapName, img, | ||
| 96 | nodeName = element.nodeName.toLowerCase(); | ||
| 97 | if ( "area" === nodeName ) { | ||
| 98 | map = element.parentNode; | ||
| 99 | mapName = map.name; | ||
| 100 | if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) { | ||
| 101 | return false; | ||
| 102 | } | ||
| 103 | img = $( "img[usemap='#" + mapName + "']" )[ 0 ]; | ||
| 104 | return !!img && visible( img ); | ||
| 105 | } | ||
| 106 | return ( /^(input|select|textarea|button|object)$/.test( nodeName ) ? | ||
| 107 | !element.disabled : | ||
| 108 | "a" === nodeName ? | ||
| 109 | element.href || isTabIndexNotNaN : | ||
| 110 | isTabIndexNotNaN) && | ||
| 111 | // the element and all of its ancestors must be visible | ||
| 112 | visible( element ); | ||
| 113 | } | ||
| 114 | |||
| 115 | function visible( element ) { | ||
| 116 | return $.expr.filters.visible( element ) && | ||
| 117 | !$( element ).parents().addBack().filter(function() { | ||
| 118 | return $.css( this, "visibility" ) === "hidden"; | ||
| 119 | }).length; | ||
| 120 | } | ||
| 121 | |||
| 122 | $.extend( $.expr[ ":" ], { | ||
| 123 | data: $.expr.createPseudo ? | ||
| 124 | $.expr.createPseudo(function( dataName ) { | ||
| 125 | return function( elem ) { | ||
| 126 | return !!$.data( elem, dataName ); | ||
| 127 | }; | ||
| 128 | }) : | ||
| 129 | // support: jQuery <1.8 | ||
| 130 | function( elem, i, match ) { | ||
| 131 | return !!$.data( elem, match[ 3 ] ); | ||
| 132 | }, | ||
| 133 | |||
| 134 | focusable: function( element ) { | ||
| 135 | return focusable( element, !isNaN( $.attr( element, "tabindex" ) ) ); | ||
| 136 | }, | ||
| 137 | |||
| 138 | tabbable: function( element ) { | ||
| 139 | var tabIndex = $.attr( element, "tabindex" ), | ||
| 140 | isTabIndexNaN = isNaN( tabIndex ); | ||
| 141 | return ( isTabIndexNaN || tabIndex >= 0 ) && focusable( element, !isTabIndexNaN ); | ||
| 142 | } | ||
| 143 | }); | ||
| 144 | |||
| 145 | // support: jQuery <1.8 | ||
| 146 | if ( !$( "<a>" ).outerWidth( 1 ).jquery ) { | ||
| 147 | $.each( [ "Width", "Height" ], function( i, name ) { | ||
| 148 | var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ], | ||
| 149 | type = name.toLowerCase(), | ||
| 150 | orig = { | ||
| 151 | innerWidth: $.fn.innerWidth, | ||
| 152 | innerHeight: $.fn.innerHeight, | ||
| 153 | outerWidth: $.fn.outerWidth, | ||
| 154 | outerHeight: $.fn.outerHeight | ||
| 155 | }; | ||
| 156 | |||
| 157 | function reduce( elem, size, border, margin ) { | ||
| 158 | $.each( side, function() { | ||
| 159 | size -= parseFloat( $.css( elem, "padding" + this ) ) || 0; | ||
| 160 | if ( border ) { | ||
| 161 | size -= parseFloat( $.css( elem, "border" + this + "Width" ) ) || 0; | ||
| 162 | } | ||
| 163 | if ( margin ) { | ||
| 164 | size -= parseFloat( $.css( elem, "margin" + this ) ) || 0; | ||
| 165 | } | ||
| 166 | }); | ||
| 167 | return size; | ||
| 168 | } | ||
| 169 | |||
| 170 | $.fn[ "inner" + name ] = function( size ) { | ||
| 171 | if ( size === undefined ) { | ||
| 172 | return orig[ "inner" + name ].call( this ); | ||
| 173 | } | ||
| 174 | |||
| 175 | return this.each(function() { | ||
| 176 | $( this ).css( type, reduce( this, size ) + "px" ); | ||
| 177 | }); | ||
| 178 | }; | ||
| 179 | |||
| 180 | $.fn[ "outer" + name] = function( size, margin ) { | ||
| 181 | if ( typeof size !== "number" ) { | ||
| 182 | return orig[ "outer" + name ].call( this, size ); | ||
| 183 | } | ||
| 184 | |||
| 185 | return this.each(function() { | ||
| 186 | $( this).css( type, reduce( this, size, true, margin ) + "px" ); | ||
| 187 | }); | ||
| 188 | }; | ||
| 189 | }); | ||
| 190 | } | ||
| 191 | |||
| 192 | // support: jQuery <1.8 | ||
| 193 | if ( !$.fn.addBack ) { | ||
| 194 | $.fn.addBack = function( selector ) { | ||
| 195 | return this.add( selector == null ? | ||
| 196 | this.prevObject : this.prevObject.filter( selector ) | ||
| 197 | ); | ||
| 198 | }; | ||
| 199 | } | ||
| 200 | |||
| 201 | // support: jQuery 1.6.1, 1.6.2 (http://bugs.jquery.com/ticket/9413) | ||
| 202 | if ( $( "<a>" ).data( "a-b", "a" ).removeData( "a-b" ).data( "a-b" ) ) { | ||
| 203 | $.fn.removeData = (function( removeData ) { | ||
| 204 | return function( key ) { | ||
| 205 | if ( arguments.length ) { | ||
| 206 | return removeData.call( this, $.camelCase( key ) ); | ||
| 207 | } else { | ||
| 208 | return removeData.call( this ); | ||
| 209 | } | ||
| 210 | }; | ||
| 211 | })( $.fn.removeData ); | ||
| 212 | } | ||
| 213 | |||
| 214 | // deprecated | ||
| 215 | $.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() ); | ||
| 216 | |||
| 217 | $.fn.extend({ | ||
| 218 | focus: (function( orig ) { | ||
| 219 | return function( delay, fn ) { | ||
| 220 | return typeof delay === "number" ? | ||
| 221 | this.each(function() { | ||
| 222 | var elem = this; | ||
| 223 | setTimeout(function() { | ||
| 224 | $( elem ).focus(); | ||
| 225 | if ( fn ) { | ||
| 226 | fn.call( elem ); | ||
| 227 | } | ||
| 228 | }, delay ); | ||
| 229 | }) : | ||
| 230 | orig.apply( this, arguments ); | ||
| 231 | }; | ||
| 232 | })( $.fn.focus ), | ||
| 233 | |||
| 234 | disableSelection: (function() { | ||
| 235 | var eventType = "onselectstart" in document.createElement( "div" ) ? | ||
| 236 | "selectstart" : | ||
| 237 | "mousedown"; | ||
| 238 | |||
| 239 | return function() { | ||
| 240 | return this.bind( eventType + ".ui-disableSelection", function( event ) { | ||
| 241 | event.preventDefault(); | ||
| 242 | }); | ||
| 243 | }; | ||
| 244 | })(), | ||
| 245 | |||
| 246 | enableSelection: function() { | ||
| 247 | return this.unbind( ".ui-disableSelection" ); | ||
| 248 | }, | ||
| 249 | |||
| 250 | zIndex: function( zIndex ) { | ||
| 251 | if ( zIndex !== undefined ) { | ||
| 252 | return this.css( "zIndex", zIndex ); | ||
| 253 | } | ||
| 254 | |||
| 255 | if ( this.length ) { | ||
| 256 | var elem = $( this[ 0 ] ), position, value; | ||
| 257 | while ( elem.length && elem[ 0 ] !== document ) { | ||
| 258 | // Ignore z-index if position is set to a value where z-index is ignored by the browser | ||
| 259 | // This makes behavior of this function consistent across browsers | ||
| 260 | // WebKit always returns auto if the element is positioned | ||
| 261 | position = elem.css( "position" ); | ||
| 262 | if ( position === "absolute" || position === "relative" || position === "fixed" ) { | ||
| 263 | // IE returns 0 when zIndex is not specified | ||
| 264 | // other browsers return a string | ||
| 265 | // we ignore the case of nested elements with an explicit value of 0 | ||
| 266 | // <div style="z-index: -10;"><div style="z-index: 0;"></div></div> | ||
| 267 | value = parseInt( elem.css( "zIndex" ), 10 ); | ||
| 268 | if ( !isNaN( value ) && value !== 0 ) { | ||
| 269 | return value; | ||
| 270 | } | ||
| 271 | } | ||
| 272 | elem = elem.parent(); | ||
| 273 | } | ||
| 274 | } | ||
| 275 | |||
| 276 | return 0; | ||
| 277 | } | ||
| 278 | }); | ||
| 279 | |||
| 280 | // $.ui.plugin is deprecated. Use $.widget() extensions instead. | ||
| 281 | $.ui.plugin = { | ||
| 282 | add: function( module, option, set ) { | ||
| 283 | var i, | ||
| 284 | proto = $.ui[ module ].prototype; | ||
| 285 | for ( i in set ) { | ||
| 286 | proto.plugins[ i ] = proto.plugins[ i ] || []; | ||
| 287 | proto.plugins[ i ].push( [ option, set[ i ] ] ); | ||
| 288 | } | ||
| 289 | }, | ||
| 290 | call: function( instance, name, args, allowDisconnected ) { | ||
| 291 | var i, | ||
| 292 | set = instance.plugins[ name ]; | ||
| 293 | |||
| 294 | if ( !set ) { | ||
| 295 | return; | ||
| 296 | } | ||
| 297 | |||
| 298 | if ( !allowDisconnected && ( !instance.element[ 0 ].parentNode || instance.element[ 0 ].parentNode.nodeType === 11 ) ) { | ||
| 299 | return; | ||
| 300 | } | ||
| 301 | |||
| 302 | for ( i = 0; i < set.length; i++ ) { | ||
| 303 | if ( instance.options[ set[ i ][ 0 ] ] ) { | ||
| 304 | set[ i ][ 1 ].apply( instance.element, args ); | ||
| 305 | } | ||
| 306 | } | ||
| 307 | } | ||
| 308 | }; | ||
| 309 | |||
| 310 | |||
| 311 | /*! | ||
| 312 | * jQuery UI Widget 1.11.4 | ||
| 313 | * http://jqueryui.com | ||
| 314 | * | ||
| 315 | * Copyright jQuery Foundation and other contributors | ||
| 316 | * Released under the MIT license. | ||
| 317 | * http://jquery.org/license | ||
| 318 | * | ||
| 319 | * http://api.jqueryui.com/jQuery.widget/ | ||
| 320 | */ | ||
| 321 | |||
| 322 | |||
| 323 | var widget_uuid = 0, | ||
| 324 | widget_slice = Array.prototype.slice; | ||
| 325 | |||
| 326 | $.cleanData = (function( orig ) { | ||
| 327 | return function( elems ) { | ||
| 328 | var events, elem, i; | ||
| 329 | for ( i = 0; (elem = elems[i]) != null; i++ ) { | ||
| 330 | try { | ||
| 331 | |||
| 332 | // Only trigger remove when necessary to save time | ||
| 333 | events = $._data( elem, "events" ); | ||
| 334 | if ( events && events.remove ) { | ||
| 335 | $( elem ).triggerHandler( "remove" ); | ||
| 336 | } | ||
| 337 | |||
| 338 | // http://bugs.jquery.com/ticket/8235 | ||
| 339 | } catch ( e ) {} | ||
| 340 | } | ||
| 341 | orig( elems ); | ||
| 342 | }; | ||
| 343 | })( $.cleanData ); | ||
| 344 | |||
| 345 | $.widget = function( name, base, prototype ) { | ||
| 346 | var fullName, existingConstructor, constructor, basePrototype, | ||
| 347 | // proxiedPrototype allows the provided prototype to remain unmodified | ||
| 348 | // so that it can be used as a mixin for multiple widgets (#8876) | ||
| 349 | proxiedPrototype = {}, | ||
| 350 | namespace = name.split( "." )[ 0 ]; | ||
| 351 | |||
| 352 | name = name.split( "." )[ 1 ]; | ||
| 353 | fullName = namespace + "-" + name; | ||
| 354 | |||
| 355 | if ( !prototype ) { | ||
| 356 | prototype = base; | ||
| 357 | base = $.Widget; | ||
| 358 | } | ||
| 359 | |||
| 360 | // create selector for plugin | ||
| 361 | $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) { | ||
| 362 | return !!$.data( elem, fullName ); | ||
| 363 | }; | ||
| 364 | |||
| 365 | $[ namespace ] = $[ namespace ] || {}; | ||
| 366 | existingConstructor = $[ namespace ][ name ]; | ||
| 367 | constructor = $[ namespace ][ name ] = function( options, element ) { | ||
| 368 | // allow instantiation without "new" keyword | ||
| 369 | if ( !this._createWidget ) { | ||
| 370 | return new constructor( options, element ); | ||
| 371 | } | ||
| 372 | |||
| 373 | // allow instantiation without initializing for simple inheritance | ||
| 374 | // must use "new" keyword (the code above always passes args) | ||
| 375 | if ( arguments.length ) { | ||
| 376 | this._createWidget( options, element ); | ||
| 377 | } | ||
| 378 | }; | ||
| 379 | // extend with the existing constructor to carry over any static properties | ||
| 380 | $.extend( constructor, existingConstructor, { | ||
| 381 | version: prototype.version, | ||
| 382 | // copy the object used to create the prototype in case we need to | ||
| 383 | // redefine the widget later | ||
| 384 | _proto: $.extend( {}, prototype ), | ||
| 385 | // track widgets that inherit from this widget in case this widget is | ||
| 386 | // redefined after a widget inherits from it | ||
| 387 | _childConstructors: [] | ||
| 388 | }); | ||
| 389 | |||
| 390 | basePrototype = new base(); | ||
| 391 | // we need to make the options hash a property directly on the new instance | ||
| 392 | // otherwise we'll modify the options hash on the prototype that we're | ||
| 393 | // inheriting from | ||
| 394 | basePrototype.options = $.widget.extend( {}, basePrototype.options ); | ||
| 395 | $.each( prototype, function( prop, value ) { | ||
| 396 | if ( !$.isFunction( value ) ) { | ||
| 397 | proxiedPrototype[ prop ] = value; | ||
| 398 | return; | ||
| 399 | } | ||
| 400 | proxiedPrototype[ prop ] = (function() { | ||
| 401 | var _super = function() { | ||
| 402 | return base.prototype[ prop ].apply( this, arguments ); | ||
| 403 | }, | ||
| 404 | _superApply = function( args ) { | ||
| 405 | return base.prototype[ prop ].apply( this, args ); | ||
| 406 | }; | ||
| 407 | return function() { | ||
| 408 | var __super = this._super, | ||
| 409 | __superApply = this._superApply, | ||
| 410 | returnValue; | ||
| 411 | |||
| 412 | this._super = _super; | ||
| 413 | this._superApply = _superApply; | ||
| 414 | |||
| 415 | returnValue = value.apply( this, arguments ); | ||
| 416 | |||
| 417 | this._super = __super; | ||
| 418 | this._superApply = __superApply; | ||
| 419 | |||
| 420 | return returnValue; | ||
| 421 | }; | ||
| 422 | })(); | ||
| 423 | }); | ||
| 424 | constructor.prototype = $.widget.extend( basePrototype, { | ||
| 425 | // TODO: remove support for widgetEventPrefix | ||
| 426 | // always use the name + a colon as the prefix, e.g., draggable:start | ||
| 427 | // don't prefix for widgets that aren't DOM-based | ||
| 428 | widgetEventPrefix: existingConstructor ? (basePrototype.widgetEventPrefix || name) : name | ||
| 429 | }, proxiedPrototype, { | ||
| 430 | constructor: constructor, | ||
| 431 | namespace: namespace, | ||
| 432 | widgetName: name, | ||
| 433 | widgetFullName: fullName | ||
| 434 | }); | ||
| 435 | |||
| 436 | // If this widget is being redefined then we need to find all widgets that | ||
| 437 | // are inheriting from it and redefine all of them so that they inherit from | ||
| 438 | // the new version of this widget. We're essentially trying to replace one | ||
| 439 | // level in the prototype chain. | ||
| 440 | if ( existingConstructor ) { | ||
| 441 | $.each( existingConstructor._childConstructors, function( i, child ) { | ||
| 442 | var childPrototype = child.prototype; | ||
| 443 | |||
| 444 | // redefine the child widget using the same prototype that was | ||
| 445 | // originally used, but inherit from the new version of the base | ||
| 446 | $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto ); | ||
| 447 | }); | ||
| 448 | // remove the list of existing child constructors from the old constructor | ||
| 449 | // so the old child constructors can be garbage collected | ||
| 450 | delete existingConstructor._childConstructors; | ||
| 451 | } else { | ||
| 452 | base._childConstructors.push( constructor ); | ||
| 453 | } | ||
| 454 | |||
| 455 | $.widget.bridge( name, constructor ); | ||
| 456 | |||
| 457 | return constructor; | ||
| 458 | }; | ||
| 459 | |||
| 460 | $.widget.extend = function( target ) { | ||
| 461 | var input = widget_slice.call( arguments, 1 ), | ||
| 462 | inputIndex = 0, | ||
| 463 | inputLength = input.length, | ||
| 464 | key, | ||
| 465 | value; | ||
| 466 | for ( ; inputIndex < inputLength; inputIndex++ ) { | ||
| 467 | for ( key in input[ inputIndex ] ) { | ||
| 468 | value = input[ inputIndex ][ key ]; | ||
| 469 | if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) { | ||
| 470 | // Clone objects | ||
| 471 | if ( $.isPlainObject( value ) ) { | ||
| 472 | target[ key ] = $.isPlainObject( target[ key ] ) ? | ||
| 473 | $.widget.extend( {}, target[ key ], value ) : | ||
| 474 | // Don't extend strings, arrays, etc. with objects | ||
| 475 | $.widget.extend( {}, value ); | ||
| 476 | // Copy everything else by reference | ||
| 477 | } else { | ||
| 478 | target[ key ] = value; | ||
| 479 | } | ||
| 480 | } | ||
| 481 | } | ||
| 482 | } | ||
| 483 | return target; | ||
| 484 | }; | ||
| 485 | |||
| 486 | $.widget.bridge = function( name, object ) { | ||
| 487 | var fullName = object.prototype.widgetFullName || name; | ||
| 488 | $.fn[ name ] = function( options ) { | ||
| 489 | var isMethodCall = typeof options === "string", | ||
| 490 | args = widget_slice.call( arguments, 1 ), | ||
| 491 | returnValue = this; | ||
| 492 | |||
| 493 | if ( isMethodCall ) { | ||
| 494 | this.each(function() { | ||
| 495 | var methodValue, | ||
| 496 | instance = $.data( this, fullName ); | ||
| 497 | if ( options === "instance" ) { | ||
| 498 | returnValue = instance; | ||
| 499 | return false; | ||
| 500 | } | ||
| 501 | if ( !instance ) { | ||
| 502 | return $.error( "cannot call methods on " + name + " prior to initialization; " + | ||
| 503 | "attempted to call method '" + options + "'" ); | ||
| 504 | } | ||
| 505 | if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) { | ||
| 506 | return $.error( "no such method '" + options + "' for " + name + " widget instance" ); | ||
| 507 | } | ||
| 508 | methodValue = instance[ options ].apply( instance, args ); | ||
| 509 | if ( methodValue !== instance && methodValue !== undefined ) { | ||
| 510 | returnValue = methodValue && methodValue.jquery ? | ||
| 511 | returnValue.pushStack( methodValue.get() ) : | ||
| 512 | methodValue; | ||
| 513 | return false; | ||
| 514 | } | ||
| 515 | }); | ||
| 516 | } else { | ||
| 517 | |||
| 518 | // Allow multiple hashes to be passed on init | ||
| 519 | if ( args.length ) { | ||
| 520 | options = $.widget.extend.apply( null, [ options ].concat(args) ); | ||
| 521 | } | ||
| 522 | |||
| 523 | this.each(function() { | ||
| 524 | var instance = $.data( this, fullName ); | ||
| 525 | if ( instance ) { | ||
| 526 | instance.option( options || {} ); | ||
| 527 | if ( instance._init ) { | ||
| 528 | instance._init(); | ||
| 529 | } | ||
| 530 | } else { | ||
| 531 | $.data( this, fullName, new object( options, this ) ); | ||
| 532 | } | ||
| 533 | }); | ||
| 534 | } | ||
| 535 | |||
| 536 | return returnValue; | ||
| 537 | }; | ||
| 538 | }; | ||
| 539 | |||
| 540 | $.Widget = function( /* options, element */ ) {}; | ||
| 541 | $.Widget._childConstructors = []; | ||
| 542 | |||
| 543 | $.Widget.prototype = { | ||
| 544 | widgetName: "widget", | ||
| 545 | widgetEventPrefix: "", | ||
| 546 | defaultElement: "<div>", | ||
| 547 | options: { | ||
| 548 | disabled: false, | ||
| 549 | |||
| 550 | // callbacks | ||
| 551 | create: null | ||
| 552 | }, | ||
| 553 | _createWidget: function( options, element ) { | ||
| 554 | element = $( element || this.defaultElement || this )[ 0 ]; | ||
| 555 | this.element = $( element ); | ||
| 556 | this.uuid = widget_uuid++; | ||
| 557 | this.eventNamespace = "." + this.widgetName + this.uuid; | ||
| 558 | |||
| 559 | this.bindings = $(); | ||
| 560 | this.hoverable = $(); | ||
| 561 | this.focusable = $(); | ||
| 562 | |||
| 563 | if ( element !== this ) { | ||
| 564 | $.data( element, this.widgetFullName, this ); | ||
| 565 | this._on( true, this.element, { | ||
| 566 | remove: function( event ) { | ||
| 567 | if ( event.target === element ) { | ||
| 568 | this.destroy(); | ||
| 569 | } | ||
| 570 | } | ||
| 571 | }); | ||
| 572 | this.document = $( element.style ? | ||
| 573 | // element within the document | ||
| 574 | element.ownerDocument : | ||
| 575 | // element is window or document | ||
| 576 | element.document || element ); | ||
| 577 | this.window = $( this.document[0].defaultView || this.document[0].parentWindow ); | ||
| 578 | } | ||
| 579 | |||
| 580 | this.options = $.widget.extend( {}, | ||
| 581 | this.options, | ||
| 582 | this._getCreateOptions(), | ||
| 583 | options ); | ||
| 584 | |||
| 585 | this._create(); | ||
| 586 | this._trigger( "create", null, this._getCreateEventData() ); | ||
| 587 | this._init(); | ||
| 588 | }, | ||
| 589 | _getCreateOptions: $.noop, | ||
| 590 | _getCreateEventData: $.noop, | ||
| 591 | _create: $.noop, | ||
| 592 | _init: $.noop, | ||
| 593 | |||
| 594 | destroy: function() { | ||
| 595 | this._destroy(); | ||
| 596 | // we can probably remove the unbind calls in 2.0 | ||
| 597 | // all event bindings should go through this._on() | ||
| 598 | this.element | ||
| 599 | .unbind( this.eventNamespace ) | ||
| 600 | .removeData( this.widgetFullName ) | ||
| 601 | // support: jquery <1.6.3 | ||
| 602 | // http://bugs.jquery.com/ticket/9413 | ||
| 603 | .removeData( $.camelCase( this.widgetFullName ) ); | ||
| 604 | this.widget() | ||
| 605 | .unbind( this.eventNamespace ) | ||
| 606 | .removeAttr( "aria-disabled" ) | ||
| 607 | .removeClass( | ||
| 608 | this.widgetFullName + "-disabled " + | ||
| 609 | "ui-state-disabled" ); | ||
| 610 | |||
| 611 | // clean up events and states | ||
| 612 | this.bindings.unbind( this.eventNamespace ); | ||
| 613 | this.hoverable.removeClass( "ui-state-hover" ); | ||
| 614 | this.focusable.removeClass( "ui-state-focus" ); | ||
| 615 | }, | ||
| 616 | _destroy: $.noop, | ||
| 617 | |||
| 618 | widget: function() { | ||
| 619 | return this.element; | ||
| 620 | }, | ||
| 621 | |||
| 622 | option: function( key, value ) { | ||
| 623 | var options = key, | ||
| 624 | parts, | ||
| 625 | curOption, | ||
| 626 | i; | ||
| 627 | |||
| 628 | if ( arguments.length === 0 ) { | ||
| 629 | // don't return a reference to the internal hash | ||
| 630 | return $.widget.extend( {}, this.options ); | ||
| 631 | } | ||
| 632 | |||
| 633 | if ( typeof key === "string" ) { | ||
| 634 | // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } } | ||
| 635 | options = {}; | ||
| 636 | parts = key.split( "." ); | ||
| 637 | key = parts.shift(); | ||
| 638 | if ( parts.length ) { | ||
| 639 | curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] ); | ||
| 640 | for ( i = 0; i < parts.length - 1; i++ ) { | ||
| 641 | curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {}; | ||
| 642 | curOption = curOption[ parts[ i ] ]; | ||
| 643 | } | ||
| 644 | key = parts.pop(); | ||
| 645 | if ( arguments.length === 1 ) { | ||
| 646 | return curOption[ key ] === undefined ? null : curOption[ key ]; | ||
| 647 | } | ||
| 648 | curOption[ key ] = value; | ||
| 649 | } else { | ||
| 650 | if ( arguments.length === 1 ) { | ||
| 651 | return this.options[ key ] === undefined ? null : this.options[ key ]; | ||
| 652 | } | ||
| 653 | options[ key ] = value; | ||
| 654 | } | ||
| 655 | } | ||
| 656 | |||
| 657 | this._setOptions( options ); | ||
| 658 | |||
| 659 | return this; | ||
| 660 | }, | ||
| 661 | _setOptions: function( options ) { | ||
| 662 | var key; | ||
| 663 | |||
| 664 | for ( key in options ) { | ||
| 665 | this._setOption( key, options[ key ] ); | ||
| 666 | } | ||
| 667 | |||
| 668 | return this; | ||
| 669 | }, | ||
| 670 | _setOption: function( key, value ) { | ||
| 671 | this.options[ key ] = value; | ||
| 672 | |||
| 673 | if ( key === "disabled" ) { | ||
| 674 | this.widget() | ||
| 675 | .toggleClass( this.widgetFullName + "-disabled", !!value ); | ||
| 676 | |||
| 677 | // If the widget is becoming disabled, then nothing is interactive | ||
| 678 | if ( value ) { | ||
| 679 | this.hoverable.removeClass( "ui-state-hover" ); | ||
| 680 | this.focusable.removeClass( "ui-state-focus" ); | ||
| 681 | } | ||
| 682 | } | ||
| 683 | |||
| 684 | return this; | ||
| 685 | }, | ||
| 686 | |||
| 687 | enable: function() { | ||
| 688 | return this._setOptions({ disabled: false }); | ||
| 689 | }, | ||
| 690 | disable: function() { | ||
| 691 | return this._setOptions({ disabled: true }); | ||
| 692 | }, | ||
| 693 | |||
| 694 | _on: function( suppressDisabledCheck, element, handlers ) { | ||
| 695 | var delegateElement, | ||
| 696 | instance = this; | ||
| 697 | |||
| 698 | // no suppressDisabledCheck flag, shuffle arguments | ||
| 699 | if ( typeof suppressDisabledCheck !== "boolean" ) { | ||
| 700 | handlers = element; | ||
| 701 | element = suppressDisabledCheck; | ||
| 702 | suppressDisabledCheck = false; | ||
| 703 | } | ||
| 704 | |||
| 705 | // no element argument, shuffle and use this.element | ||
| 706 | if ( !handlers ) { | ||
| 707 | handlers = element; | ||
| 708 | element = this.element; | ||
| 709 | delegateElement = this.widget(); | ||
| 710 | } else { | ||
| 711 | element = delegateElement = $( element ); | ||
| 712 | this.bindings = this.bindings.add( element ); | ||
| 713 | } | ||
| 714 | |||
| 715 | $.each( handlers, function( event, handler ) { | ||
| 716 | function handlerProxy() { | ||
| 717 | // allow widgets to customize the disabled handling | ||
| 718 | // - disabled as an array instead of boolean | ||
| 719 | // - disabled class as method for disabling individual parts | ||
| 720 | if ( !suppressDisabledCheck && | ||
| 721 | ( instance.options.disabled === true || | ||
| 722 | $( this ).hasClass( "ui-state-disabled" ) ) ) { | ||
| 723 | return; | ||
| 724 | } | ||
| 725 | return ( typeof handler === "string" ? instance[ handler ] : handler ) | ||
| 726 | .apply( instance, arguments ); | ||
| 727 | } | ||
| 728 | |||
| 729 | // copy the guid so direct unbinding works | ||
| 730 | if ( typeof handler !== "string" ) { | ||
| 731 | handlerProxy.guid = handler.guid = | ||
| 732 | handler.guid || handlerProxy.guid || $.guid++; | ||
| 733 | } | ||
| 734 | |||
| 735 | var match = event.match( /^([\w:-]*)\s*(.*)$/ ), | ||
| 736 | eventName = match[1] + instance.eventNamespace, | ||
| 737 | selector = match[2]; | ||
| 738 | if ( selector ) { | ||
| 739 | delegateElement.delegate( selector, eventName, handlerProxy ); | ||
| 740 | } else { | ||
| 741 | element.bind( eventName, handlerProxy ); | ||
| 742 | } | ||
| 743 | }); | ||
| 744 | }, | ||
| 745 | |||
| 746 | _off: function( element, eventName ) { | ||
| 747 | eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) + | ||
| 748 | this.eventNamespace; | ||
| 749 | element.unbind( eventName ).undelegate( eventName ); | ||
| 750 | |||
| 751 | // Clear the stack to avoid memory leaks (#10056) | ||
| 752 | this.bindings = $( this.bindings.not( element ).get() ); | ||
| 753 | this.focusable = $( this.focusable.not( element ).get() ); | ||
| 754 | this.hoverable = $( this.hoverable.not( element ).get() ); | ||
| 755 | }, | ||
| 756 | |||
| 757 | _delay: function( handler, delay ) { | ||
| 758 | function handlerProxy() { | ||
| 759 | return ( typeof handler === "string" ? instance[ handler ] : handler ) | ||
| 760 | .apply( instance, arguments ); | ||
| 761 | } | ||
| 762 | var instance = this; | ||
| 763 | return setTimeout( handlerProxy, delay || 0 ); | ||
| 764 | }, | ||
| 765 | |||
| 766 | _hoverable: function( element ) { | ||
| 767 | this.hoverable = this.hoverable.add( element ); | ||
| 768 | this._on( element, { | ||
| 769 | mouseenter: function( event ) { | ||
| 770 | $( event.currentTarget ).addClass( "ui-state-hover" ); | ||
| 771 | }, | ||
| 772 | mouseleave: function( event ) { | ||
| 773 | $( event.currentTarget ).removeClass( "ui-state-hover" ); | ||
| 774 | } | ||
| 775 | }); | ||
| 776 | }, | ||
| 777 | |||
| 778 | _focusable: function( element ) { | ||
| 779 | this.focusable = this.focusable.add( element ); | ||
| 780 | this._on( element, { | ||
| 781 | focusin: function( event ) { | ||
| 782 | $( event.currentTarget ).addClass( "ui-state-focus" ); | ||
| 783 | }, | ||
| 784 | focusout: function( event ) { | ||
| 785 | $( event.currentTarget ).removeClass( "ui-state-focus" ); | ||
| 786 | } | ||
| 787 | }); | ||
| 788 | }, | ||
| 789 | |||
| 790 | _trigger: function( type, event, data ) { | ||
| 791 | var prop, orig, | ||
| 792 | callback = this.options[ type ]; | ||
| 793 | |||
| 794 | data = data || {}; | ||
| 795 | event = $.Event( event ); | ||
| 796 | event.type = ( type === this.widgetEventPrefix ? | ||
| 797 | type : | ||
| 798 | this.widgetEventPrefix + type ).toLowerCase(); | ||
| 799 | // the original event may come from any element | ||
| 800 | // so we need to reset the target on the new event | ||
| 801 | event.target = this.element[ 0 ]; | ||
| 802 | |||
| 803 | // copy original event properties over to the new event | ||
| 804 | orig = event.originalEvent; | ||
| 805 | if ( orig ) { | ||
| 806 | for ( prop in orig ) { | ||
| 807 | if ( !( prop in event ) ) { | ||
| 808 | event[ prop ] = orig[ prop ]; | ||
| 809 | } | ||
| 810 | } | ||
| 811 | } | ||
| 812 | |||
| 813 | this.element.trigger( event, data ); | ||
| 814 | return !( $.isFunction( callback ) && | ||
| 815 | callback.apply( this.element[0], [ event ].concat( data ) ) === false || | ||
| 816 | event.isDefaultPrevented() ); | ||
| 817 | } | ||
| 818 | }; | ||
| 819 | |||
| 820 | $.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) { | ||
| 821 | $.Widget.prototype[ "_" + method ] = function( element, options, callback ) { | ||
| 822 | if ( typeof options === "string" ) { | ||
| 823 | options = { effect: options }; | ||
| 824 | } | ||
| 825 | var hasOptions, | ||
| 826 | effectName = !options ? | ||
| 827 | method : | ||
| 828 | options === true || typeof options === "number" ? | ||
| 829 | defaultEffect : | ||
| 830 | options.effect || defaultEffect; | ||
| 831 | options = options || {}; | ||
| 832 | if ( typeof options === "number" ) { | ||
| 833 | options = { duration: options }; | ||
| 834 | } | ||
| 835 | hasOptions = !$.isEmptyObject( options ); | ||
| 836 | options.complete = callback; | ||
| 837 | if ( options.delay ) { | ||
| 838 | element.delay( options.delay ); | ||
| 839 | } | ||
| 840 | if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) { | ||
| 841 | element[ method ]( options ); | ||
| 842 | } else if ( effectName !== method && element[ effectName ] ) { | ||
| 843 | element[ effectName ]( options.duration, options.easing, callback ); | ||
| 844 | } else { | ||
| 845 | element.queue(function( next ) { | ||
| 846 | $( this )[ method ](); | ||
| 847 | if ( callback ) { | ||
| 848 | callback.call( element[ 0 ] ); | ||
| 849 | } | ||
| 850 | next(); | ||
| 851 | }); | ||
| 852 | } | ||
| 853 | }; | ||
| 854 | }); | ||
| 855 | |||
| 856 | var widget = $.widget; | ||
| 857 | |||
| 858 | |||
| 859 | /*! | ||
| 860 | * jQuery UI Mouse 1.11.4 | ||
| 861 | * http://jqueryui.com | ||
| 862 | * | ||
| 863 | * Copyright jQuery Foundation and other contributors | ||
| 864 | * Released under the MIT license. | ||
| 865 | * http://jquery.org/license | ||
| 866 | * | ||
| 867 | * http://api.jqueryui.com/mouse/ | ||
| 868 | */ | ||
| 869 | |||
| 870 | |||
| 871 | var mouseHandled = false; | ||
| 872 | $( document ).mouseup( function() { | ||
| 873 | mouseHandled = false; | ||
| 874 | }); | ||
| 875 | |||
| 876 | var mouse = $.widget("ui.mouse", { | ||
| 877 | version: "1.11.4", | ||
| 878 | options: { | ||
| 879 | cancel: "input,textarea,button,select,option", | ||
| 880 | distance: 1, | ||
| 881 | delay: 0 | ||
| 882 | }, | ||
| 883 | _mouseInit: function() { | ||
| 884 | var that = this; | ||
| 885 | |||
| 886 | this.element | ||
| 887 | .bind("mousedown." + this.widgetName, function(event) { | ||
| 888 | return that._mouseDown(event); | ||
| 889 | }) | ||
| 890 | .bind("click." + this.widgetName, function(event) { | ||
| 891 | if (true === $.data(event.target, that.widgetName + ".preventClickEvent")) { | ||
| 892 | $.removeData(event.target, that.widgetName + ".preventClickEvent"); | ||
| 893 | event.stopImmediatePropagation(); | ||
| 894 | return false; | ||
| 895 | } | ||
| 896 | }); | ||
| 897 | |||
| 898 | this.started = false; | ||
| 899 | }, | ||
| 900 | |||
| 901 | // TODO: make sure destroying one instance of mouse doesn't mess with | ||
| 902 | // other instances of mouse | ||
| 903 | _mouseDestroy: function() { | ||
| 904 | this.element.unbind("." + this.widgetName); | ||
| 905 | if ( this._mouseMoveDelegate ) { | ||
| 906 | this.document | ||
| 907 | .unbind("mousemove." + this.widgetName, this._mouseMoveDelegate) | ||
| 908 | .unbind("mouseup." + this.widgetName, this._mouseUpDelegate); | ||
| 909 | } | ||
| 910 | }, | ||
| 911 | |||
| 912 | _mouseDown: function(event) { | ||
| 913 | // don't let more than one widget handle mouseStart | ||
| 914 | if ( mouseHandled ) { | ||
| 915 | return; | ||
| 916 | } | ||
| 917 | |||
| 918 | this._mouseMoved = false; | ||
| 919 | |||
| 920 | // we may have missed mouseup (out of window) | ||
| 921 | (this._mouseStarted && this._mouseUp(event)); | ||
| 922 | |||
| 923 | this._mouseDownEvent = event; | ||
| 924 | |||
| 925 | var that = this, | ||
| 926 | btnIsLeft = (event.which === 1), | ||
| 927 | // event.target.nodeName works around a bug in IE 8 with | ||
| 928 | // disabled inputs (#7620) | ||
| 929 | elIsCancel = (typeof this.options.cancel === "string" && event.target.nodeName ? $(event.target).closest(this.options.cancel).length : false); | ||
| 930 | if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) { | ||
| 931 | return true; | ||
| 932 | } | ||
| 933 | |||
| 934 | this.mouseDelayMet = !this.options.delay; | ||
| 935 | if (!this.mouseDelayMet) { | ||
| 936 | this._mouseDelayTimer = setTimeout(function() { | ||
| 937 | that.mouseDelayMet = true; | ||
| 938 | }, this.options.delay); | ||
| 939 | } | ||
| 940 | |||
| 941 | if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) { | ||
| 942 | this._mouseStarted = (this._mouseStart(event) !== false); | ||
| 943 | if (!this._mouseStarted) { | ||
| 944 | event.preventDefault(); | ||
| 945 | return true; | ||
| 946 | } | ||
| 947 | } | ||
| 948 | |||
| 949 | // Click event may never have fired (Gecko & Opera) | ||
| 950 | if (true === $.data(event.target, this.widgetName + ".preventClickEvent")) { | ||
| 951 | $.removeData(event.target, this.widgetName + ".preventClickEvent"); | ||
| 952 | } | ||
| 953 | |||
| 954 | // these delegates are required to keep context | ||
| 955 | this._mouseMoveDelegate = function(event) { | ||
| 956 | return that._mouseMove(event); | ||
| 957 | }; | ||
| 958 | this._mouseUpDelegate = function(event) { | ||
| 959 | return that._mouseUp(event); | ||
| 960 | }; | ||
| 961 | |||
| 962 | this.document | ||
| 963 | .bind( "mousemove." + this.widgetName, this._mouseMoveDelegate ) | ||
| 964 | .bind( "mouseup." + this.widgetName, this._mouseUpDelegate ); | ||
| 965 | |||
| 966 | event.preventDefault(); | ||
| 967 | |||
| 968 | mouseHandled = true; | ||
| 969 | return true; | ||
| 970 | }, | ||
| 971 | |||
| 972 | _mouseMove: function(event) { | ||
| 973 | // Only check for mouseups outside the document if you've moved inside the document | ||
| 974 | // at least once. This prevents the firing of mouseup in the case of IE<9, which will | ||
| 975 | // fire a mousemove event if content is placed under the cursor. See #7778 | ||
| 976 | // Support: IE <9 | ||
| 977 | if ( this._mouseMoved ) { | ||
| 978 | // IE mouseup check - mouseup happened when mouse was out of window | ||
| 979 | if ($.ui.ie && ( !document.documentMode || document.documentMode < 9 ) && !event.button) { | ||
| 980 | return this._mouseUp(event); | ||
| 981 | |||
| 982 | // Iframe mouseup check - mouseup occurred in another document | ||
| 983 | } else if ( !event.which ) { | ||
| 984 | return this._mouseUp( event ); | ||
| 985 | } | ||
| 986 | } | ||
| 987 | |||
| 988 | if ( event.which || event.button ) { | ||
| 989 | this._mouseMoved = true; | ||
| 990 | } | ||
| 991 | |||
| 992 | if (this._mouseStarted) { | ||
| 993 | this._mouseDrag(event); | ||
| 994 | return event.preventDefault(); | ||
| 995 | } | ||
| 996 | |||
| 997 | if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) { | ||
| 998 | this._mouseStarted = | ||
| 999 | (this._mouseStart(this._mouseDownEvent, event) !== false); | ||
| 1000 | (this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event)); | ||
| 1001 | } | ||
| 1002 | |||
| 1003 | return !this._mouseStarted; | ||
| 1004 | }, | ||
| 1005 | |||
| 1006 | _mouseUp: function(event) { | ||
| 1007 | this.document | ||
| 1008 | .unbind( "mousemove." + this.widgetName, this._mouseMoveDelegate ) | ||
| 1009 | .unbind( "mouseup." + this.widgetName, this._mouseUpDelegate ); | ||
| 1010 | |||
| 1011 | if (this._mouseStarted) { | ||
| 1012 | this._mouseStarted = false; | ||
| 1013 | |||
| 1014 | if (event.target === this._mouseDownEvent.target) { | ||
| 1015 | $.data(event.target, this.widgetName + ".preventClickEvent", true); | ||
| 1016 | } | ||
| 1017 | |||
| 1018 | this._mouseStop(event); | ||
| 1019 | } | ||
| 1020 | |||
| 1021 | mouseHandled = false; | ||
| 1022 | return false; | ||
| 1023 | }, | ||
| 1024 | |||
| 1025 | _mouseDistanceMet: function(event) { | ||
| 1026 | return (Math.max( | ||
| 1027 | Math.abs(this._mouseDownEvent.pageX - event.pageX), | ||
| 1028 | Math.abs(this._mouseDownEvent.pageY - event.pageY) | ||
| 1029 | ) >= this.options.distance | ||
| 1030 | ); | ||
| 1031 | }, | ||
| 1032 | |||
| 1033 | _mouseDelayMet: function(/* event */) { | ||
| 1034 | return this.mouseDelayMet; | ||
| 1035 | }, | ||
| 1036 | |||
| 1037 | // These are placeholder methods, to be overriden by extending plugin | ||
| 1038 | _mouseStart: function(/* event */) {}, | ||
| 1039 | _mouseDrag: function(/* event */) {}, | ||
| 1040 | _mouseStop: function(/* event */) {}, | ||
| 1041 | _mouseCapture: function(/* event */) { return true; } | ||
| 1042 | }); | ||
| 1043 | |||
| 1044 | |||
| 1045 | /*! | ||
| 1046 | * jQuery UI Position 1.11.4 | ||
| 1047 | * http://jqueryui.com | ||
| 1048 | * | ||
| 1049 | * Copyright jQuery Foundation and other contributors | ||
| 1050 | * Released under the MIT license. | ||
| 1051 | * http://jquery.org/license | ||
| 1052 | * | ||
| 1053 | * http://api.jqueryui.com/position/ | ||
| 1054 | */ | ||
| 1055 | |||
| 1056 | (function() { | ||
| 1057 | |||
| 1058 | $.ui = $.ui || {}; | ||
| 1059 | |||
| 1060 | var cachedScrollbarWidth, supportsOffsetFractions, | ||
| 1061 | max = Math.max, | ||
| 1062 | abs = Math.abs, | ||
| 1063 | round = Math.round, | ||
| 1064 | rhorizontal = /left|center|right/, | ||
| 1065 | rvertical = /top|center|bottom/, | ||
| 1066 | roffset = /[\+\-]\d+(\.[\d]+)?%?/, | ||
| 1067 | rposition = /^\w+/, | ||
| 1068 | rpercent = /%$/, | ||
| 1069 | _position = $.fn.position; | ||
| 1070 | |||
| 1071 | function getOffsets( offsets, width, height ) { | ||
| 1072 | return [ | ||
| 1073 | parseFloat( offsets[ 0 ] ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ), | ||
| 1074 | parseFloat( offsets[ 1 ] ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 ) | ||
| 1075 | ]; | ||
| 1076 | } | ||
| 1077 | |||
| 1078 | function parseCss( element, property ) { | ||
| 1079 | return parseInt( $.css( element, property ), 10 ) || 0; | ||
| 1080 | } | ||
| 1081 | |||
| 1082 | function getDimensions( elem ) { | ||
| 1083 | var raw = elem[0]; | ||
| 1084 | if ( raw.nodeType === 9 ) { | ||
| 1085 | return { | ||
| 1086 | width: elem.width(), | ||
| 1087 | height: elem.height(), | ||
| 1088 | offset: { top: 0, left: 0 } | ||
| 1089 | }; | ||
| 1090 | } | ||
| 1091 | if ( $.isWindow( raw ) ) { | ||
| 1092 | return { | ||
| 1093 | width: elem.width(), | ||
| 1094 | height: elem.height(), | ||
| 1095 | offset: { top: elem.scrollTop(), left: elem.scrollLeft() } | ||
| 1096 | }; | ||
| 1097 | } | ||
| 1098 | if ( raw.preventDefault ) { | ||
| 1099 | return { | ||
| 1100 | width: 0, | ||
| 1101 | height: 0, | ||
| 1102 | offset: { top: raw.pageY, left: raw.pageX } | ||
| 1103 | }; | ||
| 1104 | } | ||
| 1105 | return { | ||
| 1106 | width: elem.outerWidth(), | ||
| 1107 | height: elem.outerHeight(), | ||
| 1108 | offset: elem.offset() | ||
| 1109 | }; | ||
| 1110 | } | ||
| 1111 | |||
| 1112 | $.position = { | ||
| 1113 | scrollbarWidth: function() { | ||
| 1114 | if ( cachedScrollbarWidth !== undefined ) { | ||
| 1115 | return cachedScrollbarWidth; | ||
| 1116 | } | ||
| 1117 | var w1, w2, | ||
| 1118 | div = $( "<div style='display:block;position:absolute;width:50px;height:50px;overflow:hidden;'><div style='height:100px;width:auto;'></div></div>" ), | ||
| 1119 | innerDiv = div.children()[0]; | ||
| 1120 | |||
| 1121 | $( "body" ).append( div ); | ||
| 1122 | w1 = innerDiv.offsetWidth; | ||
| 1123 | div.css( "overflow", "scroll" ); | ||
| 1124 | |||
| 1125 | w2 = innerDiv.offsetWidth; | ||
| 1126 | |||
| 1127 | if ( w1 === w2 ) { | ||
| 1128 | w2 = div[0].clientWidth; | ||
| 1129 | } | ||
| 1130 | |||
| 1131 | div.remove(); | ||
| 1132 | |||
| 1133 | return (cachedScrollbarWidth = w1 - w2); | ||
| 1134 | }, | ||
| 1135 | getScrollInfo: function( within ) { | ||
| 1136 | var overflowX = within.isWindow || within.isDocument ? "" : | ||
| 1137 | within.element.css( "overflow-x" ), | ||
| 1138 | overflowY = within.isWindow || within.isDocument ? "" : | ||
| 1139 | within.element.css( "overflow-y" ), | ||
| 1140 | hasOverflowX = overflowX === "scroll" || | ||
| 1141 | ( overflowX === "auto" && within.width < within.element[0].scrollWidth ), | ||
| 1142 | hasOverflowY = overflowY === "scroll" || | ||
| 1143 | ( overflowY === "auto" && within.height < within.element[0].scrollHeight ); | ||
| 1144 | return { | ||
| 1145 | width: hasOverflowY ? $.position.scrollbarWidth() : 0, | ||
| 1146 | height: hasOverflowX ? $.position.scrollbarWidth() : 0 | ||
| 1147 | }; | ||
| 1148 | }, | ||
| 1149 | getWithinInfo: function( element ) { | ||
| 1150 | var withinElement = $( element || window ), | ||
| 1151 | isWindow = $.isWindow( withinElement[0] ), | ||
| 1152 | isDocument = !!withinElement[ 0 ] && withinElement[ 0 ].nodeType === 9; | ||
| 1153 | return { | ||
| 1154 | element: withinElement, | ||
| 1155 | isWindow: isWindow, | ||
| 1156 | isDocument: isDocument, | ||
| 1157 | offset: withinElement.offset() || { left: 0, top: 0 }, | ||
| 1158 | scrollLeft: withinElement.scrollLeft(), | ||
| 1159 | scrollTop: withinElement.scrollTop(), | ||
| 1160 | |||
| 1161 | // support: jQuery 1.6.x | ||
| 1162 | // jQuery 1.6 doesn't support .outerWidth/Height() on documents or windows | ||
| 1163 | width: isWindow || isDocument ? withinElement.width() : withinElement.outerWidth(), | ||
| 1164 | height: isWindow || isDocument ? withinElement.height() : withinElement.outerHeight() | ||
| 1165 | }; | ||
| 1166 | } | ||
| 1167 | }; | ||
| 1168 | |||
| 1169 | $.fn.position = function( options ) { | ||
| 1170 | if ( !options || !options.of ) { | ||
| 1171 | return _position.apply( this, arguments ); | ||
| 1172 | } | ||
| 1173 | |||
| 1174 | // make a copy, we don't want to modify arguments | ||
| 1175 | options = $.extend( {}, options ); | ||
| 1176 | |||
| 1177 | var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions, | ||
| 1178 | target = $( options.of ), | ||
| 1179 | within = $.position.getWithinInfo( options.within ), | ||
| 1180 | scrollInfo = $.position.getScrollInfo( within ), | ||
| 1181 | collision = ( options.collision || "flip" ).split( " " ), | ||
| 1182 | offsets = {}; | ||
| 1183 | |||
| 1184 | dimensions = getDimensions( target ); | ||
| 1185 | if ( target[0].preventDefault ) { | ||
| 1186 | // force left top to allow flipping | ||
| 1187 | options.at = "left top"; | ||
| 1188 | } | ||
| 1189 | targetWidth = dimensions.width; | ||
| 1190 | targetHeight = dimensions.height; | ||
| 1191 | targetOffset = dimensions.offset; | ||
| 1192 | // clone to reuse original targetOffset later | ||
| 1193 | basePosition = $.extend( {}, targetOffset ); | ||
| 1194 | |||
| 1195 | // force my and at to have valid horizontal and vertical positions | ||
| 1196 | // if a value is missing or invalid, it will be converted to center | ||
| 1197 | $.each( [ "my", "at" ], function() { | ||
| 1198 | var pos = ( options[ this ] || "" ).split( " " ), | ||
| 1199 | horizontalOffset, | ||
| 1200 | verticalOffset; | ||
| 1201 | |||
| 1202 | if ( pos.length === 1) { | ||
| 1203 | pos = rhorizontal.test( pos[ 0 ] ) ? | ||
| 1204 | pos.concat( [ "center" ] ) : | ||
| 1205 | rvertical.test( pos[ 0 ] ) ? | ||
| 1206 | [ "center" ].concat( pos ) : | ||
| 1207 | [ "center", "center" ]; | ||
| 1208 | } | ||
| 1209 | pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center"; | ||
| 1210 | pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center"; | ||
| 1211 | |||
| 1212 | // calculate offsets | ||
| 1213 | horizontalOffset = roffset.exec( pos[ 0 ] ); | ||
| 1214 | verticalOffset = roffset.exec( pos[ 1 ] ); | ||
| 1215 | offsets[ this ] = [ | ||
| 1216 | horizontalOffset ? horizontalOffset[ 0 ] : 0, | ||
| 1217 | verticalOffset ? verticalOffset[ 0 ] : 0 | ||
| 1218 | ]; | ||
| 1219 | |||
| 1220 | // reduce to just the positions without the offsets | ||
| 1221 | options[ this ] = [ | ||
| 1222 | rposition.exec( pos[ 0 ] )[ 0 ], | ||
| 1223 | rposition.exec( pos[ 1 ] )[ 0 ] | ||
| 1224 | ]; | ||
| 1225 | }); | ||
| 1226 | |||
| 1227 | // normalize collision option | ||
| 1228 | if ( collision.length === 1 ) { | ||
| 1229 | collision[ 1 ] = collision[ 0 ]; | ||
| 1230 | } | ||
| 1231 | |||
| 1232 | if ( options.at[ 0 ] === "right" ) { | ||
| 1233 | basePosition.left += targetWidth; | ||
| 1234 | } else if ( options.at[ 0 ] === "center" ) { | ||
| 1235 | basePosition.left += targetWidth / 2; | ||
| 1236 | } | ||
| 1237 | |||
| 1238 | if ( options.at[ 1 ] === "bottom" ) { | ||
| 1239 | basePosition.top += targetHeight; | ||
| 1240 | } else if ( options.at[ 1 ] === "center" ) { | ||
| 1241 | basePosition.top += targetHeight / 2; | ||
| 1242 | } | ||
| 1243 | |||
| 1244 | atOffset = getOffsets( offsets.at, targetWidth, targetHeight ); | ||
| 1245 | basePosition.left += atOffset[ 0 ]; | ||
| 1246 | basePosition.top += atOffset[ 1 ]; | ||
| 1247 | |||
| 1248 | return this.each(function() { | ||
| 1249 | var collisionPosition, using, | ||
| 1250 | elem = $( this ), | ||
| 1251 | elemWidth = elem.outerWidth(), | ||
| 1252 | elemHeight = elem.outerHeight(), | ||
| 1253 | marginLeft = parseCss( this, "marginLeft" ), | ||
| 1254 | marginTop = parseCss( this, "marginTop" ), | ||
| 1255 | collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) + scrollInfo.width, | ||
| 1256 | collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) + scrollInfo.height, | ||
| 1257 | position = $.extend( {}, basePosition ), | ||
| 1258 | myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() ); | ||
| 1259 | |||
| 1260 | if ( options.my[ 0 ] === "right" ) { | ||
| 1261 | position.left -= elemWidth; | ||
| 1262 | } else if ( options.my[ 0 ] === "center" ) { | ||
| 1263 | position.left -= elemWidth / 2; | ||
| 1264 | } | ||
| 1265 | |||
| 1266 | if ( options.my[ 1 ] === "bottom" ) { | ||
| 1267 | position.top -= elemHeight; | ||
| 1268 | } else if ( options.my[ 1 ] === "center" ) { | ||
| 1269 | position.top -= elemHeight / 2; | ||
| 1270 | } | ||
| 1271 | |||
| 1272 | position.left += myOffset[ 0 ]; | ||
| 1273 | position.top += myOffset[ 1 ]; | ||
| 1274 | |||
| 1275 | // if the browser doesn't support fractions, then round for consistent results | ||
| 1276 | if ( !supportsOffsetFractions ) { | ||
| 1277 | position.left = round( position.left ); | ||
| 1278 | position.top = round( position.top ); | ||
| 1279 | } | ||
| 1280 | |||
| 1281 | collisionPosition = { | ||
| 1282 | marginLeft: marginLeft, | ||
| 1283 | marginTop: marginTop | ||
| 1284 | }; | ||
| 1285 | |||
| 1286 | $.each( [ "left", "top" ], function( i, dir ) { | ||
| 1287 | if ( $.ui.position[ collision[ i ] ] ) { | ||
| 1288 | $.ui.position[ collision[ i ] ][ dir ]( position, { | ||
| 1289 | targetWidth: targetWidth, | ||
| 1290 | targetHeight: targetHeight, | ||
| 1291 | elemWidth: elemWidth, | ||
| 1292 | elemHeight: elemHeight, | ||
| 1293 | collisionPosition: collisionPosition, | ||
| 1294 | collisionWidth: collisionWidth, | ||
| 1295 | collisionHeight: collisionHeight, | ||
| 1296 | offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ], | ||
| 1297 | my: options.my, | ||
| 1298 | at: options.at, | ||
| 1299 | within: within, | ||
| 1300 | elem: elem | ||
| 1301 | }); | ||
| 1302 | } | ||
| 1303 | }); | ||
| 1304 | |||
| 1305 | if ( options.using ) { | ||
| 1306 | // adds feedback as second argument to using callback, if present | ||
| 1307 | using = function( props ) { | ||
| 1308 | var left = targetOffset.left - position.left, | ||
| 1309 | right = left + targetWidth - elemWidth, | ||
| 1310 | top = targetOffset.top - position.top, | ||
| 1311 | bottom = top + targetHeight - elemHeight, | ||
| 1312 | feedback = { | ||
| 1313 | target: { | ||
| 1314 | element: target, | ||
| 1315 | left: targetOffset.left, | ||
| 1316 | top: targetOffset.top, | ||
| 1317 | width: targetWidth, | ||
| 1318 | height: targetHeight | ||
| 1319 | }, | ||
| 1320 | element: { | ||
| 1321 | element: elem, | ||
| 1322 | left: position.left, | ||
| 1323 | top: position.top, | ||
| 1324 | width: elemWidth, | ||
| 1325 | height: elemHeight | ||
| 1326 | }, | ||
| 1327 | horizontal: right < 0 ? "left" : left > 0 ? "right" : "center", | ||
| 1328 | vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle" | ||
| 1329 | }; | ||
| 1330 | if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) { | ||
| 1331 | feedback.horizontal = "center"; | ||
| 1332 | } | ||
| 1333 | if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) { | ||
| 1334 | feedback.vertical = "middle"; | ||
| 1335 | } | ||
| 1336 | if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) { | ||
| 1337 | feedback.important = "horizontal"; | ||
| 1338 | } else { | ||
| 1339 | feedback.important = "vertical"; | ||
| 1340 | } | ||
| 1341 | options.using.call( this, props, feedback ); | ||
| 1342 | }; | ||
| 1343 | } | ||
| 1344 | |||
| 1345 | elem.offset( $.extend( position, { using: using } ) ); | ||
| 1346 | }); | ||
| 1347 | }; | ||
| 1348 | |||
| 1349 | $.ui.position = { | ||
| 1350 | fit: { | ||
| 1351 | left: function( position, data ) { | ||
| 1352 | var within = data.within, | ||
| 1353 | withinOffset = within.isWindow ? within.scrollLeft : within.offset.left, | ||
| 1354 | outerWidth = within.width, | ||
| 1355 | collisionPosLeft = position.left - data.collisionPosition.marginLeft, | ||
| 1356 | overLeft = withinOffset - collisionPosLeft, | ||
| 1357 | overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset, | ||
| 1358 | newOverRight; | ||
| 1359 | |||
| 1360 | // element is wider than within | ||
| 1361 | if ( data.collisionWidth > outerWidth ) { | ||
| 1362 | // element is initially over the left side of within | ||
| 1363 | if ( overLeft > 0 && overRight <= 0 ) { | ||
| 1364 | newOverRight = position.left + overLeft + data.collisionWidth - outerWidth - withinOffset; | ||
| 1365 | position.left += overLeft - newOverRight; | ||
| 1366 | // element is initially over right side of within | ||
| 1367 | } else if ( overRight > 0 && overLeft <= 0 ) { | ||
| 1368 | position.left = withinOffset; | ||
| 1369 | // element is initially over both left and right sides of within | ||
| 1370 | } else { | ||
| 1371 | if ( overLeft > overRight ) { | ||
| 1372 | position.left = withinOffset + outerWidth - data.collisionWidth; | ||
| 1373 | } else { | ||
| 1374 | position.left = withinOffset; | ||
| 1375 | } | ||
| 1376 | } | ||
| 1377 | // too far left -> align with left edge | ||
| 1378 | } else if ( overLeft > 0 ) { | ||
| 1379 | position.left += overLeft; | ||
| 1380 | // too far right -> align with right edge | ||
| 1381 | } else if ( overRight > 0 ) { | ||
| 1382 | position.left -= overRight; | ||
| 1383 | // adjust based on position and margin | ||
| 1384 | } else { | ||
| 1385 | position.left = max( position.left - collisionPosLeft, position.left ); | ||
| 1386 | } | ||
| 1387 | }, | ||
| 1388 | top: function( position, data ) { | ||
| 1389 | var within = data.within, | ||
| 1390 | withinOffset = within.isWindow ? within.scrollTop : within.offset.top, | ||
| 1391 | outerHeight = data.within.height, | ||
| 1392 | collisionPosTop = position.top - data.collisionPosition.marginTop, | ||
| 1393 | overTop = withinOffset - collisionPosTop, | ||
| 1394 | overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset, | ||
| 1395 | newOverBottom; | ||
| 1396 | |||
| 1397 | // element is taller than within | ||
| 1398 | if ( data.collisionHeight > outerHeight ) { | ||
| 1399 | // element is initially over the top of within | ||
| 1400 | if ( overTop > 0 && overBottom <= 0 ) { | ||
| 1401 | newOverBottom = position.top + overTop + data.collisionHeight - outerHeight - withinOffset; | ||
| 1402 | position.top += overTop - newOverBottom; | ||
| 1403 | // element is initially over bottom of within | ||
| 1404 | } else if ( overBottom > 0 && overTop <= 0 ) { | ||
| 1405 | position.top = withinOffset; | ||
| 1406 | // element is initially over both top and bottom of within | ||
| 1407 | } else { | ||
| 1408 | if ( overTop > overBottom ) { | ||
| 1409 | position.top = withinOffset + outerHeight - data.collisionHeight; | ||
| 1410 | } else { | ||
| 1411 | position.top = withinOffset; | ||
| 1412 | } | ||
| 1413 | } | ||
| 1414 | // too far up -> align with top | ||
| 1415 | } else if ( overTop > 0 ) { | ||
| 1416 | position.top += overTop; | ||
| 1417 | // too far down -> align with bottom edge | ||
| 1418 | } else if ( overBottom > 0 ) { | ||
| 1419 | position.top -= overBottom; | ||
| 1420 | // adjust based on position and margin | ||
| 1421 | } else { | ||
| 1422 | position.top = max( position.top - collisionPosTop, position.top ); | ||
| 1423 | } | ||
| 1424 | } | ||
| 1425 | }, | ||
| 1426 | flip: { | ||
| 1427 | left: function( position, data ) { | ||
| 1428 | var within = data.within, | ||
| 1429 | withinOffset = within.offset.left + within.scrollLeft, | ||
| 1430 | outerWidth = within.width, | ||
| 1431 | offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left, | ||
| 1432 | collisionPosLeft = position.left - data.collisionPosition.marginLeft, | ||
| 1433 | overLeft = collisionPosLeft - offsetLeft, | ||
| 1434 | overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft, | ||
| 1435 | myOffset = data.my[ 0 ] === "left" ? | ||
| 1436 | -data.elemWidth : | ||
| 1437 | data.my[ 0 ] === "right" ? | ||
| 1438 | data.elemWidth : | ||
| 1439 | 0, | ||
| 1440 | atOffset = data.at[ 0 ] === "left" ? | ||
| 1441 | data.targetWidth : | ||
| 1442 | data.at[ 0 ] === "right" ? | ||
| 1443 | -data.targetWidth : | ||
| 1444 | 0, | ||
| 1445 | offset = -2 * data.offset[ 0 ], | ||
| 1446 | newOverRight, | ||
| 1447 | newOverLeft; | ||
| 1448 | |||
| 1449 | if ( overLeft < 0 ) { | ||
| 1450 | newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth - outerWidth - withinOffset; | ||
| 1451 | if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) { | ||
| 1452 | position.left += myOffset + atOffset + offset; | ||
| 1453 | } | ||
| 1454 | } else if ( overRight > 0 ) { | ||
| 1455 | newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset + atOffset + offset - offsetLeft; | ||
| 1456 | if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) { | ||
| 1457 | position.left += myOffset + atOffset + offset; | ||
| 1458 | } | ||
| 1459 | } | ||
| 1460 | }, | ||
| 1461 | top: function( position, data ) { | ||
| 1462 | var within = data.within, | ||
| 1463 | withinOffset = within.offset.top + within.scrollTop, | ||
| 1464 | outerHeight = within.height, | ||
| 1465 | offsetTop = within.isWindow ? within.scrollTop : within.offset.top, | ||
| 1466 | collisionPosTop = position.top - data.collisionPosition.marginTop, | ||
| 1467 | overTop = collisionPosTop - offsetTop, | ||
| 1468 | overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop, | ||
| 1469 | top = data.my[ 1 ] === "top", | ||
| 1470 | myOffset = top ? | ||
| 1471 | -data.elemHeight : | ||
| 1472 | data.my[ 1 ] === "bottom" ? | ||
| 1473 | data.elemHeight : | ||
| 1474 | 0, | ||
| 1475 | atOffset = data.at[ 1 ] === "top" ? | ||
| 1476 | data.targetHeight : | ||
| 1477 | data.at[ 1 ] === "bottom" ? | ||
| 1478 | -data.targetHeight : | ||
| 1479 | 0, | ||
| 1480 | offset = -2 * data.offset[ 1 ], | ||
| 1481 | newOverTop, | ||
| 1482 | newOverBottom; | ||
| 1483 | if ( overTop < 0 ) { | ||
| 1484 | newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight - outerHeight - withinOffset; | ||
| 1485 | if ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) { | ||
| 1486 | position.top += myOffset + atOffset + offset; | ||
| 1487 | } | ||
| 1488 | } else if ( overBottom > 0 ) { | ||
| 1489 | newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset + offset - offsetTop; | ||
| 1490 | if ( newOverTop > 0 || abs( newOverTop ) < overBottom ) { | ||
| 1491 | position.top += myOffset + atOffset + offset; | ||
| 1492 | } | ||
| 1493 | } | ||
| 1494 | } | ||
| 1495 | }, | ||
| 1496 | flipfit: { | ||
| 1497 | left: function() { | ||
| 1498 | $.ui.position.flip.left.apply( this, arguments ); | ||
| 1499 | $.ui.position.fit.left.apply( this, arguments ); | ||
| 1500 | }, | ||
| 1501 | top: function() { | ||
| 1502 | $.ui.position.flip.top.apply( this, arguments ); | ||
| 1503 | $.ui.position.fit.top.apply( this, arguments ); | ||
| 1504 | } | ||
| 1505 | } | ||
| 1506 | }; | ||
| 1507 | |||
| 1508 | // fraction support test | ||
| 1509 | (function() { | ||
| 1510 | var testElement, testElementParent, testElementStyle, offsetLeft, i, | ||
| 1511 | body = document.getElementsByTagName( "body" )[ 0 ], | ||
| 1512 | div = document.createElement( "div" ); | ||
| 1513 | |||
| 1514 | //Create a "fake body" for testing based on method used in jQuery.support | ||
| 1515 | testElement = document.createElement( body ? "div" : "body" ); | ||
| 1516 | testElementStyle = { | ||
| 1517 | visibility: "hidden", | ||
| 1518 | width: 0, | ||
| 1519 | height: 0, | ||
| 1520 | border: 0, | ||
| 1521 | margin: 0, | ||
| 1522 | background: "none" | ||
| 1523 | }; | ||
| 1524 | if ( body ) { | ||
| 1525 | $.extend( testElementStyle, { | ||
| 1526 | position: "absolute", | ||
| 1527 | left: "-1000px", | ||
| 1528 | top: "-1000px" | ||
| 1529 | }); | ||
| 1530 | } | ||
| 1531 | for ( i in testElementStyle ) { | ||
| 1532 | testElement.style[ i ] = testElementStyle[ i ]; | ||
| 1533 | } | ||
| 1534 | testElement.appendChild( div ); | ||
| 1535 | testElementParent = body || document.documentElement; | ||
| 1536 | testElementParent.insertBefore( testElement, testElementParent.firstChild ); | ||
| 1537 | |||
| 1538 | div.style.cssText = "position: absolute; left: 10.7432222px;"; | ||
| 1539 | |||
| 1540 | offsetLeft = $( div ).offset().left; | ||
| 1541 | supportsOffsetFractions = offsetLeft > 10 && offsetLeft < 11; | ||
| 1542 | |||
| 1543 | testElement.innerHTML = ""; | ||
| 1544 | testElementParent.removeChild( testElement ); | ||
| 1545 | })(); | ||
| 1546 | |||
| 1547 | })(); | ||
| 1548 | |||
| 1549 | var position = $.ui.position; | ||
| 1550 | |||
| 1551 | |||
| 1552 | /*! | ||
| 1553 | * jQuery UI Draggable 1.11.4 | ||
| 1554 | * http://jqueryui.com | ||
| 1555 | * | ||
| 1556 | * Copyright jQuery Foundation and other contributors | ||
| 1557 | * Released under the MIT license. | ||
| 1558 | * http://jquery.org/license | ||
| 1559 | * | ||
| 1560 | * http://api.jqueryui.com/draggable/ | ||
| 1561 | */ | ||
| 1562 | |||
| 1563 | |||
| 1564 | $.widget("ui.draggable", $.ui.mouse, { | ||
| 1565 | version: "1.11.4", | ||
| 1566 | widgetEventPrefix: "drag", | ||
| 1567 | options: { | ||
| 1568 | addClasses: true, | ||
| 1569 | appendTo: "parent", | ||
| 1570 | axis: false, | ||
| 1571 | connectToSortable: false, | ||
| 1572 | containment: false, | ||
| 1573 | cursor: "auto", | ||
| 1574 | cursorAt: false, | ||
| 1575 | grid: false, | ||
| 1576 | handle: false, | ||
| 1577 | helper: "original", | ||
| 1578 | iframeFix: false, | ||
| 1579 | opacity: false, | ||
| 1580 | refreshPositions: false, | ||
| 1581 | revert: false, | ||
| 1582 | revertDuration: 500, | ||
| 1583 | scope: "default", | ||
| 1584 | scroll: true, | ||
| 1585 | scrollSensitivity: 20, | ||
| 1586 | scrollSpeed: 20, | ||
| 1587 | snap: false, | ||
| 1588 | snapMode: "both", | ||
| 1589 | snapTolerance: 20, | ||
| 1590 | stack: false, | ||
| 1591 | zIndex: false, | ||
| 1592 | |||
| 1593 | // callbacks | ||
| 1594 | drag: null, | ||
| 1595 | start: null, | ||
| 1596 | stop: null | ||
| 1597 | }, | ||
| 1598 | _create: function() { | ||
| 1599 | |||
| 1600 | if ( this.options.helper === "original" ) { | ||
| 1601 | this._setPositionRelative(); | ||
| 1602 | } | ||
| 1603 | if (this.options.addClasses){ | ||
| 1604 | this.element.addClass("ui-draggable"); | ||
| 1605 | } | ||
| 1606 | if (this.options.disabled){ | ||
| 1607 | this.element.addClass("ui-draggable-disabled"); | ||
| 1608 | } | ||
| 1609 | this._setHandleClassName(); | ||
| 1610 | |||
| 1611 | this._mouseInit(); | ||
| 1612 | }, | ||
| 1613 | |||
| 1614 | _setOption: function( key, value ) { | ||
| 1615 | this._super( key, value ); | ||
| 1616 | if ( key === "handle" ) { | ||
| 1617 | this._removeHandleClassName(); | ||
| 1618 | this._setHandleClassName(); | ||
| 1619 | } | ||
| 1620 | }, | ||
| 1621 | |||
| 1622 | _destroy: function() { | ||
| 1623 | if ( ( this.helper || this.element ).is( ".ui-draggable-dragging" ) ) { | ||
| 1624 | this.destroyOnClear = true; | ||
| 1625 | return; | ||
| 1626 | } | ||
| 1627 | this.element.removeClass( "ui-draggable ui-draggable-dragging ui-draggable-disabled" ); | ||
| 1628 | this._removeHandleClassName(); | ||
| 1629 | this._mouseDestroy(); | ||
| 1630 | }, | ||
| 1631 | |||
| 1632 | _mouseCapture: function(event) { | ||
| 1633 | var o = this.options; | ||
| 1634 | |||
| 1635 | this._blurActiveElement( event ); | ||
| 1636 | |||
| 1637 | // among others, prevent a drag on a resizable-handle | ||
| 1638 | if (this.helper || o.disabled || $(event.target).closest(".ui-resizable-handle").length > 0) { | ||
| 1639 | return false; | ||
| 1640 | } | ||
| 1641 | |||
| 1642 | //Quit if we're not on a valid handle | ||
| 1643 | this.handle = this._getHandle(event); | ||
| 1644 | if (!this.handle) { | ||
| 1645 | return false; | ||
| 1646 | } | ||
| 1647 | |||
| 1648 | this._blockFrames( o.iframeFix === true ? "iframe" : o.iframeFix ); | ||
| 1649 | |||
| 1650 | return true; | ||
| 1651 | |||
| 1652 | }, | ||
| 1653 | |||
| 1654 | _blockFrames: function( selector ) { | ||
| 1655 | this.iframeBlocks = this.document.find( selector ).map(function() { | ||
| 1656 | var iframe = $( this ); | ||
| 1657 | |||
| 1658 | return $( "<div>" ) | ||
| 1659 | .css( "position", "absolute" ) | ||
| 1660 | .appendTo( iframe.parent() ) | ||
| 1661 | .outerWidth( iframe.outerWidth() ) | ||
| 1662 | .outerHeight( iframe.outerHeight() ) | ||
| 1663 | .offset( iframe.offset() )[ 0 ]; | ||
| 1664 | }); | ||
| 1665 | }, | ||
| 1666 | |||
| 1667 | _unblockFrames: function() { | ||
| 1668 | if ( this.iframeBlocks ) { | ||
| 1669 | this.iframeBlocks.remove(); | ||
| 1670 | delete this.iframeBlocks; | ||
| 1671 | } | ||
| 1672 | }, | ||
| 1673 | |||
| 1674 | _blurActiveElement: function( event ) { | ||
| 1675 | var document = this.document[ 0 ]; | ||
| 1676 | |||
| 1677 | // Only need to blur if the event occurred on the draggable itself, see #10527 | ||
| 1678 | if ( !this.handleElement.is( event.target ) ) { | ||
| 1679 | return; | ||
| 1680 | } | ||
| 1681 | |||
| 1682 | // support: IE9 | ||
| 1683 | // IE9 throws an "Unspecified error" accessing document.activeElement from an <iframe> | ||
| 1684 | try { | ||
| 1685 | |||
| 1686 | // Support: IE9, IE10 | ||
| 1687 | // If the <body> is blurred, IE will switch windows, see #9520 | ||
| 1688 | if ( document.activeElement && document.activeElement.nodeName.toLowerCase() !== "body" ) { | ||
| 1689 | |||
| 1690 | // Blur any element that currently has focus, see #4261 | ||
| 1691 | $( document.activeElement ).blur(); | ||
| 1692 | } | ||
| 1693 | } catch ( error ) {} | ||
| 1694 | }, | ||
| 1695 | |||
| 1696 | _mouseStart: function(event) { | ||
| 1697 | |||
| 1698 | var o = this.options; | ||
| 1699 | |||
| 1700 | //Create and append the visible helper | ||
| 1701 | this.helper = this._createHelper(event); | ||
| 1702 | |||
| 1703 | this.helper.addClass("ui-draggable-dragging"); | ||
| 1704 | |||
| 1705 | //Cache the helper size | ||
| 1706 | this._cacheHelperProportions(); | ||
| 1707 | |||
| 1708 | //If ddmanager is used for droppables, set the global draggable | ||
| 1709 | if ($.ui.ddmanager) { | ||
| 1710 | $.ui.ddmanager.current = this; | ||
| 1711 | } | ||
| 1712 | |||
| 1713 | /* | ||
| 1714 | * - Position generation - | ||
| 1715 | * This block generates everything position related - it's the core of draggables. | ||
| 1716 | */ | ||
| 1717 | |||
| 1718 | //Cache the margins of the original element | ||
| 1719 | this._cacheMargins(); | ||
| 1720 | |||
| 1721 | //Store the helper's css position | ||
| 1722 | this.cssPosition = this.helper.css( "position" ); | ||
| 1723 | this.scrollParent = this.helper.scrollParent( true ); | ||
| 1724 | this.offsetParent = this.helper.offsetParent(); | ||
| 1725 | this.hasFixedAncestor = this.helper.parents().filter(function() { | ||
| 1726 | return $( this ).css( "position" ) === "fixed"; | ||
| 1727 | }).length > 0; | ||
| 1728 | |||
| 1729 | //The element's absolute position on the page minus margins | ||
| 1730 | this.positionAbs = this.element.offset(); | ||
| 1731 | this._refreshOffsets( event ); | ||
| 1732 | |||
| 1733 | //Generate the original position | ||
| 1734 | this.originalPosition = this.position = this._generatePosition( event, false ); | ||
| 1735 | this.originalPageX = event.pageX; | ||
| 1736 | this.originalPageY = event.pageY; | ||
| 1737 | |||
| 1738 | //Adjust the mouse offset relative to the helper if "cursorAt" is supplied | ||
| 1739 | (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt)); | ||
| 1740 | |||
| 1741 | //Set a containment if given in the options | ||
| 1742 | this._setContainment(); | ||
| 1743 | |||
| 1744 | //Trigger event + callbacks | ||
| 1745 | if (this._trigger("start", event) === false) { | ||
| 1746 | this._clear(); | ||
| 1747 | return false; | ||
| 1748 | } | ||
| 1749 | |||
| 1750 | //Recache the helper size | ||
| 1751 | this._cacheHelperProportions(); | ||
| 1752 | |||
| 1753 | //Prepare the droppable offsets | ||
| 1754 | if ($.ui.ddmanager && !o.dropBehaviour) { | ||
| 1755 | $.ui.ddmanager.prepareOffsets(this, event); | ||
| 1756 | } | ||
| 1757 | |||
| 1758 | // Reset helper's right/bottom css if they're set and set explicit width/height instead | ||
| 1759 | // as this prevents resizing of elements with right/bottom set (see #7772) | ||
| 1760 | this._normalizeRightBottom(); | ||
| 1761 | |||
| 1762 | this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position | ||
| 1763 | |||
| 1764 | //If the ddmanager is used for droppables, inform the manager that dragging has started (see #5003) | ||
| 1765 | if ( $.ui.ddmanager ) { | ||
| 1766 | $.ui.ddmanager.dragStart(this, event); | ||
| 1767 | } | ||
| 1768 | |||
| 1769 | return true; | ||
| 1770 | }, | ||
| 1771 | |||
| 1772 | _refreshOffsets: function( event ) { | ||
| 1773 | this.offset = { | ||
| 1774 | top: this.positionAbs.top - this.margins.top, | ||
| 1775 | left: this.positionAbs.left - this.margins.left, | ||
| 1776 | scroll: false, | ||
| 1777 | parent: this._getParentOffset(), | ||
| 1778 | relative: this._getRelativeOffset() | ||
| 1779 | }; | ||
| 1780 | |||
| 1781 | this.offset.click = { | ||
| 1782 | left: event.pageX - this.offset.left, | ||
| 1783 | top: event.pageY - this.offset.top | ||
| 1784 | }; | ||
| 1785 | }, | ||
| 1786 | |||
| 1787 | _mouseDrag: function(event, noPropagation) { | ||
| 1788 | // reset any necessary cached properties (see #5009) | ||
| 1789 | if ( this.hasFixedAncestor ) { | ||
| 1790 | this.offset.parent = this._getParentOffset(); | ||
| 1791 | } | ||
| 1792 | |||
| 1793 | //Compute the helpers position | ||
| 1794 | this.position = this._generatePosition( event, true ); | ||
| 1795 | this.positionAbs = this._convertPositionTo("absolute"); | ||
| 1796 | |||
| 1797 | //Call plugins and callbacks and use the resulting position if something is returned | ||
| 1798 | if (!noPropagation) { | ||
| 1799 | var ui = this._uiHash(); | ||
| 1800 | if (this._trigger("drag", event, ui) === false) { | ||
| 1801 | this._mouseUp({}); | ||
| 1802 | return false; | ||
| 1803 | } | ||
| 1804 | this.position = ui.position; | ||
| 1805 | } | ||
| 1806 | |||
| 1807 | this.helper[ 0 ].style.left = this.position.left + "px"; | ||
| 1808 | this.helper[ 0 ].style.top = this.position.top + "px"; | ||
| 1809 | |||
| 1810 | if ($.ui.ddmanager) { | ||
| 1811 | $.ui.ddmanager.drag(this, event); | ||
| 1812 | } | ||
| 1813 | |||
| 1814 | return false; | ||
| 1815 | }, | ||
| 1816 | |||
| 1817 | _mouseStop: function(event) { | ||
| 1818 | |||
| 1819 | //If we are using droppables, inform the manager about the drop | ||
| 1820 | var that = this, | ||
| 1821 | dropped = false; | ||
| 1822 | if ($.ui.ddmanager && !this.options.dropBehaviour) { | ||
| 1823 | dropped = $.ui.ddmanager.drop(this, event); | ||
| 1824 | } | ||
| 1825 | |||
| 1826 | //if a drop comes from outside (a sortable) | ||
| 1827 | if (this.dropped) { | ||
| 1828 | dropped = this.dropped; | ||
| 1829 | this.dropped = false; | ||
| 1830 | } | ||
| 1831 | |||
| 1832 | if ((this.options.revert === "invalid" && !dropped) || (this.options.revert === "valid" && dropped) || this.options.revert === true || ($.isFunction(this.options.revert) && this.options.revert.call(this.element, dropped))) { | ||
| 1833 | $(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() { | ||
| 1834 | if (that._trigger("stop", event) !== false) { | ||
| 1835 | that._clear(); | ||
| 1836 | } | ||
| 1837 | }); | ||
| 1838 | } else { | ||
| 1839 | if (this._trigger("stop", event) !== false) { | ||
| 1840 | this._clear(); | ||
| 1841 | } | ||
| 1842 | } | ||
| 1843 | |||
| 1844 | return false; | ||
| 1845 | }, | ||
| 1846 | |||
| 1847 | _mouseUp: function( event ) { | ||
| 1848 | this._unblockFrames(); | ||
| 1849 | |||
| 1850 | //If the ddmanager is used for droppables, inform the manager that dragging has stopped (see #5003) | ||
| 1851 | if ( $.ui.ddmanager ) { | ||
| 1852 | $.ui.ddmanager.dragStop(this, event); | ||
| 1853 | } | ||
| 1854 | |||
| 1855 | // Only need to focus if the event occurred on the draggable itself, see #10527 | ||
| 1856 | if ( this.handleElement.is( event.target ) ) { | ||
| 1857 | // The interaction is over; whether or not the click resulted in a drag, focus the element | ||
| 1858 | this.element.focus(); | ||
| 1859 | } | ||
| 1860 | |||
| 1861 | return $.ui.mouse.prototype._mouseUp.call(this, event); | ||
| 1862 | }, | ||
| 1863 | |||
| 1864 | cancel: function() { | ||
| 1865 | |||
| 1866 | if (this.helper.is(".ui-draggable-dragging")) { | ||
| 1867 | this._mouseUp({}); | ||
| 1868 | } else { | ||
| 1869 | this._clear(); | ||
| 1870 | } | ||
| 1871 | |||
| 1872 | return this; | ||
| 1873 | |||
| 1874 | }, | ||
| 1875 | |||
| 1876 | _getHandle: function(event) { | ||
| 1877 | return this.options.handle ? | ||
| 1878 | !!$( event.target ).closest( this.element.find( this.options.handle ) ).length : | ||
| 1879 | true; | ||
| 1880 | }, | ||
| 1881 | |||
| 1882 | _setHandleClassName: function() { | ||
| 1883 | this.handleElement = this.options.handle ? | ||
| 1884 | this.element.find( this.options.handle ) : this.element; | ||
| 1885 | this.handleElement.addClass( "ui-draggable-handle" ); | ||
| 1886 | }, | ||
| 1887 | |||
| 1888 | _removeHandleClassName: function() { | ||
| 1889 | this.handleElement.removeClass( "ui-draggable-handle" ); | ||
| 1890 | }, | ||
| 1891 | |||
| 1892 | _createHelper: function(event) { | ||
| 1893 | |||
| 1894 | var o = this.options, | ||
| 1895 | helperIsFunction = $.isFunction( o.helper ), | ||
| 1896 | helper = helperIsFunction ? | ||
| 1897 | $( o.helper.apply( this.element[ 0 ], [ event ] ) ) : | ||
| 1898 | ( o.helper === "clone" ? | ||
| 1899 | this.element.clone().removeAttr( "id" ) : | ||
| 1900 | this.element ); | ||
| 1901 | |||
| 1902 | if (!helper.parents("body").length) { | ||
| 1903 | helper.appendTo((o.appendTo === "parent" ? this.element[0].parentNode : o.appendTo)); | ||
| 1904 | } | ||
| 1905 | |||
| 1906 | // http://bugs.jqueryui.com/ticket/9446 | ||
| 1907 | // a helper function can return the original element | ||
| 1908 | // which wouldn't have been set to relative in _create | ||
| 1909 | if ( helperIsFunction && helper[ 0 ] === this.element[ 0 ] ) { | ||
| 1910 | this._setPositionRelative(); | ||
| 1911 | } | ||
| 1912 | |||
| 1913 | if (helper[0] !== this.element[0] && !(/(fixed|absolute)/).test(helper.css("position"))) { | ||
| 1914 | helper.css("position", "absolute"); | ||
| 1915 | } | ||
| 1916 | |||
| 1917 | return helper; | ||
| 1918 | |||
| 1919 | }, | ||
| 1920 | |||
| 1921 | _setPositionRelative: function() { | ||
| 1922 | if ( !( /^(?:r|a|f)/ ).test( this.element.css( "position" ) ) ) { | ||
| 1923 | this.element[ 0 ].style.position = "relative"; | ||
| 1924 | } | ||
| 1925 | }, | ||
| 1926 | |||
| 1927 | _adjustOffsetFromHelper: function(obj) { | ||
| 1928 | if (typeof obj === "string") { | ||
| 1929 | obj = obj.split(" "); | ||
| 1930 | } | ||
| 1931 | if ($.isArray(obj)) { | ||
| 1932 | obj = { left: +obj[0], top: +obj[1] || 0 }; | ||
| 1933 | } | ||
| 1934 | if ("left" in obj) { | ||
| 1935 | this.offset.click.left = obj.left + this.margins.left; | ||
| 1936 | } | ||
| 1937 | if ("right" in obj) { | ||
| 1938 | this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left; | ||
| 1939 | } | ||
| 1940 | if ("top" in obj) { | ||
| 1941 | this.offset.click.top = obj.top + this.margins.top; | ||
| 1942 | } | ||
| 1943 | if ("bottom" in obj) { | ||
| 1944 | this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top; | ||
| 1945 | } | ||
| 1946 | }, | ||
| 1947 | |||
| 1948 | _isRootNode: function( element ) { | ||
| 1949 | return ( /(html|body)/i ).test( element.tagName ) || element === this.document[ 0 ]; | ||
| 1950 | }, | ||
| 1951 | |||
| 1952 | _getParentOffset: function() { | ||
| 1953 | |||
| 1954 | //Get the offsetParent and cache its position | ||
| 1955 | var po = this.offsetParent.offset(), | ||
| 1956 | document = this.document[ 0 ]; | ||
| 1957 | |||
| 1958 | // This is a special case where we need to modify a offset calculated on start, since the following happened: | ||
| 1959 | // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent | ||
| 1960 | // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that | ||
| 1961 | // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag | ||
| 1962 | if (this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) { | ||
| 1963 | po.left += this.scrollParent.scrollLeft(); | ||
| 1964 | po.top += this.scrollParent.scrollTop(); | ||
| 1965 | } | ||
| 1966 | |||
| 1967 | if ( this._isRootNode( this.offsetParent[ 0 ] ) ) { | ||
| 1968 | po = { top: 0, left: 0 }; | ||
| 1969 | } | ||
| 1970 | |||
| 1971 | return { | ||
| 1972 | top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"), 10) || 0), | ||
| 1973 | left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"), 10) || 0) | ||
| 1974 | }; | ||
| 1975 | |||
| 1976 | }, | ||
| 1977 | |||
| 1978 | _getRelativeOffset: function() { | ||
| 1979 | if ( this.cssPosition !== "relative" ) { | ||
| 1980 | return { top: 0, left: 0 }; | ||
| 1981 | } | ||
| 1982 | |||
| 1983 | var p = this.element.position(), | ||
| 1984 | scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] ); | ||
| 1985 | |||
| 1986 | return { | ||
| 1987 | top: p.top - ( parseInt(this.helper.css( "top" ), 10) || 0 ) + ( !scrollIsRootNode ? this.scrollParent.scrollTop() : 0 ), | ||
| 1988 | left: p.left - ( parseInt(this.helper.css( "left" ), 10) || 0 ) + ( !scrollIsRootNode ? this.scrollParent.scrollLeft() : 0 ) | ||
| 1989 | }; | ||
| 1990 | |||
| 1991 | }, | ||
| 1992 | |||
| 1993 | _cacheMargins: function() { | ||
| 1994 | this.margins = { | ||
| 1995 | left: (parseInt(this.element.css("marginLeft"), 10) || 0), | ||
| 1996 | top: (parseInt(this.element.css("marginTop"), 10) || 0), | ||
| 1997 | right: (parseInt(this.element.css("marginRight"), 10) || 0), | ||
| 1998 | bottom: (parseInt(this.element.css("marginBottom"), 10) || 0) | ||
| 1999 | }; | ||
| 2000 | }, | ||
| 2001 | |||
| 2002 | _cacheHelperProportions: function() { | ||
| 2003 | this.helperProportions = { | ||
| 2004 | width: this.helper.outerWidth(), | ||
| 2005 | height: this.helper.outerHeight() | ||
| 2006 | }; | ||
| 2007 | }, | ||
| 2008 | |||
| 2009 | _setContainment: function() { | ||
| 2010 | |||
| 2011 | var isUserScrollable, c, ce, | ||
| 2012 | o = this.options, | ||
| 2013 | document = this.document[ 0 ]; | ||
| 2014 | |||
| 2015 | this.relativeContainer = null; | ||
| 2016 | |||
| 2017 | if ( !o.containment ) { | ||
| 2018 | this.containment = null; | ||
| 2019 | return; | ||
| 2020 | } | ||
| 2021 | |||
| 2022 | if ( o.containment === "window" ) { | ||
| 2023 | this.containment = [ | ||
| 2024 | $( window ).scrollLeft() - this.offset.relative.left - this.offset.parent.left, | ||
| 2025 | $( window ).scrollTop() - this.offset.relative.top - this.offset.parent.top, | ||
| 2026 | $( window ).scrollLeft() + $( window ).width() - this.helperProportions.width - this.margins.left, | ||
| 2027 | $( window ).scrollTop() + ( $( window ).height() || document.body.parentNode.scrollHeight ) - this.helperProportions.height - this.margins.top | ||
| 2028 | ]; | ||
| 2029 | return; | ||
| 2030 | } | ||
| 2031 | |||
| 2032 | if ( o.containment === "document") { | ||
| 2033 | this.containment = [ | ||
| 2034 | 0, | ||
| 2035 | 0, | ||
| 2036 | $( document ).width() - this.helperProportions.width - this.margins.left, | ||
| 2037 | ( $( document ).height() || document.body.parentNode.scrollHeight ) - this.helperProportions.height - this.margins.top | ||
| 2038 | ]; | ||
| 2039 | return; | ||
| 2040 | } | ||
| 2041 | |||
| 2042 | if ( o.containment.constructor === Array ) { | ||
| 2043 | this.containment = o.containment; | ||
| 2044 | return; | ||
| 2045 | } | ||
| 2046 | |||
| 2047 | if ( o.containment === "parent" ) { | ||
| 2048 | o.containment = this.helper[ 0 ].parentNode; | ||
| 2049 | } | ||
| 2050 | |||
| 2051 | c = $( o.containment ); | ||
| 2052 | ce = c[ 0 ]; | ||
| 2053 | |||
| 2054 | if ( !ce ) { | ||
| 2055 | return; | ||
| 2056 | } | ||
| 2057 | |||
| 2058 | isUserScrollable = /(scroll|auto)/.test( c.css( "overflow" ) ); | ||
| 2059 | |||
| 2060 | this.containment = [ | ||
| 2061 | ( parseInt( c.css( "borderLeftWidth" ), 10 ) || 0 ) + ( parseInt( c.css( "paddingLeft" ), 10 ) || 0 ), | ||
| 2062 | ( parseInt( c.css( "borderTopWidth" ), 10 ) || 0 ) + ( parseInt( c.css( "paddingTop" ), 10 ) || 0 ), | ||
| 2063 | ( isUserScrollable ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) - | ||
| 2064 | ( parseInt( c.css( "borderRightWidth" ), 10 ) || 0 ) - | ||
| 2065 | ( parseInt( c.css( "paddingRight" ), 10 ) || 0 ) - | ||
| 2066 | this.helperProportions.width - | ||
| 2067 | this.margins.left - | ||
| 2068 | this.margins.right, | ||
| 2069 | ( isUserScrollable ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) - | ||
| 2070 | ( parseInt( c.css( "borderBottomWidth" ), 10 ) || 0 ) - | ||
| 2071 | ( parseInt( c.css( "paddingBottom" ), 10 ) || 0 ) - | ||
| 2072 | this.helperProportions.height - | ||
| 2073 | this.margins.top - | ||
| 2074 | this.margins.bottom | ||
| 2075 | ]; | ||
| 2076 | this.relativeContainer = c; | ||
| 2077 | }, | ||
| 2078 | |||
| 2079 | _convertPositionTo: function(d, pos) { | ||
| 2080 | |||
| 2081 | if (!pos) { | ||
| 2082 | pos = this.position; | ||
| 2083 | } | ||
| 2084 | |||
| 2085 | var mod = d === "absolute" ? 1 : -1, | ||
| 2086 | scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] ); | ||
| 2087 | |||
| 2088 | return { | ||
| 2089 | top: ( | ||
| 2090 | pos.top + // The absolute mouse position | ||
| 2091 | this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent | ||
| 2092 | this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border) | ||
| 2093 | ( ( this.cssPosition === "fixed" ? -this.offset.scroll.top : ( scrollIsRootNode ? 0 : this.offset.scroll.top ) ) * mod) | ||
| 2094 | ), | ||
| 2095 | left: ( | ||
| 2096 | pos.left + // The absolute mouse position | ||
| 2097 | this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent | ||
| 2098 | this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border) | ||
| 2099 | ( ( this.cssPosition === "fixed" ? -this.offset.scroll.left : ( scrollIsRootNode ? 0 : this.offset.scroll.left ) ) * mod) | ||
| 2100 | ) | ||
| 2101 | }; | ||
| 2102 | |||
| 2103 | }, | ||
| 2104 | |||
| 2105 | _generatePosition: function( event, constrainPosition ) { | ||
| 2106 | |||
| 2107 | var containment, co, top, left, | ||
| 2108 | o = this.options, | ||
| 2109 | scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] ), | ||
| 2110 | pageX = event.pageX, | ||
| 2111 | pageY = event.pageY; | ||
| 2112 | |||
| 2113 | // Cache the scroll | ||
| 2114 | if ( !scrollIsRootNode || !this.offset.scroll ) { | ||
| 2115 | this.offset.scroll = { | ||
| 2116 | top: this.scrollParent.scrollTop(), | ||
| 2117 | left: this.scrollParent.scrollLeft() | ||
| 2118 | }; | ||
| 2119 | } | ||
| 2120 | |||
| 2121 | /* | ||
| 2122 | * - Position constraining - | ||
| 2123 | * Constrain the position to a mix of grid, containment. | ||
| 2124 | */ | ||
| 2125 | |||
| 2126 | // If we are not dragging yet, we won't check for options | ||
| 2127 | if ( constrainPosition ) { | ||
| 2128 | if ( this.containment ) { | ||
| 2129 | if ( this.relativeContainer ){ | ||
| 2130 | co = this.relativeContainer.offset(); | ||
| 2131 | containment = [ | ||
| 2132 | this.containment[ 0 ] + co.left, | ||
| 2133 | this.containment[ 1 ] + co.top, | ||
| 2134 | this.containment[ 2 ] + co.left, | ||
| 2135 | this.containment[ 3 ] + co.top | ||
| 2136 | ]; | ||
| 2137 | } else { | ||
| 2138 | containment = this.containment; | ||
| 2139 | } | ||
| 2140 | |||
| 2141 | if (event.pageX - this.offset.click.left < containment[0]) { | ||
| 2142 | pageX = containment[0] + this.offset.click.left; | ||
| 2143 | } | ||
| 2144 | if (event.pageY - this.offset.click.top < containment[1]) { | ||
| 2145 | pageY = containment[1] + this.offset.click.top; | ||
| 2146 | } | ||
| 2147 | if (event.pageX - this.offset.click.left > containment[2]) { | ||
| 2148 | pageX = containment[2] + this.offset.click.left; | ||
| 2149 | } | ||
| 2150 | if (event.pageY - this.offset.click.top > containment[3]) { | ||
| 2151 | pageY = containment[3] + this.offset.click.top; | ||
| 2152 | } | ||
| 2153 | } | ||
| 2154 | |||
| 2155 | if (o.grid) { | ||
| 2156 | //Check for grid elements set to 0 to prevent divide by 0 error causing invalid argument errors in IE (see ticket #6950) | ||
| 2157 | top = o.grid[1] ? this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1] : this.originalPageY; | ||
| 2158 | pageY = containment ? ((top - this.offset.click.top >= containment[1] || top - this.offset.click.top > containment[3]) ? top : ((top - this.offset.click.top >= containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top; | ||
| 2159 | |||
| 2160 | left = o.grid[0] ? this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0] : this.originalPageX; | ||
| 2161 | pageX = containment ? ((left - this.offset.click.left >= containment[0] || left - this.offset.click.left > containment[2]) ? left : ((left - this.offset.click.left >= containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left; | ||
| 2162 | } | ||
| 2163 | |||
| 2164 | if ( o.axis === "y" ) { | ||
| 2165 | pageX = this.originalPageX; | ||
| 2166 | } | ||
| 2167 | |||
| 2168 | if ( o.axis === "x" ) { | ||
| 2169 | pageY = this.originalPageY; | ||
| 2170 | } | ||
| 2171 | } | ||
| 2172 | |||
| 2173 | return { | ||
| 2174 | top: ( | ||
| 2175 | pageY - // The absolute mouse position | ||
| 2176 | this.offset.click.top - // Click offset (relative to the element) | ||
| 2177 | this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent | ||
| 2178 | this.offset.parent.top + // The offsetParent's offset without borders (offset + border) | ||
| 2179 | ( this.cssPosition === "fixed" ? -this.offset.scroll.top : ( scrollIsRootNode ? 0 : this.offset.scroll.top ) ) | ||
| 2180 | ), | ||
| 2181 | left: ( | ||
| 2182 | pageX - // The absolute mouse position | ||
| 2183 | this.offset.click.left - // Click offset (relative to the element) | ||
| 2184 | this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent | ||
| 2185 | this.offset.parent.left + // The offsetParent's offset without borders (offset + border) | ||
| 2186 | ( this.cssPosition === "fixed" ? -this.offset.scroll.left : ( scrollIsRootNode ? 0 : this.offset.scroll.left ) ) | ||
| 2187 | ) | ||
| 2188 | }; | ||
| 2189 | |||
| 2190 | }, | ||
| 2191 | |||
| 2192 | _clear: function() { | ||
| 2193 | this.helper.removeClass("ui-draggable-dragging"); | ||
| 2194 | if (this.helper[0] !== this.element[0] && !this.cancelHelperRemoval) { | ||
| 2195 | this.helper.remove(); | ||
| 2196 | } | ||
| 2197 | this.helper = null; | ||
| 2198 | this.cancelHelperRemoval = false; | ||
| 2199 | if ( this.destroyOnClear ) { | ||
| 2200 | this.destroy(); | ||
| 2201 | } | ||
| 2202 | }, | ||
| 2203 | |||
| 2204 | _normalizeRightBottom: function() { | ||
| 2205 | if ( this.options.axis !== "y" && this.helper.css( "right" ) !== "auto" ) { | ||
| 2206 | this.helper.width( this.helper.width() ); | ||
| 2207 | this.helper.css( "right", "auto" ); | ||
| 2208 | } | ||
| 2209 | if ( this.options.axis !== "x" && this.helper.css( "bottom" ) !== "auto" ) { | ||
| 2210 | this.helper.height( this.helper.height() ); | ||
| 2211 | this.helper.css( "bottom", "auto" ); | ||
| 2212 | } | ||
| 2213 | }, | ||
| 2214 | |||
| 2215 | // From now on bulk stuff - mainly helpers | ||
| 2216 | |||
| 2217 | _trigger: function( type, event, ui ) { | ||
| 2218 | ui = ui || this._uiHash(); | ||
| 2219 | $.ui.plugin.call( this, type, [ event, ui, this ], true ); | ||
| 2220 | |||
| 2221 | // Absolute position and offset (see #6884 ) have to be recalculated after plugins | ||
| 2222 | if ( /^(drag|start|stop)/.test( type ) ) { | ||
| 2223 | this.positionAbs = this._convertPositionTo( "absolute" ); | ||
| 2224 | ui.offset = this.positionAbs; | ||
| 2225 | } | ||
| 2226 | return $.Widget.prototype._trigger.call( this, type, event, ui ); | ||
| 2227 | }, | ||
| 2228 | |||
| 2229 | plugins: {}, | ||
| 2230 | |||
| 2231 | _uiHash: function() { | ||
| 2232 | return { | ||
| 2233 | helper: this.helper, | ||
| 2234 | position: this.position, | ||
| 2235 | originalPosition: this.originalPosition, | ||
| 2236 | offset: this.positionAbs | ||
| 2237 | }; | ||
| 2238 | } | ||
| 2239 | |||
| 2240 | }); | ||
| 2241 | |||
| 2242 | $.ui.plugin.add( "draggable", "connectToSortable", { | ||
| 2243 | start: function( event, ui, draggable ) { | ||
| 2244 | var uiSortable = $.extend( {}, ui, { | ||
| 2245 | item: draggable.element | ||
| 2246 | }); | ||
| 2247 | |||
| 2248 | draggable.sortables = []; | ||
| 2249 | $( draggable.options.connectToSortable ).each(function() { | ||
| 2250 | var sortable = $( this ).sortable( "instance" ); | ||
| 2251 | |||
| 2252 | if ( sortable && !sortable.options.disabled ) { | ||
| 2253 | draggable.sortables.push( sortable ); | ||
| 2254 | |||
| 2255 | // refreshPositions is called at drag start to refresh the containerCache | ||
| 2256 | // which is used in drag. This ensures it's initialized and synchronized | ||
| 2257 | // with any changes that might have happened on the page since initialization. | ||
| 2258 | sortable.refreshPositions(); | ||
| 2259 | sortable._trigger("activate", event, uiSortable); | ||
| 2260 | } | ||
| 2261 | }); | ||
| 2262 | }, | ||
| 2263 | stop: function( event, ui, draggable ) { | ||
| 2264 | var uiSortable = $.extend( {}, ui, { | ||
| 2265 | item: draggable.element | ||
| 2266 | }); | ||
| 2267 | |||
| 2268 | draggable.cancelHelperRemoval = false; | ||
| 2269 | |||
| 2270 | $.each( draggable.sortables, function() { | ||
| 2271 | var sortable = this; | ||
| 2272 | |||
| 2273 | if ( sortable.isOver ) { | ||
| 2274 | sortable.isOver = 0; | ||
| 2275 | |||
| 2276 | // Allow this sortable to handle removing the helper | ||
| 2277 | draggable.cancelHelperRemoval = true; | ||
| 2278 | sortable.cancelHelperRemoval = false; | ||
| 2279 | |||
| 2280 | // Use _storedCSS To restore properties in the sortable, | ||
| 2281 | // as this also handles revert (#9675) since the draggable | ||
| 2282 | // may have modified them in unexpected ways (#8809) | ||
| 2283 | sortable._storedCSS = { | ||
| 2284 | position: sortable.placeholder.css( "position" ), | ||
| 2285 | top: sortable.placeholder.css( "top" ), | ||
| 2286 | left: sortable.placeholder.css( "left" ) | ||
| 2287 | }; | ||
| 2288 | |||
| 2289 | sortable._mouseStop(event); | ||
| 2290 | |||
| 2291 | // Once drag has ended, the sortable should return to using | ||
| 2292 | // its original helper, not the shared helper from draggable | ||
| 2293 | sortable.options.helper = sortable.options._helper; | ||
| 2294 | } else { | ||
| 2295 | // Prevent this Sortable from removing the helper. | ||
| 2296 | // However, don't set the draggable to remove the helper | ||
| 2297 | // either as another connected Sortable may yet handle the removal. | ||
| 2298 | sortable.cancelHelperRemoval = true; | ||
| 2299 | |||
| 2300 | sortable._trigger( "deactivate", event, uiSortable ); | ||
| 2301 | } | ||
| 2302 | }); | ||
| 2303 | }, | ||
| 2304 | drag: function( event, ui, draggable ) { | ||
| 2305 | $.each( draggable.sortables, function() { | ||
| 2306 | var innermostIntersecting = false, | ||
| 2307 | sortable = this; | ||
| 2308 | |||
| 2309 | // Copy over variables that sortable's _intersectsWith uses | ||
| 2310 | sortable.positionAbs = draggable.positionAbs; | ||
| 2311 | sortable.helperProportions = draggable.helperProportions; | ||
| 2312 | sortable.offset.click = draggable.offset.click; | ||
| 2313 | |||
| 2314 | if ( sortable._intersectsWith( sortable.containerCache ) ) { | ||
| 2315 | innermostIntersecting = true; | ||
| 2316 | |||
| 2317 | $.each( draggable.sortables, function() { | ||
| 2318 | // Copy over variables that sortable's _intersectsWith uses | ||
| 2319 | this.positionAbs = draggable.positionAbs; | ||
| 2320 | this.helperProportions = draggable.helperProportions; | ||
| 2321 | this.offset.click = draggable.offset.click; | ||
| 2322 | |||
| 2323 | if ( this !== sortable && | ||
| 2324 | this._intersectsWith( this.containerCache ) && | ||
| 2325 | $.contains( sortable.element[ 0 ], this.element[ 0 ] ) ) { | ||
| 2326 | innermostIntersecting = false; | ||
| 2327 | } | ||
| 2328 | |||
| 2329 | return innermostIntersecting; | ||
| 2330 | }); | ||
| 2331 | } | ||
| 2332 | |||
| 2333 | if ( innermostIntersecting ) { | ||
| 2334 | // If it intersects, we use a little isOver variable and set it once, | ||
| 2335 | // so that the move-in stuff gets fired only once. | ||
| 2336 | if ( !sortable.isOver ) { | ||
| 2337 | sortable.isOver = 1; | ||
| 2338 | |||
| 2339 | // Store draggable's parent in case we need to reappend to it later. | ||
| 2340 | draggable._parent = ui.helper.parent(); | ||
| 2341 | |||
| 2342 | sortable.currentItem = ui.helper | ||
| 2343 | .appendTo( sortable.element ) | ||
| 2344 | .data( "ui-sortable-item", true ); | ||
| 2345 | |||
| 2346 | // Store helper option to later restore it | ||
| 2347 | sortable.options._helper = sortable.options.helper; | ||
| 2348 | |||
| 2349 | sortable.options.helper = function() { | ||
| 2350 | return ui.helper[ 0 ]; | ||
| 2351 | }; | ||
| 2352 | |||
| 2353 | // Fire the start events of the sortable with our passed browser event, | ||
| 2354 | // and our own helper (so it doesn't create a new one) | ||
| 2355 | event.target = sortable.currentItem[ 0 ]; | ||
| 2356 | sortable._mouseCapture( event, true ); | ||
| 2357 | sortable._mouseStart( event, true, true ); | ||
| 2358 | |||
| 2359 | // Because the browser event is way off the new appended portlet, | ||
| 2360 | // modify necessary variables to reflect the changes | ||
| 2361 | sortable.offset.click.top = draggable.offset.click.top; | ||
| 2362 | sortable.offset.click.left = draggable.offset.click.left; | ||
| 2363 | sortable.offset.parent.left -= draggable.offset.parent.left - | ||
| 2364 | sortable.offset.parent.left; | ||
| 2365 | sortable.offset.parent.top -= draggable.offset.parent.top - | ||
| 2366 | sortable.offset.parent.top; | ||
| 2367 | |||
| 2368 | draggable._trigger( "toSortable", event ); | ||
| 2369 | |||
| 2370 | // Inform draggable that the helper is in a valid drop zone, | ||
| 2371 | // used solely in the revert option to handle "valid/invalid". | ||
| 2372 | draggable.dropped = sortable.element; | ||
| 2373 | |||
| 2374 | // Need to refreshPositions of all sortables in the case that | ||
| 2375 | // adding to one sortable changes the location of the other sortables (#9675) | ||
| 2376 | $.each( draggable.sortables, function() { | ||
| 2377 | this.refreshPositions(); | ||
| 2378 | }); | ||
| 2379 | |||
| 2380 | // hack so receive/update callbacks work (mostly) | ||
| 2381 | draggable.currentItem = draggable.element; | ||
| 2382 | sortable.fromOutside = draggable; | ||
| 2383 | } | ||
| 2384 | |||
| 2385 | if ( sortable.currentItem ) { | ||
| 2386 | sortable._mouseDrag( event ); | ||
| 2387 | // Copy the sortable's position because the draggable's can potentially reflect | ||
| 2388 | // a relative position, while sortable is always absolute, which the dragged | ||
| 2389 | // element has now become. (#8809) | ||
| 2390 | ui.position = sortable.position; | ||
| 2391 | } | ||
| 2392 | } else { | ||
| 2393 | // If it doesn't intersect with the sortable, and it intersected before, | ||
| 2394 | // we fake the drag stop of the sortable, but make sure it doesn't remove | ||
| 2395 | // the helper by using cancelHelperRemoval. | ||
| 2396 | if ( sortable.isOver ) { | ||
| 2397 | |||
| 2398 | sortable.isOver = 0; | ||
| 2399 | sortable.cancelHelperRemoval = true; | ||
| 2400 | |||
| 2401 | // Calling sortable's mouseStop would trigger a revert, | ||
| 2402 | // so revert must be temporarily false until after mouseStop is called. | ||
| 2403 | sortable.options._revert = sortable.options.revert; | ||
| 2404 | sortable.options.revert = false; | ||
| 2405 | |||
| 2406 | sortable._trigger( "out", event, sortable._uiHash( sortable ) ); | ||
| 2407 | sortable._mouseStop( event, true ); | ||
| 2408 | |||
| 2409 | // restore sortable behaviors that were modfied | ||
| 2410 | // when the draggable entered the sortable area (#9481) | ||
| 2411 | sortable.options.revert = sortable.options._revert; | ||
| 2412 | sortable.options.helper = sortable.options._helper; | ||
| 2413 | |||
| 2414 | if ( sortable.placeholder ) { | ||
| 2415 | sortable.placeholder.remove(); | ||
| 2416 | } | ||
| 2417 | |||
| 2418 | // Restore and recalculate the draggable's offset considering the sortable | ||
| 2419 | // may have modified them in unexpected ways. (#8809, #10669) | ||
| 2420 | ui.helper.appendTo( draggable._parent ); | ||
| 2421 | draggable._refreshOffsets( event ); | ||
| 2422 | ui.position = draggable._generatePosition( event, true ); | ||
| 2423 | |||
| 2424 | draggable._trigger( "fromSortable", event ); | ||
| 2425 | |||
| 2426 | // Inform draggable that the helper is no longer in a valid drop zone | ||
| 2427 | draggable.dropped = false; | ||
| 2428 | |||
| 2429 | // Need to refreshPositions of all sortables just in case removing | ||
| 2430 | // from one sortable changes the location of other sortables (#9675) | ||
| 2431 | $.each( draggable.sortables, function() { | ||
| 2432 | this.refreshPositions(); | ||
| 2433 | }); | ||
| 2434 | } | ||
| 2435 | } | ||
| 2436 | }); | ||
| 2437 | } | ||
| 2438 | }); | ||
| 2439 | |||
| 2440 | $.ui.plugin.add("draggable", "cursor", { | ||
| 2441 | start: function( event, ui, instance ) { | ||
| 2442 | var t = $( "body" ), | ||
| 2443 | o = instance.options; | ||
| 2444 | |||
| 2445 | if (t.css("cursor")) { | ||
| 2446 | o._cursor = t.css("cursor"); | ||
| 2447 | } | ||
| 2448 | t.css("cursor", o.cursor); | ||
| 2449 | }, | ||
| 2450 | stop: function( event, ui, instance ) { | ||
| 2451 | var o = instance.options; | ||
| 2452 | if (o._cursor) { | ||
| 2453 | $("body").css("cursor", o._cursor); | ||
| 2454 | } | ||
| 2455 | } | ||
| 2456 | }); | ||
| 2457 | |||
| 2458 | $.ui.plugin.add("draggable", "opacity", { | ||
| 2459 | start: function( event, ui, instance ) { | ||
| 2460 | var t = $( ui.helper ), | ||
| 2461 | o = instance.options; | ||
| 2462 | if (t.css("opacity")) { | ||
| 2463 | o._opacity = t.css("opacity"); | ||
| 2464 | } | ||
| 2465 | t.css("opacity", o.opacity); | ||
| 2466 | }, | ||
| 2467 | stop: function( event, ui, instance ) { | ||
| 2468 | var o = instance.options; | ||
| 2469 | if (o._opacity) { | ||
| 2470 | $(ui.helper).css("opacity", o._opacity); | ||
| 2471 | } | ||
| 2472 | } | ||
| 2473 | }); | ||
| 2474 | |||
| 2475 | $.ui.plugin.add("draggable", "scroll", { | ||
| 2476 | start: function( event, ui, i ) { | ||
| 2477 | if ( !i.scrollParentNotHidden ) { | ||
| 2478 | i.scrollParentNotHidden = i.helper.scrollParent( false ); | ||
| 2479 | } | ||
| 2480 | |||
| 2481 | if ( i.scrollParentNotHidden[ 0 ] !== i.document[ 0 ] && i.scrollParentNotHidden[ 0 ].tagName !== "HTML" ) { | ||
| 2482 | i.overflowOffset = i.scrollParentNotHidden.offset(); | ||
| 2483 | } | ||
| 2484 | }, | ||
| 2485 | drag: function( event, ui, i ) { | ||
| 2486 | |||
| 2487 | var o = i.options, | ||
| 2488 | scrolled = false, | ||
| 2489 | scrollParent = i.scrollParentNotHidden[ 0 ], | ||
| 2490 | document = i.document[ 0 ]; | ||
| 2491 | |||
| 2492 | if ( scrollParent !== document && scrollParent.tagName !== "HTML" ) { | ||
| 2493 | if ( !o.axis || o.axis !== "x" ) { | ||
| 2494 | if ( ( i.overflowOffset.top + scrollParent.offsetHeight ) - event.pageY < o.scrollSensitivity ) { | ||
| 2495 | scrollParent.scrollTop = scrolled = scrollParent.scrollTop + o.scrollSpeed; | ||
| 2496 | } else if ( event.pageY - i.overflowOffset.top < o.scrollSensitivity ) { | ||
| 2497 | scrollParent.scrollTop = scrolled = scrollParent.scrollTop - o.scrollSpeed; | ||
| 2498 | } | ||
| 2499 | } | ||
| 2500 | |||
| 2501 | if ( !o.axis || o.axis !== "y" ) { | ||
| 2502 | if ( ( i.overflowOffset.left + scrollParent.offsetWidth ) - event.pageX < o.scrollSensitivity ) { | ||
| 2503 | scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft + o.scrollSpeed; | ||
| 2504 | } else if ( event.pageX - i.overflowOffset.left < o.scrollSensitivity ) { | ||
| 2505 | scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft - o.scrollSpeed; | ||
| 2506 | } | ||
| 2507 | } | ||
| 2508 | |||
| 2509 | } else { | ||
| 2510 | |||
| 2511 | if (!o.axis || o.axis !== "x") { | ||
| 2512 | if (event.pageY - $(document).scrollTop() < o.scrollSensitivity) { | ||
| 2513 | scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed); | ||
| 2514 | } else if ($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) { | ||
| 2515 | scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed); | ||
| 2516 | } | ||
| 2517 | } | ||
| 2518 | |||
| 2519 | if (!o.axis || o.axis !== "y") { | ||
| 2520 | if (event.pageX - $(document).scrollLeft() < o.scrollSensitivity) { | ||
| 2521 | scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed); | ||
| 2522 | } else if ($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) { | ||
| 2523 | scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed); | ||
| 2524 | } | ||
| 2525 | } | ||
| 2526 | |||
| 2527 | } | ||
| 2528 | |||
| 2529 | if (scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) { | ||
| 2530 | $.ui.ddmanager.prepareOffsets(i, event); | ||
| 2531 | } | ||
| 2532 | |||
| 2533 | } | ||
| 2534 | }); | ||
| 2535 | |||
| 2536 | $.ui.plugin.add("draggable", "snap", { | ||
| 2537 | start: function( event, ui, i ) { | ||
| 2538 | |||
| 2539 | var o = i.options; | ||
| 2540 | |||
| 2541 | i.snapElements = []; | ||
| 2542 | |||
| 2543 | $(o.snap.constructor !== String ? ( o.snap.items || ":data(ui-draggable)" ) : o.snap).each(function() { | ||
| 2544 | var $t = $(this), | ||
| 2545 | $o = $t.offset(); | ||
| 2546 | if (this !== i.element[0]) { | ||
| 2547 | i.snapElements.push({ | ||
| 2548 | item: this, | ||
| 2549 | width: $t.outerWidth(), height: $t.outerHeight(), | ||
| 2550 | top: $o.top, left: $o.left | ||
| 2551 | }); | ||
| 2552 | } | ||
| 2553 | }); | ||
| 2554 | |||
| 2555 | }, | ||
| 2556 | drag: function( event, ui, inst ) { | ||
| 2557 | |||
| 2558 | var ts, bs, ls, rs, l, r, t, b, i, first, | ||
| 2559 | o = inst.options, | ||
| 2560 | d = o.snapTolerance, | ||
| 2561 | x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width, | ||
| 2562 | y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height; | ||
| 2563 | |||
| 2564 | for (i = inst.snapElements.length - 1; i >= 0; i--){ | ||
| 2565 | |||
| 2566 | l = inst.snapElements[i].left - inst.margins.left; | ||
| 2567 | r = l + inst.snapElements[i].width; | ||
| 2568 | t = inst.snapElements[i].top - inst.margins.top; | ||
| 2569 | b = t + inst.snapElements[i].height; | ||
| 2570 | |||
| 2571 | if ( x2 < l - d || x1 > r + d || y2 < t - d || y1 > b + d || !$.contains( inst.snapElements[ i ].item.ownerDocument, inst.snapElements[ i ].item ) ) { | ||
| 2572 | if (inst.snapElements[i].snapping) { | ||
| 2573 | (inst.options.snap.release && inst.options.snap.release.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item }))); | ||
| 2574 | } | ||
| 2575 | inst.snapElements[i].snapping = false; | ||
| 2576 | continue; | ||
| 2577 | } | ||
| 2578 | |||
| 2579 | if (o.snapMode !== "inner") { | ||
| 2580 | ts = Math.abs(t - y2) <= d; | ||
| 2581 | bs = Math.abs(b - y1) <= d; | ||
| 2582 | ls = Math.abs(l - x2) <= d; | ||
| 2583 | rs = Math.abs(r - x1) <= d; | ||
| 2584 | if (ts) { | ||
| 2585 | ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top; | ||
| 2586 | } | ||
| 2587 | if (bs) { | ||
| 2588 | ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top; | ||
| 2589 | } | ||
| 2590 | if (ls) { | ||
| 2591 | ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left; | ||
| 2592 | } | ||
| 2593 | if (rs) { | ||
| 2594 | ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left; | ||
| 2595 | } | ||
| 2596 | } | ||
| 2597 | |||
| 2598 | first = (ts || bs || ls || rs); | ||
| 2599 | |||
| 2600 | if (o.snapMode !== "outer") { | ||
| 2601 | ts = Math.abs(t - y1) <= d; | ||
| 2602 | bs = Math.abs(b - y2) <= d; | ||
| 2603 | ls = Math.abs(l - x1) <= d; | ||
| 2604 | rs = Math.abs(r - x2) <= d; | ||
| 2605 | if (ts) { | ||
| 2606 | ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top; | ||
| 2607 | } | ||
| 2608 | if (bs) { | ||
| 2609 | ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top; | ||
| 2610 | } | ||
| 2611 | if (ls) { | ||
| 2612 | ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left; | ||
| 2613 | } | ||
| 2614 | if (rs) { | ||
| 2615 | ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left; | ||
| 2616 | } | ||
| 2617 | } | ||
| 2618 | |||
| 2619 | if (!inst.snapElements[i].snapping && (ts || bs || ls || rs || first)) { | ||
| 2620 | (inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item }))); | ||
| 2621 | } | ||
| 2622 | inst.snapElements[i].snapping = (ts || bs || ls || rs || first); | ||
| 2623 | |||
| 2624 | } | ||
| 2625 | |||
| 2626 | } | ||
| 2627 | }); | ||
| 2628 | |||
| 2629 | $.ui.plugin.add("draggable", "stack", { | ||
| 2630 | start: function( event, ui, instance ) { | ||
| 2631 | var min, | ||
| 2632 | o = instance.options, | ||
| 2633 | group = $.makeArray($(o.stack)).sort(function(a, b) { | ||
| 2634 | return (parseInt($(a).css("zIndex"), 10) || 0) - (parseInt($(b).css("zIndex"), 10) || 0); | ||
| 2635 | }); | ||
| 2636 | |||
| 2637 | if (!group.length) { return; } | ||
| 2638 | |||
| 2639 | min = parseInt($(group[0]).css("zIndex"), 10) || 0; | ||
| 2640 | $(group).each(function(i) { | ||
| 2641 | $(this).css("zIndex", min + i); | ||
| 2642 | }); | ||
| 2643 | this.css("zIndex", (min + group.length)); | ||
| 2644 | } | ||
| 2645 | }); | ||
| 2646 | |||
| 2647 | $.ui.plugin.add("draggable", "zIndex", { | ||
| 2648 | start: function( event, ui, instance ) { | ||
| 2649 | var t = $( ui.helper ), | ||
| 2650 | o = instance.options; | ||
| 2651 | |||
| 2652 | if (t.css("zIndex")) { | ||
| 2653 | o._zIndex = t.css("zIndex"); | ||
| 2654 | } | ||
| 2655 | t.css("zIndex", o.zIndex); | ||
| 2656 | }, | ||
| 2657 | stop: function( event, ui, instance ) { | ||
| 2658 | var o = instance.options; | ||
| 2659 | |||
| 2660 | if (o._zIndex) { | ||
| 2661 | $(ui.helper).css("zIndex", o._zIndex); | ||
| 2662 | } | ||
| 2663 | } | ||
| 2664 | }); | ||
| 2665 | |||
| 2666 | var draggable = $.ui.draggable; | ||
| 2667 | |||
| 2668 | |||
| 2669 | /*! | ||
| 2670 | * jQuery UI Droppable 1.11.4 | ||
| 2671 | * http://jqueryui.com | ||
| 2672 | * | ||
| 2673 | * Copyright jQuery Foundation and other contributors | ||
| 2674 | * Released under the MIT license. | ||
| 2675 | * http://jquery.org/license | ||
| 2676 | * | ||
| 2677 | * http://api.jqueryui.com/droppable/ | ||
| 2678 | */ | ||
| 2679 | |||
| 2680 | |||
| 2681 | $.widget( "ui.droppable", { | ||
| 2682 | version: "1.11.4", | ||
| 2683 | widgetEventPrefix: "drop", | ||
| 2684 | options: { | ||
| 2685 | accept: "*", | ||
| 2686 | activeClass: false, | ||
| 2687 | addClasses: true, | ||
| 2688 | greedy: false, | ||
| 2689 | hoverClass: false, | ||
| 2690 | scope: "default", | ||
| 2691 | tolerance: "intersect", | ||
| 2692 | |||
| 2693 | // callbacks | ||
| 2694 | activate: null, | ||
| 2695 | deactivate: null, | ||
| 2696 | drop: null, | ||
| 2697 | out: null, | ||
| 2698 | over: null | ||
| 2699 | }, | ||
| 2700 | _create: function() { | ||
| 2701 | |||
| 2702 | var proportions, | ||
| 2703 | o = this.options, | ||
| 2704 | accept = o.accept; | ||
| 2705 | |||
| 2706 | this.isover = false; | ||
| 2707 | this.isout = true; | ||
| 2708 | |||
| 2709 | this.accept = $.isFunction( accept ) ? accept : function( d ) { | ||
| 2710 | return d.is( accept ); | ||
| 2711 | }; | ||
| 2712 | |||
| 2713 | this.proportions = function( /* valueToWrite */ ) { | ||
| 2714 | if ( arguments.length ) { | ||
| 2715 | // Store the droppable's proportions | ||
| 2716 | proportions = arguments[ 0 ]; | ||
| 2717 | } else { | ||
| 2718 | // Retrieve or derive the droppable's proportions | ||
| 2719 | return proportions ? | ||
| 2720 | proportions : | ||
| 2721 | proportions = { | ||
| 2722 | width: this.element[ 0 ].offsetWidth, | ||
| 2723 | height: this.element[ 0 ].offsetHeight | ||
| 2724 | }; | ||
| 2725 | } | ||
| 2726 | }; | ||
| 2727 | |||
| 2728 | this._addToManager( o.scope ); | ||
| 2729 | |||
| 2730 | o.addClasses && this.element.addClass( "ui-droppable" ); | ||
| 2731 | |||
| 2732 | }, | ||
| 2733 | |||
| 2734 | _addToManager: function( scope ) { | ||
| 2735 | // Add the reference and positions to the manager | ||
| 2736 | $.ui.ddmanager.droppables[ scope ] = $.ui.ddmanager.droppables[ scope ] || []; | ||
| 2737 | $.ui.ddmanager.droppables[ scope ].push( this ); | ||
| 2738 | }, | ||
| 2739 | |||
| 2740 | _splice: function( drop ) { | ||
| 2741 | var i = 0; | ||
| 2742 | for ( ; i < drop.length; i++ ) { | ||
| 2743 | if ( drop[ i ] === this ) { | ||
| 2744 | drop.splice( i, 1 ); | ||
| 2745 | } | ||
| 2746 | } | ||
| 2747 | }, | ||
| 2748 | |||
| 2749 | _destroy: function() { | ||
| 2750 | var drop = $.ui.ddmanager.droppables[ this.options.scope ]; | ||
| 2751 | |||
| 2752 | this._splice( drop ); | ||
| 2753 | |||
| 2754 | this.element.removeClass( "ui-droppable ui-droppable-disabled" ); | ||
| 2755 | }, | ||
| 2756 | |||
| 2757 | _setOption: function( key, value ) { | ||
| 2758 | |||
| 2759 | if ( key === "accept" ) { | ||
| 2760 | this.accept = $.isFunction( value ) ? value : function( d ) { | ||
| 2761 | return d.is( value ); | ||
| 2762 | }; | ||
| 2763 | } else if ( key === "scope" ) { | ||
| 2764 | var drop = $.ui.ddmanager.droppables[ this.options.scope ]; | ||
| 2765 | |||
| 2766 | this._splice( drop ); | ||
| 2767 | this._addToManager( value ); | ||
| 2768 | } | ||
| 2769 | |||
| 2770 | this._super( key, value ); | ||
| 2771 | }, | ||
| 2772 | |||
| 2773 | _activate: function( event ) { | ||
| 2774 | var draggable = $.ui.ddmanager.current; | ||
| 2775 | if ( this.options.activeClass ) { | ||
| 2776 | this.element.addClass( this.options.activeClass ); | ||
| 2777 | } | ||
| 2778 | if ( draggable ){ | ||
| 2779 | this._trigger( "activate", event, this.ui( draggable ) ); | ||
| 2780 | } | ||
| 2781 | }, | ||
| 2782 | |||
| 2783 | _deactivate: function( event ) { | ||
| 2784 | var draggable = $.ui.ddmanager.current; | ||
| 2785 | if ( this.options.activeClass ) { | ||
| 2786 | this.element.removeClass( this.options.activeClass ); | ||
| 2787 | } | ||
| 2788 | if ( draggable ){ | ||
| 2789 | this._trigger( "deactivate", event, this.ui( draggable ) ); | ||
| 2790 | } | ||
| 2791 | }, | ||
| 2792 | |||
| 2793 | _over: function( event ) { | ||
| 2794 | |||
| 2795 | var draggable = $.ui.ddmanager.current; | ||
| 2796 | |||
| 2797 | // Bail if draggable and droppable are same element | ||
| 2798 | if ( !draggable || ( draggable.currentItem || draggable.element )[ 0 ] === this.element[ 0 ] ) { | ||
| 2799 | return; | ||
| 2800 | } | ||
| 2801 | |||
| 2802 | if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem || draggable.element ) ) ) { | ||
| 2803 | if ( this.options.hoverClass ) { | ||
| 2804 | this.element.addClass( this.options.hoverClass ); | ||
| 2805 | } | ||
| 2806 | this._trigger( "over", event, this.ui( draggable ) ); | ||
| 2807 | } | ||
| 2808 | |||
| 2809 | }, | ||
| 2810 | |||
| 2811 | _out: function( event ) { | ||
| 2812 | |||
| 2813 | var draggable = $.ui.ddmanager.current; | ||
| 2814 | |||
| 2815 | // Bail if draggable and droppable are same element | ||
| 2816 | if ( !draggable || ( draggable.currentItem || draggable.element )[ 0 ] === this.element[ 0 ] ) { | ||
| 2817 | return; | ||
| 2818 | } | ||
| 2819 | |||
| 2820 | if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem || draggable.element ) ) ) { | ||
| 2821 | if ( this.options.hoverClass ) { | ||
| 2822 | this.element.removeClass( this.options.hoverClass ); | ||
| 2823 | } | ||
| 2824 | this._trigger( "out", event, this.ui( draggable ) ); | ||
| 2825 | } | ||
| 2826 | |||
| 2827 | }, | ||
| 2828 | |||
| 2829 | _drop: function( event, custom ) { | ||
| 2830 | |||
| 2831 | var draggable = custom || $.ui.ddmanager.current, | ||
| 2832 | childrenIntersection = false; | ||
| 2833 | |||
| 2834 | // Bail if draggable and droppable are same element | ||
| 2835 | if ( !draggable || ( draggable.currentItem || draggable.element )[ 0 ] === this.element[ 0 ] ) { | ||
| 2836 | return false; | ||
| 2837 | } | ||
| 2838 | |||
| 2839 | this.element.find( ":data(ui-droppable)" ).not( ".ui-draggable-dragging" ).each(function() { | ||
| 2840 | var inst = $( this ).droppable( "instance" ); | ||
| 2841 | if ( | ||
| 2842 | inst.options.greedy && | ||
| 2843 | !inst.options.disabled && | ||
| 2844 | inst.options.scope === draggable.options.scope && | ||
| 2845 | inst.accept.call( inst.element[ 0 ], ( draggable.currentItem || draggable.element ) ) && | ||
| 2846 | $.ui.intersect( draggable, $.extend( inst, { offset: inst.element.offset() } ), inst.options.tolerance, event ) | ||
| 2847 | ) { childrenIntersection = true; return false; } | ||
| 2848 | }); | ||
| 2849 | if ( childrenIntersection ) { | ||
| 2850 | return false; | ||
| 2851 | } | ||
| 2852 | |||
| 2853 | if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem || draggable.element ) ) ) { | ||
| 2854 | if ( this.options.activeClass ) { | ||
| 2855 | this.element.removeClass( this.options.activeClass ); | ||
| 2856 | } | ||
| 2857 | if ( this.options.hoverClass ) { | ||
| 2858 | this.element.removeClass( this.options.hoverClass ); | ||
| 2859 | } | ||
| 2860 | this._trigger( "drop", event, this.ui( draggable ) ); | ||
| 2861 | return this.element; | ||
| 2862 | } | ||
| 2863 | |||
| 2864 | return false; | ||
| 2865 | |||
| 2866 | }, | ||
| 2867 | |||
| 2868 | ui: function( c ) { | ||
| 2869 | return { | ||
| 2870 | draggable: ( c.currentItem || c.element ), | ||
| 2871 | helper: c.helper, | ||
| 2872 | position: c.position, | ||
| 2873 | offset: c.positionAbs | ||
| 2874 | }; | ||
| 2875 | } | ||
| 2876 | |||
| 2877 | }); | ||
| 2878 | |||
| 2879 | $.ui.intersect = (function() { | ||
| 2880 | function isOverAxis( x, reference, size ) { | ||
| 2881 | return ( x >= reference ) && ( x < ( reference + size ) ); | ||
| 2882 | } | ||
| 2883 | |||
| 2884 | return function( draggable, droppable, toleranceMode, event ) { | ||
| 2885 | |||
| 2886 | if ( !droppable.offset ) { | ||
| 2887 | return false; | ||
| 2888 | } | ||
| 2889 | |||
| 2890 | var x1 = ( draggable.positionAbs || draggable.position.absolute ).left + draggable.margins.left, | ||
| 2891 | y1 = ( draggable.positionAbs || draggable.position.absolute ).top + draggable.margins.top, | ||
| 2892 | x2 = x1 + draggable.helperProportions.width, | ||
| 2893 | y2 = y1 + draggable.helperProportions.height, | ||
| 2894 | l = droppable.offset.left, | ||
| 2895 | t = droppable.offset.top, | ||
| 2896 | r = l + droppable.proportions().width, | ||
| 2897 | b = t + droppable.proportions().height; | ||
| 2898 | |||
| 2899 | switch ( toleranceMode ) { | ||
| 2900 | case "fit": | ||
| 2901 | return ( l <= x1 && x2 <= r && t <= y1 && y2 <= b ); | ||
| 2902 | case "intersect": | ||
| 2903 | return ( l < x1 + ( draggable.helperProportions.width / 2 ) && // Right Half | ||
| 2904 | x2 - ( draggable.helperProportions.width / 2 ) < r && // Left Half | ||
| 2905 | t < y1 + ( draggable.helperProportions.height / 2 ) && // Bottom Half | ||
| 2906 | y2 - ( draggable.helperProportions.height / 2 ) < b ); // Top Half | ||
| 2907 | case "pointer": | ||
| 2908 | return isOverAxis( event.pageY, t, droppable.proportions().height ) && isOverAxis( event.pageX, l, droppable.proportions().width ); | ||
| 2909 | case "touch": | ||
| 2910 | return ( | ||
| 2911 | ( y1 >= t && y1 <= b ) || // Top edge touching | ||
| 2912 | ( y2 >= t && y2 <= b ) || // Bottom edge touching | ||
| 2913 | ( y1 < t && y2 > b ) // Surrounded vertically | ||
| 2914 | ) && ( | ||
| 2915 | ( x1 >= l && x1 <= r ) || // Left edge touching | ||
| 2916 | ( x2 >= l && x2 <= r ) || // Right edge touching | ||
| 2917 | ( x1 < l && x2 > r ) // Surrounded horizontally | ||
| 2918 | ); | ||
| 2919 | default: | ||
| 2920 | return false; | ||
| 2921 | } | ||
| 2922 | }; | ||
| 2923 | })(); | ||
| 2924 | |||
| 2925 | /* | ||
| 2926 | This manager tracks offsets of draggables and droppables | ||
| 2927 | */ | ||
| 2928 | $.ui.ddmanager = { | ||
| 2929 | current: null, | ||
| 2930 | droppables: { "default": [] }, | ||
| 2931 | prepareOffsets: function( t, event ) { | ||
| 2932 | |||
| 2933 | var i, j, | ||
| 2934 | m = $.ui.ddmanager.droppables[ t.options.scope ] || [], | ||
| 2935 | type = event ? event.type : null, // workaround for #2317 | ||
| 2936 | list = ( t.currentItem || t.element ).find( ":data(ui-droppable)" ).addBack(); | ||
| 2937 | |||
| 2938 | droppablesLoop: for ( i = 0; i < m.length; i++ ) { | ||
| 2939 | |||
| 2940 | // No disabled and non-accepted | ||
| 2941 | if ( m[ i ].options.disabled || ( t && !m[ i ].accept.call( m[ i ].element[ 0 ], ( t.currentItem || t.element ) ) ) ) { | ||
| 2942 | continue; | ||
| 2943 | } | ||
| 2944 | |||
| 2945 | // Filter out elements in the current dragged item | ||
| 2946 | for ( j = 0; j < list.length; j++ ) { | ||
| 2947 | if ( list[ j ] === m[ i ].element[ 0 ] ) { | ||
| 2948 | m[ i ].proportions().height = 0; | ||
| 2949 | continue droppablesLoop; | ||
| 2950 | } | ||
| 2951 | } | ||
| 2952 | |||
| 2953 | m[ i ].visible = m[ i ].element.css( "display" ) !== "none"; | ||
| 2954 | if ( !m[ i ].visible ) { | ||
| 2955 | continue; | ||
| 2956 | } | ||
| 2957 | |||
| 2958 | // Activate the droppable if used directly from draggables | ||
| 2959 | if ( type === "mousedown" ) { | ||
| 2960 | m[ i ]._activate.call( m[ i ], event ); | ||
| 2961 | } | ||
| 2962 | |||
| 2963 | m[ i ].offset = m[ i ].element.offset(); | ||
| 2964 | m[ i ].proportions({ width: m[ i ].element[ 0 ].offsetWidth, height: m[ i ].element[ 0 ].offsetHeight }); | ||
| 2965 | |||
| 2966 | } | ||
| 2967 | |||
| 2968 | }, | ||
| 2969 | drop: function( draggable, event ) { | ||
| 2970 | |||
| 2971 | var dropped = false; | ||
| 2972 | // Create a copy of the droppables in case the list changes during the drop (#9116) | ||
| 2973 | $.each( ( $.ui.ddmanager.droppables[ draggable.options.scope ] || [] ).slice(), function() { | ||
| 2974 | |||
| 2975 | if ( !this.options ) { | ||
| 2976 | return; | ||
| 2977 | } | ||
| 2978 | if ( !this.options.disabled && this.visible && $.ui.intersect( draggable, this, this.options.tolerance, event ) ) { | ||
| 2979 | dropped = this._drop.call( this, event ) || dropped; | ||
| 2980 | } | ||
| 2981 | |||
| 2982 | if ( !this.options.disabled && this.visible && this.accept.call( this.element[ 0 ], ( draggable.currentItem || draggable.element ) ) ) { | ||
| 2983 | this.isout = true; | ||
| 2984 | this.isover = false; | ||
| 2985 | this._deactivate.call( this, event ); | ||
| 2986 | } | ||
| 2987 | |||
| 2988 | }); | ||
| 2989 | return dropped; | ||
| 2990 | |||
| 2991 | }, | ||
| 2992 | dragStart: function( draggable, event ) { | ||
| 2993 | // Listen for scrolling so that if the dragging causes scrolling the position of the droppables can be recalculated (see #5003) | ||
| 2994 | draggable.element.parentsUntil( "body" ).bind( "scroll.droppable", function() { | ||
| 2995 | if ( !draggable.options.refreshPositions ) { | ||
| 2996 | $.ui.ddmanager.prepareOffsets( draggable, event ); | ||
| 2997 | } | ||
| 2998 | }); | ||
| 2999 | }, | ||
| 3000 | drag: function( draggable, event ) { | ||
| 3001 | |||
| 3002 | // If you have a highly dynamic page, you might try this option. It renders positions every time you move the mouse. | ||
| 3003 | if ( draggable.options.refreshPositions ) { | ||
| 3004 | $.ui.ddmanager.prepareOffsets( draggable, event ); | ||
| 3005 | } | ||
| 3006 | |||
| 3007 | // Run through all droppables and check their positions based on specific tolerance options | ||
| 3008 | $.each( $.ui.ddmanager.droppables[ draggable.options.scope ] || [], function() { | ||
| 3009 | |||
| 3010 | if ( this.options.disabled || this.greedyChild || !this.visible ) { | ||
| 3011 | return; | ||
| 3012 | } | ||
| 3013 | |||
| 3014 | var parentInstance, scope, parent, | ||
| 3015 | intersects = $.ui.intersect( draggable, this, this.options.tolerance, event ), | ||
| 3016 | c = !intersects && this.isover ? "isout" : ( intersects && !this.isover ? "isover" : null ); | ||
| 3017 | if ( !c ) { | ||
| 3018 | return; | ||
| 3019 | } | ||
| 3020 | |||
| 3021 | if ( this.options.greedy ) { | ||
| 3022 | // find droppable parents with same scope | ||
| 3023 | scope = this.options.scope; | ||
| 3024 | parent = this.element.parents( ":data(ui-droppable)" ).filter(function() { | ||
| 3025 | return $( this ).droppable( "instance" ).options.scope === scope; | ||
| 3026 | }); | ||
| 3027 | |||
| 3028 | if ( parent.length ) { | ||
| 3029 | parentInstance = $( parent[ 0 ] ).droppable( "instance" ); | ||
| 3030 | parentInstance.greedyChild = ( c === "isover" ); | ||
| 3031 | } | ||
| 3032 | } | ||
| 3033 | |||
| 3034 | // we just moved into a greedy child | ||
| 3035 | if ( parentInstance && c === "isover" ) { | ||
| 3036 | parentInstance.isover = false; | ||
| 3037 | parentInstance.isout = true; | ||
| 3038 | parentInstance._out.call( parentInstance, event ); | ||
| 3039 | } | ||
| 3040 | |||
| 3041 | this[ c ] = true; | ||
| 3042 | this[c === "isout" ? "isover" : "isout"] = false; | ||
| 3043 | this[c === "isover" ? "_over" : "_out"].call( this, event ); | ||
| 3044 | |||
| 3045 | // we just moved out of a greedy child | ||
| 3046 | if ( parentInstance && c === "isout" ) { | ||
| 3047 | parentInstance.isout = false; | ||
| 3048 | parentInstance.isover = true; | ||
| 3049 | parentInstance._over.call( parentInstance, event ); | ||
| 3050 | } | ||
| 3051 | }); | ||
| 3052 | |||
| 3053 | }, | ||
| 3054 | dragStop: function( draggable, event ) { | ||
| 3055 | draggable.element.parentsUntil( "body" ).unbind( "scroll.droppable" ); | ||
| 3056 | // Call prepareOffsets one final time since IE does not fire return scroll events when overflow was caused by drag (see #5003) | ||
| 3057 | if ( !draggable.options.refreshPositions ) { | ||
| 3058 | $.ui.ddmanager.prepareOffsets( draggable, event ); | ||
| 3059 | } | ||
| 3060 | } | ||
| 3061 | }; | ||
| 3062 | |||
| 3063 | var droppable = $.ui.droppable; | ||
| 3064 | |||
| 3065 | |||
| 3066 | /*! | ||
| 3067 | * jQuery UI Resizable 1.11.4 | ||
| 3068 | * http://jqueryui.com | ||
| 3069 | * | ||
| 3070 | * Copyright jQuery Foundation and other contributors | ||
| 3071 | * Released under the MIT license. | ||
| 3072 | * http://jquery.org/license | ||
| 3073 | * | ||
| 3074 | * http://api.jqueryui.com/resizable/ | ||
| 3075 | */ | ||
| 3076 | |||
| 3077 | |||
| 3078 | $.widget("ui.resizable", $.ui.mouse, { | ||
| 3079 | version: "1.11.4", | ||
| 3080 | widgetEventPrefix: "resize", | ||
| 3081 | options: { | ||
| 3082 | alsoResize: false, | ||
| 3083 | animate: false, | ||
| 3084 | animateDuration: "slow", | ||
| 3085 | animateEasing: "swing", | ||
| 3086 | aspectRatio: false, | ||
| 3087 | autoHide: false, | ||
| 3088 | containment: false, | ||
| 3089 | ghost: false, | ||
| 3090 | grid: false, | ||
| 3091 | handles: "e,s,se", | ||
| 3092 | helper: false, | ||
| 3093 | maxHeight: null, | ||
| 3094 | maxWidth: null, | ||
| 3095 | minHeight: 10, | ||
| 3096 | minWidth: 10, | ||
| 3097 | // See #7960 | ||
| 3098 | zIndex: 90, | ||
| 3099 | |||
| 3100 | // callbacks | ||
| 3101 | resize: null, | ||
| 3102 | start: null, | ||
| 3103 | stop: null | ||
| 3104 | }, | ||
| 3105 | |||
| 3106 | _num: function( value ) { | ||
| 3107 | return parseInt( value, 10 ) || 0; | ||
| 3108 | }, | ||
| 3109 | |||
| 3110 | _isNumber: function( value ) { | ||
| 3111 | return !isNaN( parseInt( value, 10 ) ); | ||
| 3112 | }, | ||
| 3113 | |||
| 3114 | _hasScroll: function( el, a ) { | ||
| 3115 | |||
| 3116 | if ( $( el ).css( "overflow" ) === "hidden") { | ||
| 3117 | return false; | ||
| 3118 | } | ||
| 3119 | |||
| 3120 | var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop", | ||
| 3121 | has = false; | ||
| 3122 | |||
| 3123 | if ( el[ scroll ] > 0 ) { | ||
| 3124 | return true; | ||
| 3125 | } | ||
| 3126 | |||
| 3127 | // TODO: determine which cases actually cause this to happen | ||
| 3128 | // if the element doesn't have the scroll set, see if it's possible to | ||
| 3129 | // set the scroll | ||
| 3130 | el[ scroll ] = 1; | ||
| 3131 | has = ( el[ scroll ] > 0 ); | ||
| 3132 | el[ scroll ] = 0; | ||
| 3133 | return has; | ||
| 3134 | }, | ||
| 3135 | |||
| 3136 | _create: function() { | ||
| 3137 | |||
| 3138 | var n, i, handle, axis, hname, | ||
| 3139 | that = this, | ||
| 3140 | o = this.options; | ||
| 3141 | this.element.addClass("ui-resizable"); | ||
| 3142 | |||
| 3143 | $.extend(this, { | ||
| 3144 | _aspectRatio: !!(o.aspectRatio), | ||
| 3145 | aspectRatio: o.aspectRatio, | ||
| 3146 | originalElement: this.element, | ||
| 3147 | _proportionallyResizeElements: [], | ||
| 3148 | _helper: o.helper || o.ghost || o.animate ? o.helper || "ui-resizable-helper" : null | ||
| 3149 | }); | ||
| 3150 | |||
| 3151 | // Wrap the element if it cannot hold child nodes | ||
| 3152 | if (this.element[0].nodeName.match(/^(canvas|textarea|input|select|button|img)$/i)) { | ||
| 3153 | |||
| 3154 | this.element.wrap( | ||
| 3155 | $("<div class='ui-wrapper' style='overflow: hidden;'></div>").css({ | ||
| 3156 | position: this.element.css("position"), | ||
| 3157 | width: this.element.outerWidth(), | ||
| 3158 | height: this.element.outerHeight(), | ||
| 3159 | top: this.element.css("top"), | ||
| 3160 | left: this.element.css("left") | ||
| 3161 | }) | ||
| 3162 | ); | ||
| 3163 | |||
| 3164 | this.element = this.element.parent().data( | ||
| 3165 | "ui-resizable", this.element.resizable( "instance" ) | ||
| 3166 | ); | ||
| 3167 | |||
| 3168 | this.elementIsWrapper = true; | ||
| 3169 | |||
| 3170 | this.element.css({ | ||
| 3171 | marginLeft: this.originalElement.css("marginLeft"), | ||
| 3172 | marginTop: this.originalElement.css("marginTop"), | ||
| 3173 | marginRight: this.originalElement.css("marginRight"), | ||
| 3174 | marginBottom: this.originalElement.css("marginBottom") | ||
| 3175 | }); | ||
| 3176 | this.originalElement.css({ | ||
| 3177 | marginLeft: 0, | ||
| 3178 | marginTop: 0, | ||
| 3179 | marginRight: 0, | ||
| 3180 | marginBottom: 0 | ||
| 3181 | }); | ||
| 3182 | // support: Safari | ||
| 3183 | // Prevent Safari textarea resize | ||
| 3184 | this.originalResizeStyle = this.originalElement.css("resize"); | ||
| 3185 | this.originalElement.css("resize", "none"); | ||
| 3186 | |||
| 3187 | this._proportionallyResizeElements.push( this.originalElement.css({ | ||
| 3188 | position: "static", | ||
| 3189 | zoom: 1, | ||
| 3190 | display: "block" | ||
| 3191 | }) ); | ||
| 3192 | |||
| 3193 | // support: IE9 | ||
| 3194 | // avoid IE jump (hard set the margin) | ||
| 3195 | this.originalElement.css({ margin: this.originalElement.css("margin") }); | ||
| 3196 | |||
| 3197 | this._proportionallyResize(); | ||
| 3198 | } | ||
| 3199 | |||
| 3200 | this.handles = o.handles || | ||
| 3201 | ( !$(".ui-resizable-handle", this.element).length ? | ||
| 3202 | "e,s,se" : { | ||
| 3203 | n: ".ui-resizable-n", | ||
| 3204 | e: ".ui-resizable-e", | ||
| 3205 | s: ".ui-resizable-s", | ||
| 3206 | w: ".ui-resizable-w", | ||
| 3207 | se: ".ui-resizable-se", | ||
| 3208 | sw: ".ui-resizable-sw", | ||
| 3209 | ne: ".ui-resizable-ne", | ||
| 3210 | nw: ".ui-resizable-nw" | ||
| 3211 | } ); | ||
| 3212 | |||
| 3213 | this._handles = $(); | ||
| 3214 | if ( this.handles.constructor === String ) { | ||
| 3215 | |||
| 3216 | if ( this.handles === "all") { | ||
| 3217 | this.handles = "n,e,s,w,se,sw,ne,nw"; | ||
| 3218 | } | ||
| 3219 | |||
| 3220 | n = this.handles.split(","); | ||
| 3221 | this.handles = {}; | ||
| 3222 | |||
| 3223 | for (i = 0; i < n.length; i++) { | ||
| 3224 | |||
| 3225 | handle = $.trim(n[i]); | ||
| 3226 | hname = "ui-resizable-" + handle; | ||
| 3227 | axis = $("<div class='ui-resizable-handle " + hname + "'></div>"); | ||
| 3228 | |||
| 3229 | axis.css({ zIndex: o.zIndex }); | ||
| 3230 | |||
| 3231 | // TODO : What's going on here? | ||
| 3232 | if ("se" === handle) { | ||
| 3233 | axis.addClass("ui-icon ui-icon-gripsmall-diagonal-se"); | ||
| 3234 | } | ||
| 3235 | |||
| 3236 | this.handles[handle] = ".ui-resizable-" + handle; | ||
| 3237 | this.element.append(axis); | ||
| 3238 | } | ||
| 3239 | |||
| 3240 | } | ||
| 3241 | |||
| 3242 | this._renderAxis = function(target) { | ||
| 3243 | |||
| 3244 | var i, axis, padPos, padWrapper; | ||
| 3245 | |||
| 3246 | target = target || this.element; | ||
| 3247 | |||
| 3248 | for (i in this.handles) { | ||
| 3249 | |||
| 3250 | if (this.handles[i].constructor === String) { | ||
| 3251 | this.handles[i] = this.element.children( this.handles[ i ] ).first().show(); | ||
| 3252 | } else if ( this.handles[ i ].jquery || this.handles[ i ].nodeType ) { | ||
| 3253 | this.handles[ i ] = $( this.handles[ i ] ); | ||
| 3254 | this._on( this.handles[ i ], { "mousedown": that._mouseDown }); | ||
| 3255 | } | ||
| 3256 | |||
| 3257 | if (this.elementIsWrapper && this.originalElement[0].nodeName.match(/^(textarea|input|select|button)$/i)) { | ||
| 3258 | |||
| 3259 | axis = $(this.handles[i], this.element); | ||
| 3260 | |||
| 3261 | padWrapper = /sw|ne|nw|se|n|s/.test(i) ? axis.outerHeight() : axis.outerWidth(); | ||
| 3262 | |||
| 3263 | padPos = [ "padding", | ||
| 3264 | /ne|nw|n/.test(i) ? "Top" : | ||
| 3265 | /se|sw|s/.test(i) ? "Bottom" : | ||
| 3266 | /^e$/.test(i) ? "Right" : "Left" ].join(""); | ||
| 3267 | |||
| 3268 | target.css(padPos, padWrapper); | ||
| 3269 | |||
| 3270 | this._proportionallyResize(); | ||
| 3271 | } | ||
| 3272 | |||
| 3273 | this._handles = this._handles.add( this.handles[ i ] ); | ||
| 3274 | } | ||
| 3275 | }; | ||
| 3276 | |||
| 3277 | // TODO: make renderAxis a prototype function | ||
| 3278 | this._renderAxis(this.element); | ||
| 3279 | |||
| 3280 | this._handles = this._handles.add( this.element.find( ".ui-resizable-handle" ) ); | ||
| 3281 | this._handles.disableSelection(); | ||
| 3282 | |||
| 3283 | this._handles.mouseover(function() { | ||
| 3284 | if (!that.resizing) { | ||
| 3285 | if (this.className) { | ||
| 3286 | axis = this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i); | ||
| 3287 | } | ||
| 3288 | that.axis = axis && axis[1] ? axis[1] : "se"; | ||
| 3289 | } | ||
| 3290 | }); | ||
| 3291 | |||
| 3292 | if (o.autoHide) { | ||
| 3293 | this._handles.hide(); | ||
| 3294 | $(this.element) | ||
| 3295 | .addClass("ui-resizable-autohide") | ||
| 3296 | .mouseenter(function() { | ||
| 3297 | if (o.disabled) { | ||
| 3298 | return; | ||
| 3299 | } | ||
| 3300 | $(this).removeClass("ui-resizable-autohide"); | ||
| 3301 | that._handles.show(); | ||
| 3302 | }) | ||
| 3303 | .mouseleave(function() { | ||
| 3304 | if (o.disabled) { | ||
| 3305 | return; | ||
| 3306 | } | ||
| 3307 | if (!that.resizing) { | ||
| 3308 | $(this).addClass("ui-resizable-autohide"); | ||
| 3309 | that._handles.hide(); | ||
| 3310 | } | ||
| 3311 | }); | ||
| 3312 | } | ||
| 3313 | |||
| 3314 | this._mouseInit(); | ||
| 3315 | }, | ||
| 3316 | |||
| 3317 | _destroy: function() { | ||
| 3318 | |||
| 3319 | this._mouseDestroy(); | ||
| 3320 | |||
| 3321 | var wrapper, | ||
| 3322 | _destroy = function(exp) { | ||
| 3323 | $(exp) | ||
| 3324 | .removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing") | ||
| 3325 | .removeData("resizable") | ||
| 3326 | .removeData("ui-resizable") | ||
| 3327 | .unbind(".resizable") | ||
| 3328 | .find(".ui-resizable-handle") | ||
| 3329 | .remove(); | ||
| 3330 | }; | ||
| 3331 | |||
| 3332 | // TODO: Unwrap at same DOM position | ||
| 3333 | if (this.elementIsWrapper) { | ||
| 3334 | _destroy(this.element); | ||
| 3335 | wrapper = this.element; | ||
| 3336 | this.originalElement.css({ | ||
| 3337 | position: wrapper.css("position"), | ||
| 3338 | width: wrapper.outerWidth(), | ||
| 3339 | height: wrapper.outerHeight(), | ||
| 3340 | top: wrapper.css("top"), | ||
| 3341 | left: wrapper.css("left") | ||
| 3342 | }).insertAfter( wrapper ); | ||
| 3343 | wrapper.remove(); | ||
| 3344 | } | ||
| 3345 | |||
| 3346 | this.originalElement.css("resize", this.originalResizeStyle); | ||
| 3347 | _destroy(this.originalElement); | ||
| 3348 | |||
| 3349 | return this; | ||
| 3350 | }, | ||
| 3351 | |||
| 3352 | _mouseCapture: function(event) { | ||
| 3353 | var i, handle, | ||
| 3354 | capture = false; | ||
| 3355 | |||
| 3356 | for (i in this.handles) { | ||
| 3357 | handle = $(this.handles[i])[0]; | ||
| 3358 | if (handle === event.target || $.contains(handle, event.target)) { | ||
| 3359 | capture = true; | ||
| 3360 | } | ||
| 3361 | } | ||
| 3362 | |||
| 3363 | return !this.options.disabled && capture; | ||
| 3364 | }, | ||
| 3365 | |||
| 3366 | _mouseStart: function(event) { | ||
| 3367 | |||
| 3368 | var curleft, curtop, cursor, | ||
| 3369 | o = this.options, | ||
| 3370 | el = this.element; | ||
| 3371 | |||
| 3372 | this.resizing = true; | ||
| 3373 | |||
| 3374 | this._renderProxy(); | ||
| 3375 | |||
| 3376 | curleft = this._num(this.helper.css("left")); | ||
| 3377 | curtop = this._num(this.helper.css("top")); | ||
| 3378 | |||
| 3379 | if (o.containment) { | ||
| 3380 | curleft += $(o.containment).scrollLeft() || 0; | ||
| 3381 | curtop += $(o.containment).scrollTop() || 0; | ||
| 3382 | } | ||
| 3383 | |||
| 3384 | this.offset = this.helper.offset(); | ||
| 3385 | this.position = { left: curleft, top: curtop }; | ||
| 3386 | |||
| 3387 | this.size = this._helper ? { | ||
| 3388 | width: this.helper.width(), | ||
| 3389 | height: this.helper.height() | ||
| 3390 | } : { | ||
| 3391 | width: el.width(), | ||
| 3392 | height: el.height() | ||
| 3393 | }; | ||
| 3394 | |||
| 3395 | this.originalSize = this._helper ? { | ||
| 3396 | width: el.outerWidth(), | ||
| 3397 | height: el.outerHeight() | ||
| 3398 | } : { | ||
| 3399 | width: el.width(), | ||
| 3400 | height: el.height() | ||
| 3401 | }; | ||
| 3402 | |||
| 3403 | this.sizeDiff = { | ||
| 3404 | width: el.outerWidth() - el.width(), | ||
| 3405 | height: el.outerHeight() - el.height() | ||
| 3406 | }; | ||
| 3407 | |||
| 3408 | this.originalPosition = { left: curleft, top: curtop }; | ||
| 3409 | this.originalMousePosition = { left: event.pageX, top: event.pageY }; | ||
| 3410 | |||
| 3411 | this.aspectRatio = (typeof o.aspectRatio === "number") ? | ||
| 3412 | o.aspectRatio : | ||
| 3413 | ((this.originalSize.width / this.originalSize.height) || 1); | ||
| 3414 | |||
| 3415 | cursor = $(".ui-resizable-" + this.axis).css("cursor"); | ||
| 3416 | $("body").css("cursor", cursor === "auto" ? this.axis + "-resize" : cursor); | ||
| 3417 | |||
| 3418 | el.addClass("ui-resizable-resizing"); | ||
| 3419 | this._propagate("start", event); | ||
| 3420 | return true; | ||
| 3421 | }, | ||
| 3422 | |||
| 3423 | _mouseDrag: function(event) { | ||
| 3424 | |||
| 3425 | var data, props, | ||
| 3426 | smp = this.originalMousePosition, | ||
| 3427 | a = this.axis, | ||
| 3428 | dx = (event.pageX - smp.left) || 0, | ||
| 3429 | dy = (event.pageY - smp.top) || 0, | ||
| 3430 | trigger = this._change[a]; | ||
| 3431 | |||
| 3432 | this._updatePrevProperties(); | ||
| 3433 | |||
| 3434 | if (!trigger) { | ||
| 3435 | return false; | ||
| 3436 | } | ||
| 3437 | |||
| 3438 | data = trigger.apply(this, [ event, dx, dy ]); | ||
| 3439 | |||
| 3440 | this._updateVirtualBoundaries(event.shiftKey); | ||
| 3441 | if (this._aspectRatio || event.shiftKey) { | ||
| 3442 | data = this._updateRatio(data, event); | ||
| 3443 | } | ||
| 3444 | |||
| 3445 | data = this._respectSize(data, event); | ||
| 3446 | |||
| 3447 | this._updateCache(data); | ||
| 3448 | |||
| 3449 | this._propagate("resize", event); | ||
| 3450 | |||
| 3451 | props = this._applyChanges(); | ||
| 3452 | |||
| 3453 | if ( !this._helper && this._proportionallyResizeElements.length ) { | ||
| 3454 | this._proportionallyResize(); | ||
| 3455 | } | ||
| 3456 | |||
| 3457 | if ( !$.isEmptyObject( props ) ) { | ||
| 3458 | this._updatePrevProperties(); | ||
| 3459 | this._trigger( "resize", event, this.ui() ); | ||
| 3460 | this._applyChanges(); | ||
| 3461 | } | ||
| 3462 | |||
| 3463 | return false; | ||
| 3464 | }, | ||
| 3465 | |||
| 3466 | _mouseStop: function(event) { | ||
| 3467 | |||
| 3468 | this.resizing = false; | ||
| 3469 | var pr, ista, soffseth, soffsetw, s, left, top, | ||
| 3470 | o = this.options, that = this; | ||
| 3471 | |||
| 3472 | if (this._helper) { | ||
| 3473 | |||
| 3474 | pr = this._proportionallyResizeElements; | ||
| 3475 | ista = pr.length && (/textarea/i).test(pr[0].nodeName); | ||
| 3476 | soffseth = ista && this._hasScroll(pr[0], "left") ? 0 : that.sizeDiff.height; | ||
| 3477 | soffsetw = ista ? 0 : that.sizeDiff.width; | ||
| 3478 | |||
| 3479 | s = { | ||
| 3480 | width: (that.helper.width() - soffsetw), | ||
| 3481 | height: (that.helper.height() - soffseth) | ||
| 3482 | }; | ||
| 3483 | left = (parseInt(that.element.css("left"), 10) + | ||
| 3484 | (that.position.left - that.originalPosition.left)) || null; | ||
| 3485 | top = (parseInt(that.element.css("top"), 10) + | ||
| 3486 | (that.position.top - that.originalPosition.top)) || null; | ||
| 3487 | |||
| 3488 | if (!o.animate) { | ||
| 3489 | this.element.css($.extend(s, { top: top, left: left })); | ||
| 3490 | } | ||
| 3491 | |||
| 3492 | that.helper.height(that.size.height); | ||
| 3493 | that.helper.width(that.size.width); | ||
| 3494 | |||
| 3495 | if (this._helper && !o.animate) { | ||
| 3496 | this._proportionallyResize(); | ||
| 3497 | } | ||
| 3498 | } | ||
| 3499 | |||
| 3500 | $("body").css("cursor", "auto"); | ||
| 3501 | |||
| 3502 | this.element.removeClass("ui-resizable-resizing"); | ||
| 3503 | |||
| 3504 | this._propagate("stop", event); | ||
| 3505 | |||
| 3506 | if (this._helper) { | ||
| 3507 | this.helper.remove(); | ||
| 3508 | } | ||
| 3509 | |||
| 3510 | return false; | ||
| 3511 | |||
| 3512 | }, | ||
| 3513 | |||
| 3514 | _updatePrevProperties: function() { | ||
| 3515 | this.prevPosition = { | ||
| 3516 | top: this.position.top, | ||
| 3517 | left: this.position.left | ||
| 3518 | }; | ||
| 3519 | this.prevSize = { | ||
| 3520 | width: this.size.width, | ||
| 3521 | height: this.size.height | ||
| 3522 | }; | ||
| 3523 | }, | ||
| 3524 | |||
| 3525 | _applyChanges: function() { | ||
| 3526 | var props = {}; | ||
| 3527 | |||
| 3528 | if ( this.position.top !== this.prevPosition.top ) { | ||
| 3529 | props.top = this.position.top + "px"; | ||
| 3530 | } | ||
| 3531 | if ( this.position.left !== this.prevPosition.left ) { | ||
| 3532 | props.left = this.position.left + "px"; | ||
| 3533 | } | ||
| 3534 | if ( this.size.width !== this.prevSize.width ) { | ||
| 3535 | props.width = this.size.width + "px"; | ||
| 3536 | } | ||
| 3537 | if ( this.size.height !== this.prevSize.height ) { | ||
| 3538 | props.height = this.size.height + "px"; | ||
| 3539 | } | ||
| 3540 | |||
| 3541 | this.helper.css( props ); | ||
| 3542 | |||
| 3543 | return props; | ||
| 3544 | }, | ||
| 3545 | |||
| 3546 | _updateVirtualBoundaries: function(forceAspectRatio) { | ||
| 3547 | var pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b, | ||
| 3548 | o = this.options; | ||
| 3549 | |||
| 3550 | b = { | ||
| 3551 | minWidth: this._isNumber(o.minWidth) ? o.minWidth : 0, | ||
| 3552 | maxWidth: this._isNumber(o.maxWidth) ? o.maxWidth : Infinity, | ||
| 3553 | minHeight: this._isNumber(o.minHeight) ? o.minHeight : 0, | ||
| 3554 | maxHeight: this._isNumber(o.maxHeight) ? o.maxHeight : Infinity | ||
| 3555 | }; | ||
| 3556 | |||
| 3557 | if (this._aspectRatio || forceAspectRatio) { | ||
| 3558 | pMinWidth = b.minHeight * this.aspectRatio; | ||
| 3559 | pMinHeight = b.minWidth / this.aspectRatio; | ||
| 3560 | pMaxWidth = b.maxHeight * this.aspectRatio; | ||
| 3561 | pMaxHeight = b.maxWidth / this.aspectRatio; | ||
| 3562 | |||
| 3563 | if (pMinWidth > b.minWidth) { | ||
| 3564 | b.minWidth = pMinWidth; | ||
| 3565 | } | ||
| 3566 | if (pMinHeight > b.minHeight) { | ||
| 3567 | b.minHeight = pMinHeight; | ||
| 3568 | } | ||
| 3569 | if (pMaxWidth < b.maxWidth) { | ||
| 3570 | b.maxWidth = pMaxWidth; | ||
| 3571 | } | ||
| 3572 | if (pMaxHeight < b.maxHeight) { | ||
| 3573 | b.maxHeight = pMaxHeight; | ||
| 3574 | } | ||
| 3575 | } | ||
| 3576 | this._vBoundaries = b; | ||
| 3577 | }, | ||
| 3578 | |||
| 3579 | _updateCache: function(data) { | ||
| 3580 | this.offset = this.helper.offset(); | ||
| 3581 | if (this._isNumber(data.left)) { | ||
| 3582 | this.position.left = data.left; | ||
| 3583 | } | ||
| 3584 | if (this._isNumber(data.top)) { | ||
| 3585 | this.position.top = data.top; | ||
| 3586 | } | ||
| 3587 | if (this._isNumber(data.height)) { | ||
| 3588 | this.size.height = data.height; | ||
| 3589 | } | ||
| 3590 | if (this._isNumber(data.width)) { | ||
| 3591 | this.size.width = data.width; | ||
| 3592 | } | ||
| 3593 | }, | ||
| 3594 | |||
| 3595 | _updateRatio: function( data ) { | ||
| 3596 | |||
| 3597 | var cpos = this.position, | ||
| 3598 | csize = this.size, | ||
| 3599 | a = this.axis; | ||
| 3600 | |||
| 3601 | if (this._isNumber(data.height)) { | ||
| 3602 | data.width = (data.height * this.aspectRatio); | ||
| 3603 | } else if (this._isNumber(data.width)) { | ||
| 3604 | data.height = (data.width / this.aspectRatio); | ||
| 3605 | } | ||
| 3606 | |||
| 3607 | if (a === "sw") { | ||
| 3608 | data.left = cpos.left + (csize.width - data.width); | ||
| 3609 | data.top = null; | ||
| 3610 | } | ||
| 3611 | if (a === "nw") { | ||
| 3612 | data.top = cpos.top + (csize.height - data.height); | ||
| 3613 | data.left = cpos.left + (csize.width - data.width); | ||
| 3614 | } | ||
| 3615 | |||
| 3616 | return data; | ||
| 3617 | }, | ||
| 3618 | |||
| 3619 | _respectSize: function( data ) { | ||
| 3620 | |||
| 3621 | var o = this._vBoundaries, | ||
| 3622 | a = this.axis, | ||
| 3623 | ismaxw = this._isNumber(data.width) && o.maxWidth && (o.maxWidth < data.width), | ||
| 3624 | ismaxh = this._isNumber(data.height) && o.maxHeight && (o.maxHeight < data.height), | ||
| 3625 | isminw = this._isNumber(data.width) && o.minWidth && (o.minWidth > data.width), | ||
| 3626 | isminh = this._isNumber(data.height) && o.minHeight && (o.minHeight > data.height), | ||
| 3627 | dw = this.originalPosition.left + this.originalSize.width, | ||
| 3628 | dh = this.position.top + this.size.height, | ||
| 3629 | cw = /sw|nw|w/.test(a), ch = /nw|ne|n/.test(a); | ||
| 3630 | if (isminw) { | ||
| 3631 | data.width = o.minWidth; | ||
| 3632 | } | ||
| 3633 | if (isminh) { | ||
| 3634 | data.height = o.minHeight; | ||
| 3635 | } | ||
| 3636 | if (ismaxw) { | ||
| 3637 | data.width = o.maxWidth; | ||
| 3638 | } | ||
| 3639 | if (ismaxh) { | ||
| 3640 | data.height = o.maxHeight; | ||
| 3641 | } | ||
| 3642 | |||
| 3643 | if (isminw && cw) { | ||
| 3644 | data.left = dw - o.minWidth; | ||
| 3645 | } | ||
| 3646 | if (ismaxw && cw) { | ||
| 3647 | data.left = dw - o.maxWidth; | ||
| 3648 | } | ||
| 3649 | if (isminh && ch) { | ||
| 3650 | data.top = dh - o.minHeight; | ||
| 3651 | } | ||
| 3652 | if (ismaxh && ch) { | ||
| 3653 | data.top = dh - o.maxHeight; | ||
| 3654 | } | ||
| 3655 | |||
| 3656 | // Fixing jump error on top/left - bug #2330 | ||
| 3657 | if (!data.width && !data.height && !data.left && data.top) { | ||
| 3658 | data.top = null; | ||
| 3659 | } else if (!data.width && !data.height && !data.top && data.left) { | ||
| 3660 | data.left = null; | ||
| 3661 | } | ||
| 3662 | |||
| 3663 | return data; | ||
| 3664 | }, | ||
| 3665 | |||
| 3666 | _getPaddingPlusBorderDimensions: function( element ) { | ||
| 3667 | var i = 0, | ||
| 3668 | widths = [], | ||
| 3669 | borders = [ | ||
| 3670 | element.css( "borderTopWidth" ), | ||
| 3671 | element.css( "borderRightWidth" ), | ||
| 3672 | element.css( "borderBottomWidth" ), | ||
| 3673 | element.css( "borderLeftWidth" ) | ||
| 3674 | ], | ||
| 3675 | paddings = [ | ||
| 3676 | element.css( "paddingTop" ), | ||
| 3677 | element.css( "paddingRight" ), | ||
| 3678 | element.css( "paddingBottom" ), | ||
| 3679 | element.css( "paddingLeft" ) | ||
| 3680 | ]; | ||
| 3681 | |||
| 3682 | for ( ; i < 4; i++ ) { | ||
| 3683 | widths[ i ] = ( parseInt( borders[ i ], 10 ) || 0 ); | ||
| 3684 | widths[ i ] += ( parseInt( paddings[ i ], 10 ) || 0 ); | ||
| 3685 | } | ||
| 3686 | |||
| 3687 | return { | ||
| 3688 | height: widths[ 0 ] + widths[ 2 ], | ||
| 3689 | width: widths[ 1 ] + widths[ 3 ] | ||
| 3690 | }; | ||
| 3691 | }, | ||
| 3692 | |||
| 3693 | _proportionallyResize: function() { | ||
| 3694 | |||
| 3695 | if (!this._proportionallyResizeElements.length) { | ||
| 3696 | return; | ||
| 3697 | } | ||
| 3698 | |||
| 3699 | var prel, | ||
| 3700 | i = 0, | ||
| 3701 | element = this.helper || this.element; | ||
| 3702 | |||
| 3703 | for ( ; i < this._proportionallyResizeElements.length; i++) { | ||
| 3704 | |||
| 3705 | prel = this._proportionallyResizeElements[i]; | ||
| 3706 | |||
| 3707 | // TODO: Seems like a bug to cache this.outerDimensions | ||
| 3708 | // considering that we are in a loop. | ||
| 3709 | if (!this.outerDimensions) { | ||
| 3710 | this.outerDimensions = this._getPaddingPlusBorderDimensions( prel ); | ||
| 3711 | } | ||
| 3712 | |||
| 3713 | prel.css({ | ||
| 3714 | height: (element.height() - this.outerDimensions.height) || 0, | ||
| 3715 | width: (element.width() - this.outerDimensions.width) || 0 | ||
| 3716 | }); | ||
| 3717 | |||
| 3718 | } | ||
| 3719 | |||
| 3720 | }, | ||
| 3721 | |||
| 3722 | _renderProxy: function() { | ||
| 3723 | |||
| 3724 | var el = this.element, o = this.options; | ||
| 3725 | this.elementOffset = el.offset(); | ||
| 3726 | |||
| 3727 | if (this._helper) { | ||
| 3728 | |||
| 3729 | this.helper = this.helper || $("<div style='overflow:hidden;'></div>"); | ||
| 3730 | |||
| 3731 | this.helper.addClass(this._helper).css({ | ||
| 3732 | width: this.element.outerWidth() - 1, | ||
| 3733 | height: this.element.outerHeight() - 1, | ||
| 3734 | position: "absolute", | ||
| 3735 | left: this.elementOffset.left + "px", | ||
| 3736 | top: this.elementOffset.top + "px", | ||
| 3737 | zIndex: ++o.zIndex //TODO: Don't modify option | ||
| 3738 | }); | ||
| 3739 | |||
| 3740 | this.helper | ||
| 3741 | .appendTo("body") | ||
| 3742 | .disableSelection(); | ||
| 3743 | |||
| 3744 | } else { | ||
| 3745 | this.helper = this.element; | ||
| 3746 | } | ||
| 3747 | |||
| 3748 | }, | ||
| 3749 | |||
| 3750 | _change: { | ||
| 3751 | e: function(event, dx) { | ||
| 3752 | return { width: this.originalSize.width + dx }; | ||
| 3753 | }, | ||
| 3754 | w: function(event, dx) { | ||
| 3755 | var cs = this.originalSize, sp = this.originalPosition; | ||
| 3756 | return { left: sp.left + dx, width: cs.width - dx }; | ||
| 3757 | }, | ||
| 3758 | n: function(event, dx, dy) { | ||
| 3759 | var cs = this.originalSize, sp = this.originalPosition; | ||
| 3760 | return { top: sp.top + dy, height: cs.height - dy }; | ||
| 3761 | }, | ||
| 3762 | s: function(event, dx, dy) { | ||
| 3763 | return { height: this.originalSize.height + dy }; | ||
| 3764 | }, | ||
| 3765 | se: function(event, dx, dy) { | ||
| 3766 | return $.extend(this._change.s.apply(this, arguments), | ||
| 3767 | this._change.e.apply(this, [ event, dx, dy ])); | ||
| 3768 | }, | ||
| 3769 | sw: function(event, dx, dy) { | ||
| 3770 | return $.extend(this._change.s.apply(this, arguments), | ||
| 3771 | this._change.w.apply(this, [ event, dx, dy ])); | ||
| 3772 | }, | ||
| 3773 | ne: function(event, dx, dy) { | ||
| 3774 | return $.extend(this._change.n.apply(this, arguments), | ||
| 3775 | this._change.e.apply(this, [ event, dx, dy ])); | ||
| 3776 | }, | ||
| 3777 | nw: function(event, dx, dy) { | ||
| 3778 | return $.extend(this._change.n.apply(this, arguments), | ||
| 3779 | this._change.w.apply(this, [ event, dx, dy ])); | ||
| 3780 | } | ||
| 3781 | }, | ||
| 3782 | |||
| 3783 | _propagate: function(n, event) { | ||
| 3784 | $.ui.plugin.call(this, n, [ event, this.ui() ]); | ||
| 3785 | (n !== "resize" && this._trigger(n, event, this.ui())); | ||
| 3786 | }, | ||
| 3787 | |||
| 3788 | plugins: {}, | ||
| 3789 | |||
| 3790 | ui: function() { | ||
| 3791 | return { | ||
| 3792 | originalElement: this.originalElement, | ||
| 3793 | element: this.element, | ||
| 3794 | helper: this.helper, | ||
| 3795 | position: this.position, | ||
| 3796 | size: this.size, | ||
| 3797 | originalSize: this.originalSize, | ||
| 3798 | originalPosition: this.originalPosition | ||
| 3799 | }; | ||
| 3800 | } | ||
| 3801 | |||
| 3802 | }); | ||
| 3803 | |||
| 3804 | /* | ||
| 3805 | * Resizable Extensions | ||
| 3806 | */ | ||
| 3807 | |||
| 3808 | $.ui.plugin.add("resizable", "animate", { | ||
| 3809 | |||
| 3810 | stop: function( event ) { | ||
| 3811 | var that = $(this).resizable( "instance" ), | ||
| 3812 | o = that.options, | ||
| 3813 | pr = that._proportionallyResizeElements, | ||
| 3814 | ista = pr.length && (/textarea/i).test(pr[0].nodeName), | ||
| 3815 | soffseth = ista && that._hasScroll(pr[0], "left") ? 0 : that.sizeDiff.height, | ||
| 3816 | soffsetw = ista ? 0 : that.sizeDiff.width, | ||
| 3817 | style = { width: (that.size.width - soffsetw), height: (that.size.height - soffseth) }, | ||
| 3818 | left = (parseInt(that.element.css("left"), 10) + | ||
| 3819 | (that.position.left - that.originalPosition.left)) || null, | ||
| 3820 | top = (parseInt(that.element.css("top"), 10) + | ||
| 3821 | (that.position.top - that.originalPosition.top)) || null; | ||
| 3822 | |||
| 3823 | that.element.animate( | ||
| 3824 | $.extend(style, top && left ? { top: top, left: left } : {}), { | ||
| 3825 | duration: o.animateDuration, | ||
| 3826 | easing: o.animateEasing, | ||
| 3827 | step: function() { | ||
| 3828 | |||
| 3829 | var data = { | ||
| 3830 | width: parseInt(that.element.css("width"), 10), | ||
| 3831 | height: parseInt(that.element.css("height"), 10), | ||
| 3832 | top: parseInt(that.element.css("top"), 10), | ||
| 3833 | left: parseInt(that.element.css("left"), 10) | ||
| 3834 | }; | ||
| 3835 | |||
| 3836 | if (pr && pr.length) { | ||
| 3837 | $(pr[0]).css({ width: data.width, height: data.height }); | ||
| 3838 | } | ||
| 3839 | |||
| 3840 | // propagating resize, and updating values for each animation step | ||
| 3841 | that._updateCache(data); | ||
| 3842 | that._propagate("resize", event); | ||
| 3843 | |||
| 3844 | } | ||
| 3845 | } | ||
| 3846 | ); | ||
| 3847 | } | ||
| 3848 | |||
| 3849 | }); | ||
| 3850 | |||
| 3851 | $.ui.plugin.add( "resizable", "containment", { | ||
| 3852 | |||
| 3853 | start: function() { | ||
| 3854 | var element, p, co, ch, cw, width, height, | ||
| 3855 | that = $( this ).resizable( "instance" ), | ||
| 3856 | o = that.options, | ||
| 3857 | el = that.element, | ||
| 3858 | oc = o.containment, | ||
| 3859 | ce = ( oc instanceof $ ) ? oc.get( 0 ) : ( /parent/.test( oc ) ) ? el.parent().get( 0 ) : oc; | ||
| 3860 | |||
| 3861 | if ( !ce ) { | ||
| 3862 | return; | ||
| 3863 | } | ||
| 3864 | |||
| 3865 | that.containerElement = $( ce ); | ||
| 3866 | |||
| 3867 | if ( /document/.test( oc ) || oc === document ) { | ||
| 3868 | that.containerOffset = { | ||
| 3869 | left: 0, | ||
| 3870 | top: 0 | ||
| 3871 | }; | ||
| 3872 | that.containerPosition = { | ||
| 3873 | left: 0, | ||
| 3874 | top: 0 | ||
| 3875 | }; | ||
| 3876 | |||
| 3877 | that.parentData = { | ||
| 3878 | element: $( document ), | ||
| 3879 | left: 0, | ||
| 3880 | top: 0, | ||
| 3881 | width: $( document ).width(), | ||
| 3882 | height: $( document ).height() || document.body.parentNode.scrollHeight | ||
| 3883 | }; | ||
| 3884 | } else { | ||
| 3885 | element = $( ce ); | ||
| 3886 | p = []; | ||
| 3887 | $([ "Top", "Right", "Left", "Bottom" ]).each(function( i, name ) { | ||
| 3888 | p[ i ] = that._num( element.css( "padding" + name ) ); | ||
| 3889 | }); | ||
| 3890 | |||
| 3891 | that.containerOffset = element.offset(); | ||
| 3892 | that.containerPosition = element.position(); | ||
| 3893 | that.containerSize = { | ||
| 3894 | height: ( element.innerHeight() - p[ 3 ] ), | ||
| 3895 | width: ( element.innerWidth() - p[ 1 ] ) | ||
| 3896 | }; | ||
| 3897 | |||
| 3898 | co = that.containerOffset; | ||
| 3899 | ch = that.containerSize.height; | ||
| 3900 | cw = that.containerSize.width; | ||
| 3901 | width = ( that._hasScroll ( ce, "left" ) ? ce.scrollWidth : cw ); | ||
| 3902 | height = ( that._hasScroll ( ce ) ? ce.scrollHeight : ch ) ; | ||
| 3903 | |||
| 3904 | that.parentData = { | ||
| 3905 | element: ce, | ||
| 3906 | left: co.left, | ||
| 3907 | top: co.top, | ||
| 3908 | width: width, | ||
| 3909 | height: height | ||
| 3910 | }; | ||
| 3911 | } | ||
| 3912 | }, | ||
| 3913 | |||
| 3914 | resize: function( event ) { | ||
| 3915 | var woset, hoset, isParent, isOffsetRelative, | ||
| 3916 | that = $( this ).resizable( "instance" ), | ||
| 3917 | o = that.options, | ||
| 3918 | co = that.containerOffset, | ||
| 3919 | cp = that.position, | ||
| 3920 | pRatio = that._aspectRatio || event.shiftKey, | ||
| 3921 | cop = { | ||
| 3922 | top: 0, | ||
| 3923 | left: 0 | ||
| 3924 | }, | ||
| 3925 | ce = that.containerElement, | ||
| 3926 | continueResize = true; | ||
| 3927 | |||
| 3928 | if ( ce[ 0 ] !== document && ( /static/ ).test( ce.css( "position" ) ) ) { | ||
| 3929 | cop = co; | ||
| 3930 | } | ||
| 3931 | |||
| 3932 | if ( cp.left < ( that._helper ? co.left : 0 ) ) { | ||
| 3933 | that.size.width = that.size.width + | ||
| 3934 | ( that._helper ? | ||
| 3935 | ( that.position.left - co.left ) : | ||
| 3936 | ( that.position.left - cop.left ) ); | ||
| 3937 | |||
| 3938 | if ( pRatio ) { | ||
| 3939 | that.size.height = that.size.width / that.aspectRatio; | ||
| 3940 | continueResize = false; | ||
| 3941 | } | ||
| 3942 | that.position.left = o.helper ? co.left : 0; | ||
| 3943 | } | ||
| 3944 | |||
| 3945 | if ( cp.top < ( that._helper ? co.top : 0 ) ) { | ||
| 3946 | that.size.height = that.size.height + | ||
| 3947 | ( that._helper ? | ||
| 3948 | ( that.position.top - co.top ) : | ||
| 3949 | that.position.top ); | ||
| 3950 | |||
| 3951 | if ( pRatio ) { | ||
| 3952 | that.size.width = that.size.height * that.aspectRatio; | ||
| 3953 | continueResize = false; | ||
| 3954 | } | ||
| 3955 | that.position.top = that._helper ? co.top : 0; | ||
| 3956 | } | ||
| 3957 | |||
| 3958 | isParent = that.containerElement.get( 0 ) === that.element.parent().get( 0 ); | ||
| 3959 | isOffsetRelative = /relative|absolute/.test( that.containerElement.css( "position" ) ); | ||
| 3960 | |||
| 3961 | if ( isParent && isOffsetRelative ) { | ||
| 3962 | that.offset.left = that.parentData.left + that.position.left; | ||
| 3963 | that.offset.top = that.parentData.top + that.position.top; | ||
| 3964 | } else { | ||
| 3965 | that.offset.left = that.element.offset().left; | ||
| 3966 | that.offset.top = that.element.offset().top; | ||
| 3967 | } | ||
| 3968 | |||
| 3969 | woset = Math.abs( that.sizeDiff.width + | ||
| 3970 | (that._helper ? | ||
| 3971 | that.offset.left - cop.left : | ||
| 3972 | (that.offset.left - co.left)) ); | ||
| 3973 | |||
| 3974 | hoset = Math.abs( that.sizeDiff.height + | ||
| 3975 | (that._helper ? | ||
| 3976 | that.offset.top - cop.top : | ||
| 3977 | (that.offset.top - co.top)) ); | ||
| 3978 | |||
| 3979 | if ( woset + that.size.width >= that.parentData.width ) { | ||
| 3980 | that.size.width = that.parentData.width - woset; | ||
| 3981 | if ( pRatio ) { | ||
| 3982 | that.size.height = that.size.width / that.aspectRatio; | ||
| 3983 | continueResize = false; | ||
| 3984 | } | ||
| 3985 | } | ||
| 3986 | |||
| 3987 | if ( hoset + that.size.height >= that.parentData.height ) { | ||
| 3988 | that.size.height = that.parentData.height - hoset; | ||
| 3989 | if ( pRatio ) { | ||
| 3990 | that.size.width = that.size.height * that.aspectRatio; | ||
| 3991 | continueResize = false; | ||
| 3992 | } | ||
| 3993 | } | ||
| 3994 | |||
| 3995 | if ( !continueResize ) { | ||
| 3996 | that.position.left = that.prevPosition.left; | ||
| 3997 | that.position.top = that.prevPosition.top; | ||
| 3998 | that.size.width = that.prevSize.width; | ||
| 3999 | that.size.height = that.prevSize.height; | ||
| 4000 | } | ||
| 4001 | }, | ||
| 4002 | |||
| 4003 | stop: function() { | ||
| 4004 | var that = $( this ).resizable( "instance" ), | ||
| 4005 | o = that.options, | ||
| 4006 | co = that.containerOffset, | ||
| 4007 | cop = that.containerPosition, | ||
| 4008 | ce = that.containerElement, | ||
| 4009 | helper = $( that.helper ), | ||
| 4010 | ho = helper.offset(), | ||
| 4011 | w = helper.outerWidth() - that.sizeDiff.width, | ||
| 4012 | h = helper.outerHeight() - that.sizeDiff.height; | ||
| 4013 | |||
| 4014 | if ( that._helper && !o.animate && ( /relative/ ).test( ce.css( "position" ) ) ) { | ||
| 4015 | $( this ).css({ | ||
| 4016 | left: ho.left - cop.left - co.left, | ||
| 4017 | width: w, | ||
| 4018 | height: h | ||
| 4019 | }); | ||
| 4020 | } | ||
| 4021 | |||
| 4022 | if ( that._helper && !o.animate && ( /static/ ).test( ce.css( "position" ) ) ) { | ||
| 4023 | $( this ).css({ | ||
| 4024 | left: ho.left - cop.left - co.left, | ||
| 4025 | width: w, | ||
| 4026 | height: h | ||
| 4027 | }); | ||
| 4028 | } | ||
| 4029 | } | ||
| 4030 | }); | ||
| 4031 | |||
| 4032 | $.ui.plugin.add("resizable", "alsoResize", { | ||
| 4033 | |||
| 4034 | start: function() { | ||
| 4035 | var that = $(this).resizable( "instance" ), | ||
| 4036 | o = that.options; | ||
| 4037 | |||
| 4038 | $(o.alsoResize).each(function() { | ||
| 4039 | var el = $(this); | ||
| 4040 | el.data("ui-resizable-alsoresize", { | ||
| 4041 | width: parseInt(el.width(), 10), height: parseInt(el.height(), 10), | ||
| 4042 | left: parseInt(el.css("left"), 10), top: parseInt(el.css("top"), 10) | ||
| 4043 | }); | ||
| 4044 | }); | ||
| 4045 | }, | ||
| 4046 | |||
| 4047 | resize: function(event, ui) { | ||
| 4048 | var that = $(this).resizable( "instance" ), | ||
| 4049 | o = that.options, | ||
| 4050 | os = that.originalSize, | ||
| 4051 | op = that.originalPosition, | ||
| 4052 | delta = { | ||
| 4053 | height: (that.size.height - os.height) || 0, | ||
| 4054 | width: (that.size.width - os.width) || 0, | ||
| 4055 | top: (that.position.top - op.top) || 0, | ||
| 4056 | left: (that.position.left - op.left) || 0 | ||
| 4057 | }; | ||
| 4058 | |||
| 4059 | $(o.alsoResize).each(function() { | ||
| 4060 | var el = $(this), start = $(this).data("ui-resizable-alsoresize"), style = {}, | ||
| 4061 | css = el.parents(ui.originalElement[0]).length ? | ||
| 4062 | [ "width", "height" ] : | ||
| 4063 | [ "width", "height", "top", "left" ]; | ||
| 4064 | |||
| 4065 | $.each(css, function(i, prop) { | ||
| 4066 | var sum = (start[prop] || 0) + (delta[prop] || 0); | ||
| 4067 | if (sum && sum >= 0) { | ||
| 4068 | style[prop] = sum || null; | ||
| 4069 | } | ||
| 4070 | }); | ||
| 4071 | |||
| 4072 | el.css(style); | ||
| 4073 | }); | ||
| 4074 | }, | ||
| 4075 | |||
| 4076 | stop: function() { | ||
| 4077 | $(this).removeData("resizable-alsoresize"); | ||
| 4078 | } | ||
| 4079 | }); | ||
| 4080 | |||
| 4081 | $.ui.plugin.add("resizable", "ghost", { | ||
| 4082 | |||
| 4083 | start: function() { | ||
| 4084 | |||
| 4085 | var that = $(this).resizable( "instance" ), o = that.options, cs = that.size; | ||
| 4086 | |||
| 4087 | that.ghost = that.originalElement.clone(); | ||
| 4088 | that.ghost | ||
| 4089 | .css({ | ||
| 4090 | opacity: 0.25, | ||
| 4091 | display: "block", | ||
| 4092 | position: "relative", | ||
| 4093 | height: cs.height, | ||
| 4094 | width: cs.width, | ||
| 4095 | margin: 0, | ||
| 4096 | left: 0, | ||
| 4097 | top: 0 | ||
| 4098 | }) | ||
| 4099 | .addClass("ui-resizable-ghost") | ||
| 4100 | .addClass(typeof o.ghost === "string" ? o.ghost : ""); | ||
| 4101 | |||
| 4102 | that.ghost.appendTo(that.helper); | ||
| 4103 | |||
| 4104 | }, | ||
| 4105 | |||
| 4106 | resize: function() { | ||
| 4107 | var that = $(this).resizable( "instance" ); | ||
| 4108 | if (that.ghost) { | ||
| 4109 | that.ghost.css({ | ||
| 4110 | position: "relative", | ||
| 4111 | height: that.size.height, | ||
| 4112 | width: that.size.width | ||
| 4113 | }); | ||
| 4114 | } | ||
| 4115 | }, | ||
| 4116 | |||
| 4117 | stop: function() { | ||
| 4118 | var that = $(this).resizable( "instance" ); | ||
| 4119 | if (that.ghost && that.helper) { | ||
| 4120 | that.helper.get(0).removeChild(that.ghost.get(0)); | ||
| 4121 | } | ||
| 4122 | } | ||
| 4123 | |||
| 4124 | }); | ||
| 4125 | |||
| 4126 | $.ui.plugin.add("resizable", "grid", { | ||
| 4127 | |||
| 4128 | resize: function() { | ||
| 4129 | var outerDimensions, | ||
| 4130 | that = $(this).resizable( "instance" ), | ||
| 4131 | o = that.options, | ||
| 4132 | cs = that.size, | ||
| 4133 | os = that.originalSize, | ||
| 4134 | op = that.originalPosition, | ||
| 4135 | a = that.axis, | ||
| 4136 | grid = typeof o.grid === "number" ? [ o.grid, o.grid ] : o.grid, | ||
| 4137 | gridX = (grid[0] || 1), | ||
| 4138 | gridY = (grid[1] || 1), | ||
| 4139 | ox = Math.round((cs.width - os.width) / gridX) * gridX, | ||
| 4140 | oy = Math.round((cs.height - os.height) / gridY) * gridY, | ||
| 4141 | newWidth = os.width + ox, | ||
| 4142 | newHeight = os.height + oy, | ||
| 4143 | isMaxWidth = o.maxWidth && (o.maxWidth < newWidth), | ||
| 4144 | isMaxHeight = o.maxHeight && (o.maxHeight < newHeight), | ||
| 4145 | isMinWidth = o.minWidth && (o.minWidth > newWidth), | ||
| 4146 | isMinHeight = o.minHeight && (o.minHeight > newHeight); | ||
| 4147 | |||
| 4148 | o.grid = grid; | ||
| 4149 | |||
| 4150 | if (isMinWidth) { | ||
| 4151 | newWidth += gridX; | ||
| 4152 | } | ||
| 4153 | if (isMinHeight) { | ||
| 4154 | newHeight += gridY; | ||
| 4155 | } | ||
| 4156 | if (isMaxWidth) { | ||
| 4157 | newWidth -= gridX; | ||
| 4158 | } | ||
| 4159 | if (isMaxHeight) { | ||
| 4160 | newHeight -= gridY; | ||
| 4161 | } | ||
| 4162 | |||
| 4163 | if (/^(se|s|e)$/.test(a)) { | ||
| 4164 | that.size.width = newWidth; | ||
| 4165 | that.size.height = newHeight; | ||
| 4166 | } else if (/^(ne)$/.test(a)) { | ||
| 4167 | that.size.width = newWidth; | ||
| 4168 | that.size.height = newHeight; | ||
| 4169 | that.position.top = op.top - oy; | ||
| 4170 | } else if (/^(sw)$/.test(a)) { | ||
| 4171 | that.size.width = newWidth; | ||
| 4172 | that.size.height = newHeight; | ||
| 4173 | that.position.left = op.left - ox; | ||
| 4174 | } else { | ||
| 4175 | if ( newHeight - gridY <= 0 || newWidth - gridX <= 0) { | ||
| 4176 | outerDimensions = that._getPaddingPlusBorderDimensions( this ); | ||
| 4177 | } | ||
| 4178 | |||
| 4179 | if ( newHeight - gridY > 0 ) { | ||
| 4180 | that.size.height = newHeight; | ||
| 4181 | that.position.top = op.top - oy; | ||
| 4182 | } else { | ||
| 4183 | newHeight = gridY - outerDimensions.height; | ||
| 4184 | that.size.height = newHeight; | ||
| 4185 | that.position.top = op.top + os.height - newHeight; | ||
| 4186 | } | ||
| 4187 | if ( newWidth - gridX > 0 ) { | ||
| 4188 | that.size.width = newWidth; | ||
| 4189 | that.position.left = op.left - ox; | ||
| 4190 | } else { | ||
| 4191 | newWidth = gridX - outerDimensions.width; | ||
| 4192 | that.size.width = newWidth; | ||
| 4193 | that.position.left = op.left + os.width - newWidth; | ||
| 4194 | } | ||
| 4195 | } | ||
| 4196 | } | ||
| 4197 | |||
| 4198 | }); | ||
| 4199 | |||
| 4200 | var resizable = $.ui.resizable; | ||
| 4201 | |||
| 4202 | |||
| 4203 | /*! | ||
| 4204 | * jQuery UI Selectable 1.11.4 | ||
| 4205 | * http://jqueryui.com | ||
| 4206 | * | ||
| 4207 | * Copyright jQuery Foundation and other contributors | ||
| 4208 | * Released under the MIT license. | ||
| 4209 | * http://jquery.org/license | ||
| 4210 | * | ||
| 4211 | * http://api.jqueryui.com/selectable/ | ||
| 4212 | */ | ||
| 4213 | |||
| 4214 | |||
| 4215 | var selectable = $.widget("ui.selectable", $.ui.mouse, { | ||
| 4216 | version: "1.11.4", | ||
| 4217 | options: { | ||
| 4218 | appendTo: "body", | ||
| 4219 | autoRefresh: true, | ||
| 4220 | distance: 0, | ||
| 4221 | filter: "*", | ||
| 4222 | tolerance: "touch", | ||
| 4223 | |||
| 4224 | // callbacks | ||
| 4225 | selected: null, | ||
| 4226 | selecting: null, | ||
| 4227 | start: null, | ||
| 4228 | stop: null, | ||
| 4229 | unselected: null, | ||
| 4230 | unselecting: null | ||
| 4231 | }, | ||
| 4232 | _create: function() { | ||
| 4233 | var selectees, | ||
| 4234 | that = this; | ||
| 4235 | |||
| 4236 | this.element.addClass("ui-selectable"); | ||
| 4237 | |||
| 4238 | this.dragged = false; | ||
| 4239 | |||
| 4240 | // cache selectee children based on filter | ||
| 4241 | this.refresh = function() { | ||
| 4242 | selectees = $(that.options.filter, that.element[0]); | ||
| 4243 | selectees.addClass("ui-selectee"); | ||
| 4244 | selectees.each(function() { | ||
| 4245 | var $this = $(this), | ||
| 4246 | pos = $this.offset(); | ||
| 4247 | $.data(this, "selectable-item", { | ||
| 4248 | element: this, | ||
| 4249 | $element: $this, | ||
| 4250 | left: pos.left, | ||
| 4251 | top: pos.top, | ||
| 4252 | right: pos.left + $this.outerWidth(), | ||
| 4253 | bottom: pos.top + $this.outerHeight(), | ||
| 4254 | startselected: false, | ||
| 4255 | selected: $this.hasClass("ui-selected"), | ||
| 4256 | selecting: $this.hasClass("ui-selecting"), | ||
| 4257 | unselecting: $this.hasClass("ui-unselecting") | ||
| 4258 | }); | ||
| 4259 | }); | ||
| 4260 | }; | ||
| 4261 | this.refresh(); | ||
| 4262 | |||
| 4263 | this.selectees = selectees.addClass("ui-selectee"); | ||
| 4264 | |||
| 4265 | this._mouseInit(); | ||
| 4266 | |||
| 4267 | this.helper = $("<div class='ui-selectable-helper'></div>"); | ||
| 4268 | }, | ||
| 4269 | |||
| 4270 | _destroy: function() { | ||
| 4271 | this.selectees | ||
| 4272 | .removeClass("ui-selectee") | ||
| 4273 | .removeData("selectable-item"); | ||
| 4274 | this.element | ||
| 4275 | .removeClass("ui-selectable ui-selectable-disabled"); | ||
| 4276 | this._mouseDestroy(); | ||
| 4277 | }, | ||
| 4278 | |||
| 4279 | _mouseStart: function(event) { | ||
| 4280 | var that = this, | ||
| 4281 | options = this.options; | ||
| 4282 | |||
| 4283 | this.opos = [ event.pageX, event.pageY ]; | ||
| 4284 | |||
| 4285 | if (this.options.disabled) { | ||
| 4286 | return; | ||
| 4287 | } | ||
| 4288 | |||
| 4289 | this.selectees = $(options.filter, this.element[0]); | ||
| 4290 | |||
| 4291 | this._trigger("start", event); | ||
| 4292 | |||
| 4293 | $(options.appendTo).append(this.helper); | ||
| 4294 | // position helper (lasso) | ||
| 4295 | this.helper.css({ | ||
| 4296 | "left": event.pageX, | ||
| 4297 | "top": event.pageY, | ||
| 4298 | "width": 0, | ||
| 4299 | "height": 0 | ||
| 4300 | }); | ||
| 4301 | |||
| 4302 | if (options.autoRefresh) { | ||
| 4303 | this.refresh(); | ||
| 4304 | } | ||
| 4305 | |||
| 4306 | this.selectees.filter(".ui-selected").each(function() { | ||
| 4307 | var selectee = $.data(this, "selectable-item"); | ||
| 4308 | selectee.startselected = true; | ||
| 4309 | if (!event.metaKey && !event.ctrlKey) { | ||
| 4310 | selectee.$element.removeClass("ui-selected"); | ||
| 4311 | selectee.selected = false; | ||
| 4312 | selectee.$element.addClass("ui-unselecting"); | ||
| 4313 | selectee.unselecting = true; | ||
| 4314 | // selectable UNSELECTING callback | ||
| 4315 | that._trigger("unselecting", event, { | ||
| 4316 | unselecting: selectee.element | ||
| 4317 | }); | ||
| 4318 | } | ||
| 4319 | }); | ||
| 4320 | |||
| 4321 | $(event.target).parents().addBack().each(function() { | ||
| 4322 | var doSelect, | ||
| 4323 | selectee = $.data(this, "selectable-item"); | ||
| 4324 | if (selectee) { | ||
| 4325 | doSelect = (!event.metaKey && !event.ctrlKey) || !selectee.$element.hasClass("ui-selected"); | ||
| 4326 | selectee.$element | ||
| 4327 | .removeClass(doSelect ? "ui-unselecting" : "ui-selected") | ||
| 4328 | .addClass(doSelect ? "ui-selecting" : "ui-unselecting"); | ||
| 4329 | selectee.unselecting = !doSelect; | ||
| 4330 | selectee.selecting = doSelect; | ||
| 4331 | selectee.selected = doSelect; | ||
| 4332 | // selectable (UN)SELECTING callback | ||
| 4333 | if (doSelect) { | ||
| 4334 | that._trigger("selecting", event, { | ||
| 4335 | selecting: selectee.element | ||
| 4336 | }); | ||
| 4337 | } else { | ||
| 4338 | that._trigger("unselecting", event, { | ||
| 4339 | unselecting: selectee.element | ||
| 4340 | }); | ||
| 4341 | } | ||
| 4342 | return false; | ||
| 4343 | } | ||
| 4344 | }); | ||
| 4345 | |||
| 4346 | }, | ||
| 4347 | |||
| 4348 | _mouseDrag: function(event) { | ||
| 4349 | |||
| 4350 | this.dragged = true; | ||
| 4351 | |||
| 4352 | if (this.options.disabled) { | ||
| 4353 | return; | ||
| 4354 | } | ||
| 4355 | |||
| 4356 | var tmp, | ||
| 4357 | that = this, | ||
| 4358 | options = this.options, | ||
| 4359 | x1 = this.opos[0], | ||
| 4360 | y1 = this.opos[1], | ||
| 4361 | x2 = event.pageX, | ||
| 4362 | y2 = event.pageY; | ||
| 4363 | |||
| 4364 | if (x1 > x2) { tmp = x2; x2 = x1; x1 = tmp; } | ||
| 4365 | if (y1 > y2) { tmp = y2; y2 = y1; y1 = tmp; } | ||
| 4366 | this.helper.css({ left: x1, top: y1, width: x2 - x1, height: y2 - y1 }); | ||
| 4367 | |||
| 4368 | this.selectees.each(function() { | ||
| 4369 | var selectee = $.data(this, "selectable-item"), | ||
| 4370 | hit = false; | ||
| 4371 | |||
| 4372 | //prevent helper from being selected if appendTo: selectable | ||
| 4373 | if (!selectee || selectee.element === that.element[0]) { | ||
| 4374 | return; | ||
| 4375 | } | ||
| 4376 | |||
| 4377 | if (options.tolerance === "touch") { | ||
| 4378 | hit = ( !(selectee.left > x2 || selectee.right < x1 || selectee.top > y2 || selectee.bottom < y1) ); | ||
| 4379 | } else if (options.tolerance === "fit") { | ||
| 4380 | hit = (selectee.left > x1 && selectee.right < x2 && selectee.top > y1 && selectee.bottom < y2); | ||
| 4381 | } | ||
| 4382 | |||
| 4383 | if (hit) { | ||
| 4384 | // SELECT | ||
| 4385 | if (selectee.selected) { | ||
| 4386 | selectee.$element.removeClass("ui-selected"); | ||
| 4387 | selectee.selected = false; | ||
| 4388 | } | ||
| 4389 | if (selectee.unselecting) { | ||
| 4390 | selectee.$element.removeClass("ui-unselecting"); | ||
| 4391 | selectee.unselecting = false; | ||
| 4392 | } | ||
| 4393 | if (!selectee.selecting) { | ||
| 4394 | selectee.$element.addClass("ui-selecting"); | ||
| 4395 | selectee.selecting = true; | ||
| 4396 | // selectable SELECTING callback | ||
| 4397 | that._trigger("selecting", event, { | ||
| 4398 | selecting: selectee.element | ||
| 4399 | }); | ||
| 4400 | } | ||
| 4401 | } else { | ||
| 4402 | // UNSELECT | ||
| 4403 | if (selectee.selecting) { | ||
| 4404 | if ((event.metaKey || event.ctrlKey) && selectee.startselected) { | ||
| 4405 | selectee.$element.removeClass("ui-selecting"); | ||
| 4406 | selectee.selecting = false; | ||
| 4407 | selectee.$element.addClass("ui-selected"); | ||
| 4408 | selectee.selected = true; | ||
| 4409 | } else { | ||
| 4410 | selectee.$element.removeClass("ui-selecting"); | ||
| 4411 | selectee.selecting = false; | ||
| 4412 | if (selectee.startselected) { | ||
| 4413 | selectee.$element.addClass("ui-unselecting"); | ||
| 4414 | selectee.unselecting = true; | ||
| 4415 | } | ||
| 4416 | // selectable UNSELECTING callback | ||
| 4417 | that._trigger("unselecting", event, { | ||
| 4418 | unselecting: selectee.element | ||
| 4419 | }); | ||
| 4420 | } | ||
| 4421 | } | ||
| 4422 | if (selectee.selected) { | ||
| 4423 | if (!event.metaKey && !event.ctrlKey && !selectee.startselected) { | ||
| 4424 | selectee.$element.removeClass("ui-selected"); | ||
| 4425 | selectee.selected = false; | ||
| 4426 | |||
| 4427 | selectee.$element.addClass("ui-unselecting"); | ||
| 4428 | selectee.unselecting = true; | ||
| 4429 | // selectable UNSELECTING callback | ||
| 4430 | that._trigger("unselecting", event, { | ||
| 4431 | unselecting: selectee.element | ||
| 4432 | }); | ||
| 4433 | } | ||
| 4434 | } | ||
| 4435 | } | ||
| 4436 | }); | ||
| 4437 | |||
| 4438 | return false; | ||
| 4439 | }, | ||
| 4440 | |||
| 4441 | _mouseStop: function(event) { | ||
| 4442 | var that = this; | ||
| 4443 | |||
| 4444 | this.dragged = false; | ||
| 4445 | |||
| 4446 | $(".ui-unselecting", this.element[0]).each(function() { | ||
| 4447 | var selectee = $.data(this, "selectable-item"); | ||
| 4448 | selectee.$element.removeClass("ui-unselecting"); | ||
| 4449 | selectee.unselecting = false; | ||
| 4450 | selectee.startselected = false; | ||
| 4451 | that._trigger("unselected", event, { | ||
| 4452 | unselected: selectee.element | ||
| 4453 | }); | ||
| 4454 | }); | ||
| 4455 | $(".ui-selecting", this.element[0]).each(function() { | ||
| 4456 | var selectee = $.data(this, "selectable-item"); | ||
| 4457 | selectee.$element.removeClass("ui-selecting").addClass("ui-selected"); | ||
| 4458 | selectee.selecting = false; | ||
| 4459 | selectee.selected = true; | ||
| 4460 | selectee.startselected = true; | ||
| 4461 | that._trigger("selected", event, { | ||
| 4462 | selected: selectee.element | ||
| 4463 | }); | ||
| 4464 | }); | ||
| 4465 | this._trigger("stop", event); | ||
| 4466 | |||
| 4467 | this.helper.remove(); | ||
| 4468 | |||
| 4469 | return false; | ||
| 4470 | } | ||
| 4471 | |||
| 4472 | }); | ||
| 4473 | |||
| 4474 | |||
| 4475 | /*! | ||
| 4476 | * jQuery UI Sortable 1.11.4 | ||
| 4477 | * http://jqueryui.com | ||
| 4478 | * | ||
| 4479 | * Copyright jQuery Foundation and other contributors | ||
| 4480 | * Released under the MIT license. | ||
| 4481 | * http://jquery.org/license | ||
| 4482 | * | ||
| 4483 | * http://api.jqueryui.com/sortable/ | ||
| 4484 | */ | ||
| 4485 | |||
| 4486 | |||
| 4487 | var sortable = $.widget("ui.sortable", $.ui.mouse, { | ||
| 4488 | version: "1.11.4", | ||
| 4489 | widgetEventPrefix: "sort", | ||
| 4490 | ready: false, | ||
| 4491 | options: { | ||
| 4492 | appendTo: "parent", | ||
| 4493 | axis: false, | ||
| 4494 | connectWith: false, | ||
| 4495 | containment: false, | ||
| 4496 | cursor: "auto", | ||
| 4497 | cursorAt: false, | ||
| 4498 | dropOnEmpty: true, | ||
| 4499 | forcePlaceholderSize: false, | ||
| 4500 | forceHelperSize: false, | ||
| 4501 | grid: false, | ||
| 4502 | handle: false, | ||
| 4503 | helper: "original", | ||
| 4504 | items: "> *", | ||
| 4505 | opacity: false, | ||
| 4506 | placeholder: false, | ||
| 4507 | revert: false, | ||
| 4508 | scroll: true, | ||
| 4509 | scrollSensitivity: 20, | ||
| 4510 | scrollSpeed: 20, | ||
| 4511 | scope: "default", | ||
| 4512 | tolerance: "intersect", | ||
| 4513 | zIndex: 1000, | ||
| 4514 | |||
| 4515 | // callbacks | ||
| 4516 | activate: null, | ||
| 4517 | beforeStop: null, | ||
| 4518 | change: null, | ||
| 4519 | deactivate: null, | ||
| 4520 | out: null, | ||
| 4521 | over: null, | ||
| 4522 | receive: null, | ||
| 4523 | remove: null, | ||
| 4524 | sort: null, | ||
| 4525 | start: null, | ||
| 4526 | stop: null, | ||
| 4527 | update: null | ||
| 4528 | }, | ||
| 4529 | |||
| 4530 | _isOverAxis: function( x, reference, size ) { | ||
| 4531 | return ( x >= reference ) && ( x < ( reference + size ) ); | ||
| 4532 | }, | ||
| 4533 | |||
| 4534 | _isFloating: function( item ) { | ||
| 4535 | return (/left|right/).test(item.css("float")) || (/inline|table-cell/).test(item.css("display")); | ||
| 4536 | }, | ||
| 4537 | |||
| 4538 | _create: function() { | ||
| 4539 | this.containerCache = {}; | ||
| 4540 | this.element.addClass("ui-sortable"); | ||
| 4541 | |||
| 4542 | //Get the items | ||
| 4543 | this.refresh(); | ||
| 4544 | |||
| 4545 | //Let's determine the parent's offset | ||
| 4546 | this.offset = this.element.offset(); | ||
| 4547 | |||
| 4548 | //Initialize mouse events for interaction | ||
| 4549 | this._mouseInit(); | ||
| 4550 | |||
| 4551 | this._setHandleClassName(); | ||
| 4552 | |||
| 4553 | //We're ready to go | ||
| 4554 | this.ready = true; | ||
| 4555 | |||
| 4556 | }, | ||
| 4557 | |||
| 4558 | _setOption: function( key, value ) { | ||
| 4559 | this._super( key, value ); | ||
| 4560 | |||
| 4561 | if ( key === "handle" ) { | ||
| 4562 | this._setHandleClassName(); | ||
| 4563 | } | ||
| 4564 | }, | ||
| 4565 | |||
| 4566 | _setHandleClassName: function() { | ||
| 4567 | this.element.find( ".ui-sortable-handle" ).removeClass( "ui-sortable-handle" ); | ||
| 4568 | $.each( this.items, function() { | ||
| 4569 | ( this.instance.options.handle ? | ||
| 4570 | this.item.find( this.instance.options.handle ) : this.item ) | ||
| 4571 | .addClass( "ui-sortable-handle" ); | ||
| 4572 | }); | ||
| 4573 | }, | ||
| 4574 | |||
| 4575 | _destroy: function() { | ||
| 4576 | this.element | ||
| 4577 | .removeClass( "ui-sortable ui-sortable-disabled" ) | ||
| 4578 | .find( ".ui-sortable-handle" ) | ||
| 4579 | .removeClass( "ui-sortable-handle" ); | ||
| 4580 | this._mouseDestroy(); | ||
| 4581 | |||
| 4582 | for ( var i = this.items.length - 1; i >= 0; i-- ) { | ||
| 4583 | this.items[i].item.removeData(this.widgetName + "-item"); | ||
| 4584 | } | ||
| 4585 | |||
| 4586 | return this; | ||
| 4587 | }, | ||
| 4588 | |||
| 4589 | _mouseCapture: function(event, overrideHandle) { | ||
| 4590 | var currentItem = null, | ||
| 4591 | validHandle = false, | ||
| 4592 | that = this; | ||
| 4593 | |||
| 4594 | if (this.reverting) { | ||
| 4595 | return false; | ||
| 4596 | } | ||
| 4597 | |||
| 4598 | if(this.options.disabled || this.options.type === "static") { | ||
| 4599 | return false; | ||
| 4600 | } | ||
| 4601 | |||
| 4602 | //We have to refresh the items data once first | ||
| 4603 | this._refreshItems(event); | ||
| 4604 | |||
| 4605 | //Find out if the clicked node (or one of its parents) is a actual item in this.items | ||
| 4606 | $(event.target).parents().each(function() { | ||
| 4607 | if($.data(this, that.widgetName + "-item") === that) { | ||
| 4608 | currentItem = $(this); | ||
| 4609 | return false; | ||
| 4610 | } | ||
| 4611 | }); | ||
| 4612 | if($.data(event.target, that.widgetName + "-item") === that) { | ||
| 4613 | currentItem = $(event.target); | ||
| 4614 | } | ||
| 4615 | |||
| 4616 | if(!currentItem) { | ||
| 4617 | return false; | ||
| 4618 | } | ||
| 4619 | if(this.options.handle && !overrideHandle) { | ||
| 4620 | $(this.options.handle, currentItem).find("*").addBack().each(function() { | ||
| 4621 | if(this === event.target) { | ||
| 4622 | validHandle = true; | ||
| 4623 | } | ||
| 4624 | }); | ||
| 4625 | if(!validHandle) { | ||
| 4626 | return false; | ||
| 4627 | } | ||
| 4628 | } | ||
| 4629 | |||
| 4630 | this.currentItem = currentItem; | ||
| 4631 | this._removeCurrentsFromItems(); | ||
| 4632 | return true; | ||
| 4633 | |||
| 4634 | }, | ||
| 4635 | |||
| 4636 | _mouseStart: function(event, overrideHandle, noActivation) { | ||
| 4637 | |||
| 4638 | var i, body, | ||
| 4639 | o = this.options; | ||
| 4640 | |||
| 4641 | this.currentContainer = this; | ||
| 4642 | |||
| 4643 | //We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture | ||
| 4644 | this.refreshPositions(); | ||
| 4645 | |||
| 4646 | //Create and append the visible helper | ||
| 4647 | this.helper = this._createHelper(event); | ||
| 4648 | |||
| 4649 | //Cache the helper size | ||
| 4650 | this._cacheHelperProportions(); | ||
| 4651 | |||
| 4652 | /* | ||
| 4653 | * - Position generation - | ||
| 4654 | * This block generates everything position related - it's the core of draggables. | ||
| 4655 | */ | ||
| 4656 | |||
| 4657 | //Cache the margins of the original element | ||
| 4658 | this._cacheMargins(); | ||
| 4659 | |||
| 4660 | //Get the next scrolling parent | ||
| 4661 | this.scrollParent = this.helper.scrollParent(); | ||
| 4662 | |||
| 4663 | //The element's absolute position on the page minus margins | ||
| 4664 | this.offset = this.currentItem.offset(); | ||
| 4665 | this.offset = { | ||
| 4666 | top: this.offset.top - this.margins.top, | ||
| 4667 | left: this.offset.left - this.margins.left | ||
| 4668 | }; | ||
| 4669 | |||
| 4670 | $.extend(this.offset, { | ||
| 4671 | click: { //Where the click happened, relative to the element | ||
| 4672 | left: event.pageX - this.offset.left, | ||
| 4673 | top: event.pageY - this.offset.top | ||
| 4674 | }, | ||
| 4675 | parent: this._getParentOffset(), | ||
| 4676 | relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper | ||
| 4677 | }); | ||
| 4678 | |||
| 4679 | // Only after we got the offset, we can change the helper's position to absolute | ||
| 4680 | // TODO: Still need to figure out a way to make relative sorting possible | ||
| 4681 | this.helper.css("position", "absolute"); | ||
| 4682 | this.cssPosition = this.helper.css("position"); | ||
| 4683 | |||
| 4684 | //Generate the original position | ||
| 4685 | this.originalPosition = this._generatePosition(event); | ||
| 4686 | this.originalPageX = event.pageX; | ||
| 4687 | this.originalPageY = event.pageY; | ||
| 4688 | |||
| 4689 | //Adjust the mouse offset relative to the helper if "cursorAt" is supplied | ||
| 4690 | (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt)); | ||
| 4691 | |||
| 4692 | //Cache the former DOM position | ||
| 4693 | this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] }; | ||
| 4694 | |||
| 4695 | //If the helper is not the original, hide the original so it's not playing any role during the drag, won't cause anything bad this way | ||
| 4696 | if(this.helper[0] !== this.currentItem[0]) { | ||
| 4697 | this.currentItem.hide(); | ||
| 4698 | } | ||
| 4699 | |||
| 4700 | //Create the placeholder | ||
| 4701 | this._createPlaceholder(); | ||
| 4702 | |||
| 4703 | //Set a containment if given in the options | ||
| 4704 | if(o.containment) { | ||
| 4705 | this._setContainment(); | ||
| 4706 | } | ||
| 4707 | |||
| 4708 | if( o.cursor && o.cursor !== "auto" ) { // cursor option | ||
| 4709 | body = this.document.find( "body" ); | ||
| 4710 | |||
| 4711 | // support: IE | ||
| 4712 | this.storedCursor = body.css( "cursor" ); | ||
| 4713 | body.css( "cursor", o.cursor ); | ||
| 4714 | |||
| 4715 | this.storedStylesheet = $( "<style>*{ cursor: "+o.cursor+" !important; }</style>" ).appendTo( body ); | ||
| 4716 | } | ||
| 4717 | |||
| 4718 | if(o.opacity) { // opacity option | ||
| 4719 | if (this.helper.css("opacity")) { | ||
| 4720 | this._storedOpacity = this.helper.css("opacity"); | ||
| 4721 | } | ||
| 4722 | this.helper.css("opacity", o.opacity); | ||
| 4723 | } | ||
| 4724 | |||
| 4725 | if(o.zIndex) { // zIndex option | ||
| 4726 | if (this.helper.css("zIndex")) { | ||
| 4727 | this._storedZIndex = this.helper.css("zIndex"); | ||
| 4728 | } | ||
| 4729 | this.helper.css("zIndex", o.zIndex); | ||
| 4730 | } | ||
| 4731 | |||
| 4732 | //Prepare scrolling | ||
| 4733 | if(this.scrollParent[0] !== this.document[0] && this.scrollParent[0].tagName !== "HTML") { | ||
| 4734 | this.overflowOffset = this.scrollParent.offset(); | ||
| 4735 | } | ||
| 4736 | |||
| 4737 | //Call callbacks | ||
| 4738 | this._trigger("start", event, this._uiHash()); | ||
| 4739 | |||
| 4740 | //Recache the helper size | ||
| 4741 | if(!this._preserveHelperProportions) { | ||
| 4742 | this._cacheHelperProportions(); | ||
| 4743 | } | ||
| 4744 | |||
| 4745 | |||
| 4746 | //Post "activate" events to possible containers | ||
| 4747 | if( !noActivation ) { | ||
| 4748 | for ( i = this.containers.length - 1; i >= 0; i-- ) { | ||
| 4749 | this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) ); | ||
| 4750 | } | ||
| 4751 | } | ||
| 4752 | |||
| 4753 | //Prepare possible droppables | ||
| 4754 | if($.ui.ddmanager) { | ||
| 4755 | $.ui.ddmanager.current = this; | ||
| 4756 | } | ||
| 4757 | |||
| 4758 | if ($.ui.ddmanager && !o.dropBehaviour) { | ||
| 4759 | $.ui.ddmanager.prepareOffsets(this, event); | ||
| 4760 | } | ||
| 4761 | |||
| 4762 | this.dragging = true; | ||
| 4763 | |||
| 4764 | this.helper.addClass("ui-sortable-helper"); | ||
| 4765 | this._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position | ||
| 4766 | return true; | ||
| 4767 | |||
| 4768 | }, | ||
| 4769 | |||
| 4770 | _mouseDrag: function(event) { | ||
| 4771 | var i, item, itemElement, intersection, | ||
| 4772 | o = this.options, | ||
| 4773 | scrolled = false; | ||
| 4774 | |||
| 4775 | //Compute the helpers position | ||
| 4776 | this.position = this._generatePosition(event); | ||
| 4777 | this.positionAbs = this._convertPositionTo("absolute"); | ||
| 4778 | |||
| 4779 | if (!this.lastPositionAbs) { | ||
| 4780 | this.lastPositionAbs = this.positionAbs; | ||
| 4781 | } | ||
| 4782 | |||
| 4783 | //Do scrolling | ||
| 4784 | if(this.options.scroll) { | ||
| 4785 | if(this.scrollParent[0] !== this.document[0] && this.scrollParent[0].tagName !== "HTML") { | ||
| 4786 | |||
| 4787 | if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) { | ||
| 4788 | this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed; | ||
| 4789 | } else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity) { | ||
| 4790 | this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed; | ||
| 4791 | } | ||
| 4792 | |||
| 4793 | if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) { | ||
| 4794 | this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed; | ||
| 4795 | } else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity) { | ||
| 4796 | this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed; | ||
| 4797 | } | ||
| 4798 | |||
| 4799 | } else { | ||
| 4800 | |||
| 4801 | if(event.pageY - this.document.scrollTop() < o.scrollSensitivity) { | ||
| 4802 | scrolled = this.document.scrollTop(this.document.scrollTop() - o.scrollSpeed); | ||
| 4803 | } else if(this.window.height() - (event.pageY - this.document.scrollTop()) < o.scrollSensitivity) { | ||
| 4804 | scrolled = this.document.scrollTop(this.document.scrollTop() + o.scrollSpeed); | ||
| 4805 | } | ||
| 4806 | |||
| 4807 | if(event.pageX - this.document.scrollLeft() < o.scrollSensitivity) { | ||
| 4808 | scrolled = this.document.scrollLeft(this.document.scrollLeft() - o.scrollSpeed); | ||
| 4809 | } else if(this.window.width() - (event.pageX - this.document.scrollLeft()) < o.scrollSensitivity) { | ||
| 4810 | scrolled = this.document.scrollLeft(this.document.scrollLeft() + o.scrollSpeed); | ||
| 4811 | } | ||
| 4812 | |||
| 4813 | } | ||
| 4814 | |||
| 4815 | if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) { | ||
| 4816 | $.ui.ddmanager.prepareOffsets(this, event); | ||
| 4817 | } | ||
| 4818 | } | ||
| 4819 | |||
| 4820 | //Regenerate the absolute position used for position checks | ||
| 4821 | this.positionAbs = this._convertPositionTo("absolute"); | ||
| 4822 | |||
| 4823 | //Set the helper position | ||
| 4824 | if(!this.options.axis || this.options.axis !== "y") { | ||
| 4825 | this.helper[0].style.left = this.position.left+"px"; | ||
| 4826 | } | ||
| 4827 | if(!this.options.axis || this.options.axis !== "x") { | ||
| 4828 | this.helper[0].style.top = this.position.top+"px"; | ||
| 4829 | } | ||
| 4830 | |||
| 4831 | //Rearrange | ||
| 4832 | for (i = this.items.length - 1; i >= 0; i--) { | ||
| 4833 | |||
| 4834 | //Cache variables and intersection, continue if no intersection | ||
| 4835 | item = this.items[i]; | ||
| 4836 | itemElement = item.item[0]; | ||
| 4837 | intersection = this._intersectsWithPointer(item); | ||
| 4838 | if (!intersection) { | ||
| 4839 | continue; | ||
| 4840 | } | ||
| 4841 | |||
| 4842 | // Only put the placeholder inside the current Container, skip all | ||
| 4843 | // items from other containers. This works because when moving | ||
| 4844 | // an item from one container to another the | ||
| 4845 | // currentContainer is switched before the placeholder is moved. | ||
| 4846 | // | ||
| 4847 | // Without this, moving items in "sub-sortables" can cause | ||
| 4848 | // the placeholder to jitter between the outer and inner container. | ||
| 4849 | if (item.instance !== this.currentContainer) { | ||
| 4850 | continue; | ||
| 4851 | } | ||
| 4852 | |||
| 4853 | // cannot intersect with itself | ||
| 4854 | // no useless actions that have been done before | ||
| 4855 | // no action if the item moved is the parent of the item checked | ||
| 4856 | if (itemElement !== this.currentItem[0] && | ||
| 4857 | this.placeholder[intersection === 1 ? "next" : "prev"]()[0] !== itemElement && | ||
| 4858 | !$.contains(this.placeholder[0], itemElement) && | ||
| 4859 | (this.options.type === "semi-dynamic" ? !$.contains(this.element[0], itemElement) : true) | ||
| 4860 | ) { | ||
| 4861 | |||
| 4862 | this.direction = intersection === 1 ? "down" : "up"; | ||
| 4863 | |||
| 4864 | if (this.options.tolerance === "pointer" || this._intersectsWithSides(item)) { | ||
| 4865 | this._rearrange(event, item); | ||
| 4866 | } else { | ||
| 4867 | break; | ||
| 4868 | } | ||
| 4869 | |||
| 4870 | this._trigger("change", event, this._uiHash()); | ||
| 4871 | break; | ||
| 4872 | } | ||
| 4873 | } | ||
| 4874 | |||
| 4875 | //Post events to containers | ||
| 4876 | this._contactContainers(event); | ||
| 4877 | |||
| 4878 | //Interconnect with droppables | ||
| 4879 | if($.ui.ddmanager) { | ||
| 4880 | $.ui.ddmanager.drag(this, event); | ||
| 4881 | } | ||
| 4882 | |||
| 4883 | //Call callbacks | ||
| 4884 | this._trigger("sort", event, this._uiHash()); | ||
| 4885 | |||
| 4886 | this.lastPositionAbs = this.positionAbs; | ||
| 4887 | return false; | ||
| 4888 | |||
| 4889 | }, | ||
| 4890 | |||
| 4891 | _mouseStop: function(event, noPropagation) { | ||
| 4892 | |||
| 4893 | if(!event) { | ||
| 4894 | return; | ||
| 4895 | } | ||
| 4896 | |||
| 4897 | //If we are using droppables, inform the manager about the drop | ||
| 4898 | if ($.ui.ddmanager && !this.options.dropBehaviour) { | ||
| 4899 | $.ui.ddmanager.drop(this, event); | ||
| 4900 | } | ||
| 4901 | |||
| 4902 | if(this.options.revert) { | ||
| 4903 | var that = this, | ||
| 4904 | cur = this.placeholder.offset(), | ||
| 4905 | axis = this.options.axis, | ||
| 4906 | animation = {}; | ||
| 4907 | |||
| 4908 | if ( !axis || axis === "x" ) { | ||
| 4909 | animation.left = cur.left - this.offset.parent.left - this.margins.left + (this.offsetParent[0] === this.document[0].body ? 0 : this.offsetParent[0].scrollLeft); | ||
| 4910 | } | ||
| 4911 | if ( !axis || axis === "y" ) { | ||
| 4912 | animation.top = cur.top - this.offset.parent.top - this.margins.top + (this.offsetParent[0] === this.document[0].body ? 0 : this.offsetParent[0].scrollTop); | ||
| 4913 | } | ||
| 4914 | this.reverting = true; | ||
| 4915 | $(this.helper).animate( animation, parseInt(this.options.revert, 10) || 500, function() { | ||
| 4916 | that._clear(event); | ||
| 4917 | }); | ||
| 4918 | } else { | ||
| 4919 | this._clear(event, noPropagation); | ||
| 4920 | } | ||
| 4921 | |||
| 4922 | return false; | ||
| 4923 | |||
| 4924 | }, | ||
| 4925 | |||
| 4926 | cancel: function() { | ||
| 4927 | |||
| 4928 | if(this.dragging) { | ||
| 4929 | |||
| 4930 | this._mouseUp({ target: null }); | ||
| 4931 | |||
| 4932 | if(this.options.helper === "original") { | ||
| 4933 | this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"); | ||
| 4934 | } else { | ||
| 4935 | this.currentItem.show(); | ||
| 4936 | } | ||
| 4937 | |||
| 4938 | //Post deactivating events to containers | ||
| 4939 | for (var i = this.containers.length - 1; i >= 0; i--){ | ||
| 4940 | this.containers[i]._trigger("deactivate", null, this._uiHash(this)); | ||
| 4941 | if(this.containers[i].containerCache.over) { | ||
| 4942 | this.containers[i]._trigger("out", null, this._uiHash(this)); | ||
| 4943 | this.containers[i].containerCache.over = 0; | ||
| 4944 | } | ||
| 4945 | } | ||
| 4946 | |||
| 4947 | } | ||
| 4948 | |||
| 4949 | if (this.placeholder) { | ||
| 4950 | //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node! | ||
| 4951 | if(this.placeholder[0].parentNode) { | ||
| 4952 | this.placeholder[0].parentNode.removeChild(this.placeholder[0]); | ||
| 4953 | } | ||
| 4954 | if(this.options.helper !== "original" && this.helper && this.helper[0].parentNode) { | ||
| 4955 | this.helper.remove(); | ||
| 4956 | } | ||
| 4957 | |||
| 4958 | $.extend(this, { | ||
| 4959 | helper: null, | ||
| 4960 | dragging: false, | ||
| 4961 | reverting: false, | ||
| 4962 | _noFinalSort: null | ||
| 4963 | }); | ||
| 4964 | |||
| 4965 | if(this.domPosition.prev) { | ||
| 4966 | $(this.domPosition.prev).after(this.currentItem); | ||
| 4967 | } else { | ||
| 4968 | $(this.domPosition.parent).prepend(this.currentItem); | ||
| 4969 | } | ||
| 4970 | } | ||
| 4971 | |||
| 4972 | return this; | ||
| 4973 | |||
| 4974 | }, | ||
| 4975 | |||
| 4976 | serialize: function(o) { | ||
| 4977 | |||
| 4978 | var items = this._getItemsAsjQuery(o && o.connected), | ||
| 4979 | str = []; | ||
| 4980 | o = o || {}; | ||
| 4981 | |||
| 4982 | $(items).each(function() { | ||
| 4983 | var res = ($(o.item || this).attr(o.attribute || "id") || "").match(o.expression || (/(.+)[\-=_](.+)/)); | ||
| 4984 | if (res) { | ||
| 4985 | str.push((o.key || res[1]+"[]")+"="+(o.key && o.expression ? res[1] : res[2])); | ||
| 4986 | } | ||
| 4987 | }); | ||
| 4988 | |||
| 4989 | if(!str.length && o.key) { | ||
| 4990 | str.push(o.key + "="); | ||
| 4991 | } | ||
| 4992 | |||
| 4993 | return str.join("&"); | ||
| 4994 | |||
| 4995 | }, | ||
| 4996 | |||
| 4997 | toArray: function(o) { | ||
| 4998 | |||
| 4999 | var items = this._getItemsAsjQuery(o && o.connected), | ||
11618 more lines aren’t shown here.
| @@ -0,0 +1,13963 @@ | |||
| 1 | /** | ||
| 2 | * PUI Object | ||
| 3 | */ | ||
| 4 | var PUI = { | ||
| 5 | |||
| 6 | zindex : 1000, | ||
| 7 | |||
| 8 | gridColumns: { | ||
| 9 | '1': 'ui-grid-col-12', | ||
| 10 | '2': 'ui-grid-col-6', | ||
| 11 | '3': 'ui-grid-col-4', | ||
| 12 | '4': 'ui-grid-col-3', | ||
| 13 | '6': 'ui-grid-col-2', | ||
| 14 | '12': 'ui-grid-col-11' | ||
| 15 | }, | ||
| 16 | |||
| 17 | charSet: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', | ||
| 18 | |||
| 19 | /** | ||
| 20 | * Aligns container scrollbar to keep item in container viewport, algorithm copied from jquery-ui menu widget | ||
| 21 | */ | ||
| 22 | scrollInView: function(container, item) { | ||
| 23 | var borderTop = parseFloat(container.css('borderTopWidth')) || 0, | ||
| 24 | paddingTop = parseFloat(container.css('paddingTop')) || 0, | ||
| 25 | offset = item.offset().top - container.offset().top - borderTop - paddingTop, | ||
| 26 | scroll = container.scrollTop(), | ||
| 27 | elementHeight = container.height(), | ||
| 28 | itemHeight = item.outerHeight(true); | ||
| 29 | |||
| 30 | if(offset < 0) { | ||
| 31 | container.scrollTop(scroll + offset); | ||
| 32 | } | ||
| 33 | else if((offset + itemHeight) > elementHeight) { | ||
| 34 | container.scrollTop(scroll + offset - elementHeight + itemHeight); | ||
| 35 | } | ||
| 36 | }, | ||
| 37 | |||
| 38 | generateRandomId: function() { | ||
| 39 | var id = ''; | ||
| 40 | for (var i = 1; i <= 10; i++) { | ||
| 41 | var randPos = Math.floor(Math.random() * this.charSet.length); | ||
| 42 | id += this.charSet[randPos]; | ||
| 43 | } | ||
| 44 | return id; | ||
| 45 | }, | ||
| 46 | |||
| 47 | isIE: function(version) { | ||
| 48 | return (this.browser.msie && parseInt(this.browser.version, 10) === version); | ||
| 49 | }, | ||
| 50 | |||
| 51 | escapeRegExp: function(text) { | ||
| 52 | return text.replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1"); | ||
| 53 | }, | ||
| 54 | |||
| 55 | escapeHTML: function(value) { | ||
| 56 | return value.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>'); | ||
| 57 | }, | ||
| 58 | |||
| 59 | escapeClientId: function(id) { | ||
| 60 | return "#" + id.replace(/:/g,"\\:"); | ||
| 61 | }, | ||
| 62 | |||
| 63 | clearSelection: function() { | ||
| 64 | if(window.getSelection) { | ||
| 65 | if(window.getSelection().empty) { | ||
| 66 | window.getSelection().empty(); | ||
| 67 | } else if(window.getSelection().removeAllRanges) { | ||
| 68 | window.getSelection().removeAllRanges(); | ||
| 69 | } | ||
| 70 | } else if(document.selection && document.selection.empty) { | ||
| 71 | document.selection.empty(); | ||
| 72 | } | ||
| 73 | }, | ||
| 74 | |||
| 75 | inArray: function(arr, item) { | ||
| 76 | for(var i = 0; i < arr.length; i++) { | ||
| 77 | if(arr[i] === item) { | ||
| 78 | return true; | ||
| 79 | } | ||
| 80 | } | ||
| 81 | |||
| 82 | return false; | ||
| 83 | }, | ||
| 84 | |||
| 85 | calculateScrollbarWidth: function() { | ||
| 86 | if(!this.scrollbarWidth) { | ||
| 87 | if(this.browser.msie) { | ||
| 88 | var $textarea1 = $('<textarea cols="10" rows="2"></textarea>') | ||
| 89 | .css({ position: 'absolute', top: -1000, left: -1000 }).appendTo('body'), | ||
| 90 | $textarea2 = $('<textarea cols="10" rows="2" style="overflow: hidden;"></textarea>') | ||
| 91 | .css({ position: 'absolute', top: -1000, left: -1000 }).appendTo('body'); | ||
| 92 | this.scrollbarWidth = $textarea1.width() - $textarea2.width(); | ||
| 93 | $textarea1.add($textarea2).remove(); | ||
| 94 | } | ||
| 95 | else { | ||
| 96 | var $div = $('<div />') | ||
| 97 | .css({ width: 100, height: 100, overflow: 'auto', position: 'absolute', top: -1000, left: -1000 }) | ||
| 98 | .prependTo('body').append('<div />').find('div') | ||
| 99 | .css({ width: '100%', height: 200 }); | ||
| 100 | this.scrollbarWidth = 100 - $div.width(); | ||
| 101 | $div.parent().remove(); | ||
| 102 | } | ||
| 103 | } | ||
| 104 | |||
| 105 | return this.scrollbarWidth; | ||
| 106 | }, | ||
| 107 | |||
| 108 | //adapted from jquery browser plugin | ||
| 109 | resolveUserAgent: function() { | ||
| 110 | var matched, browser; | ||
| 111 | |||
| 112 | jQuery.uaMatch = function( ua ) { | ||
| 113 | ua = ua.toLowerCase(); | ||
| 114 | |||
| 115 | var match = /(opr)[\/]([\w.]+)/.exec( ua ) || | ||
| 116 | /(chrome)[ \/]([\w.]+)/.exec( ua ) || | ||
| 117 | /(version)[ \/]([\w.]+).*(safari)[ \/]([\w.]+)/.exec( ua ) || | ||
| 118 | /(webkit)[ \/]([\w.]+)/.exec( ua ) || | ||
| 119 | /(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua ) || | ||
| 120 | /(msie) ([\w.]+)/.exec( ua ) || | ||
| 121 | ua.indexOf("trident") >= 0 && /(rv)(?::| )([\w.]+)/.exec( ua ) || | ||
| 122 | ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua ) || | ||
| 123 | []; | ||
| 124 | |||
| 125 | var platform_match = /(ipad)/.exec( ua ) || | ||
| 126 | /(iphone)/.exec( ua ) || | ||
| 127 | /(android)/.exec( ua ) || | ||
| 128 | /(windows phone)/.exec( ua ) || | ||
| 129 | /(win)/.exec( ua ) || | ||
| 130 | /(mac)/.exec( ua ) || | ||
| 131 | /(linux)/.exec( ua ) || | ||
| 132 | /(cros)/i.exec( ua ) || | ||
| 133 | []; | ||
| 134 | |||
| 135 | return { | ||
| 136 | browser: match[ 3 ] || match[ 1 ] || "", | ||
| 137 | version: match[ 2 ] || "0", | ||
| 138 | platform: platform_match[ 0 ] || "" | ||
| 139 | }; | ||
| 140 | }; | ||
| 141 | |||
| 142 | matched = jQuery.uaMatch( window.navigator.userAgent ); | ||
| 143 | browser = {}; | ||
| 144 | |||
| 145 | if ( matched.browser ) { | ||
| 146 | browser[ matched.browser ] = true; | ||
| 147 | browser.version = matched.version; | ||
| 148 | browser.versionNumber = parseInt(matched.version); | ||
| 149 | } | ||
| 150 | |||
| 151 | if ( matched.platform ) { | ||
| 152 | browser[ matched.platform ] = true; | ||
| 153 | } | ||
| 154 | |||
| 155 | // These are all considered mobile platforms, meaning they run a mobile browser | ||
| 156 | if ( browser.android || browser.ipad || browser.iphone || browser[ "windows phone" ] ) { | ||
| 157 | browser.mobile = true; | ||
| 158 | } | ||
| 159 | |||
| 160 | // These are all considered desktop platforms, meaning they run a desktop browser | ||
| 161 | if ( browser.cros || browser.mac || browser.linux || browser.win ) { | ||
| 162 | browser.desktop = true; | ||
| 163 | } | ||
| 164 | |||
| 165 | // Chrome, Opera 15+ and Safari are webkit based browsers | ||
| 166 | if ( browser.chrome || browser.opr || browser.safari ) { | ||
| 167 | browser.webkit = true; | ||
| 168 | } | ||
| 169 | |||
| 170 | // IE11 has a new token so we will assign it msie to avoid breaking changes | ||
| 171 | if ( browser.rv ) | ||
| 172 | { | ||
| 173 | var ie = "msie"; | ||
| 174 | |||
| 175 | matched.browser = ie; | ||
| 176 | browser[ie] = true; | ||
| 177 | } | ||
| 178 | |||
| 179 | // Opera 15+ are identified as opr | ||
| 180 | if ( browser.opr ) | ||
| 181 | { | ||
| 182 | var opera = "opera"; | ||
| 183 | |||
| 184 | matched.browser = opera; | ||
| 185 | browser[opera] = true; | ||
| 186 | } | ||
| 187 | |||
| 188 | // Stock Android browsers are marked as Safari on Android. | ||
| 189 | if ( browser.safari && browser.android ) | ||
| 190 | { | ||
| 191 | var android = "android"; | ||
| 192 | |||
| 193 | matched.browser = android; | ||
| 194 | browser[android] = true; | ||
| 195 | } | ||
| 196 | |||
| 197 | // Assign the name and platform variable | ||
| 198 | browser.name = matched.browser; | ||
| 199 | browser.platform = matched.platform; | ||
| 200 | |||
| 201 | this.browser = browser; | ||
| 202 | $.browser = browser; | ||
| 203 | }, | ||
| 204 | |||
| 205 | getGridColumn: function(number) { | ||
| 206 | return this.gridColumns[number + '']; | ||
| 207 | }, | ||
| 208 | |||
| 209 | executeFunctionByName: function(functionName /*, args */) { | ||
| 210 | var args = [].slice.call(arguments).splice(1), | ||
| 211 | context = window, | ||
| 212 | namespaces = functionName.split("."), | ||
| 213 | func = namespaces.pop(); | ||
| 214 | for(var i = 0; i < namespaces.length; i++) { | ||
| 215 | context = context[namespaces[i]]; | ||
| 216 | } | ||
| 217 | return context[func].apply(this, args); | ||
| 218 | }, | ||
| 219 | |||
| 220 | resolveObjectByName: function(name) { | ||
| 221 | if(name) { | ||
| 222 | var parts = name.split("."); | ||
| 223 | for(var i = 0, len = parts.length, obj = window; i < len; ++i) { | ||
| 224 | obj = obj[parts[i]]; | ||
| 225 | } | ||
| 226 | return obj; | ||
| 227 | } | ||
| 228 | else { | ||
| 229 | return null; | ||
| 230 | } | ||
| 231 | }, | ||
| 232 | |||
| 233 | getCookie : function(name) { | ||
| 234 | return $.cookie(name); | ||
| 235 | }, | ||
| 236 | |||
| 237 | setCookie : function(name, value, cfg) { | ||
| 238 | $.cookie(name, value, cfg); | ||
| 239 | }, | ||
| 240 | |||
| 241 | deleteCookie: function(name, cfg) { | ||
| 242 | $.removeCookie(name, cfg); | ||
| 243 | } | ||
| 244 | |||
| 245 | }; | ||
| 246 | |||
| 247 | PUI.resolveUserAgent(); | ||
| 248 | /** | ||
| 249 | * PrimeUI Accordion widget | ||
| 250 | */ | ||
| 251 | (function() { | ||
| 252 | |||
| 253 | $.widget("primeui.puiaccordion", { | ||
| 254 | |||
| 255 | options: { | ||
| 256 | activeIndex: 0, | ||
| 257 | multiple: false | ||
| 258 | }, | ||
| 259 | |||
| 260 | _create: function() { | ||
| 261 | if(this.options.multiple) { | ||
| 262 | this.options.activeIndex = this.options.activeIndex||[0]; | ||
| 263 | } | ||
| 264 | |||
| 265 | var $this = this; | ||
| 266 | this.element.addClass('ui-accordion ui-widget ui-helper-reset'); | ||
| 267 | |||
| 268 | var tabContainers = this.element.children(); | ||
| 269 | |||
| 270 | //primeui | ||
| 271 | if(tabContainers.is('div')) { | ||
| 272 | this.panelMode = 'native'; | ||
| 273 | this.headers = this.element.children('h3'); | ||
| 274 | this.panels = this.element.children('div'); | ||
| 275 | } | ||
| 276 | //primeng | ||
| 277 | else { | ||
| 278 | this.panelMode = 'wrapped'; | ||
| 279 | this.headers = tabContainers.children('h3'); | ||
| 280 | this.panels = tabContainers.children('div'); | ||
| 281 | } | ||
| 282 | |||
| 283 | this.headers.addClass('ui-accordion-header ui-helper-reset ui-state-default').each(function(i) { | ||
| 284 | var header = $(this), | ||
| 285 | title = header.html(), | ||
| 286 | active = $this.options.multiple ? ($.inArray(i, $this.options.activeIndex) !== -1) : (i == $this.options.activeIndex), | ||
| 287 | headerClass = (active) ? 'ui-state-active ui-corner-top' : 'ui-corner-all', | ||
| 288 | iconClass = (active) ? 'fa fa-fw fa-caret-down' : 'fa fa-fw fa-caret-right'; | ||
| 289 | |||
| 290 | header.addClass(headerClass).html('<span class="' + iconClass + '"></span><a href="#">' + title + '</a>'); | ||
| 291 | }); | ||
| 292 | |||
| 293 | this.panels.each(function(i) { | ||
| 294 | var content = $(this); | ||
| 295 | content.addClass('ui-accordion-content ui-helper-reset ui-widget-content'), | ||
| 296 | active = $this.options.multiple ? ($.inArray(i, $this.options.activeIndex) !== -1) : (i == $this.options.activeIndex); | ||
| 297 | |||
| 298 | if(!active) { | ||
| 299 | content.addClass('ui-helper-hidden'); | ||
| 300 | } | ||
| 301 | }); | ||
| 302 | |||
| 303 | this.headers.children('a').disableSelection(); | ||
| 304 | |||
| 305 | this._bindEvents(); | ||
| 306 | }, | ||
| 307 | |||
| 308 | _destroy: function() { | ||
| 309 | this._unbindEvents(); | ||
| 310 | this.element.removeClass('ui-accordion ui-widget ui-helper-reset'); | ||
| 311 | this.headers.removeClass('ui-accordion-header ui-helper-reset ui-state-default ui-state-hover ui-state-active ui-state-disabled ui-corner-all ui-corner-top'); | ||
| 312 | this.panels.removeClass('ui-accordion-content ui-helper-reset ui-widget-content ui-helper-hidden'); | ||
| 313 | this.headers.children('.fa').remove(); | ||
| 314 | this.headers.children('a').contents().unwrap(); | ||
| 315 | }, | ||
| 316 | |||
| 317 | _bindEvents: function() { | ||
| 318 | var $this = this; | ||
| 319 | |||
| 320 | this.headers.on('mouseover.puiaccordion', function() { | ||
| 321 | var element = $(this); | ||
| 322 | if(!element.hasClass('ui-state-active')&&!element.hasClass('ui-state-disabled')) { | ||
| 323 | element.addClass('ui-state-hover'); | ||
| 324 | } | ||
| 325 | }).on('mouseout.puiaccordion', function() { | ||
| 326 | var element = $(this); | ||
| 327 | if(!element.hasClass('ui-state-active')&&!element.hasClass('ui-state-disabled')) { | ||
| 328 | element.removeClass('ui-state-hover'); | ||
| 329 | } | ||
| 330 | }).on('click.puiaccordion', function(e) { | ||
| 331 | var element = $(this); | ||
| 332 | if(!element.hasClass('ui-state-disabled')) { | ||
| 333 | var tabIndex = ($this.panelMode === 'native') ? element.index() / 2 : element.parent().index(); | ||
| 334 | |||
| 335 | if(element.hasClass('ui-state-active')) { | ||
| 336 | $this.unselect(tabIndex); | ||
| 337 | } | ||
| 338 | else { | ||
| 339 | $this.select(tabIndex, false); | ||
| 340 | } | ||
| 341 | } | ||
| 342 | |||
| 343 | e.preventDefault(); | ||
| 344 | }); | ||
| 345 | }, | ||
| 346 | |||
| 347 | _unbindEvents: function() { | ||
| 348 | this.headers.off('mouseover.puiaccordion mouseout.puiaccordion click.puiaccordion'); | ||
| 349 | }, | ||
| 350 | |||
| 351 | /** | ||
| 352 | * Activates a tab with given index | ||
| 353 | */ | ||
| 354 | select: function(index, silent) { | ||
| 355 | var panel = this.panels.eq(index); | ||
| 356 | |||
| 357 | if(!silent) { | ||
| 358 | this._trigger('change', null, {'index': index}); | ||
| 359 | } | ||
| 360 | |||
| 361 | //update state | ||
| 362 | if(this.options.multiple) { | ||
| 363 | this._addToSelection(index); | ||
| 364 | } | ||
| 365 | else { | ||
| 366 | this.options.activeIndex = index; | ||
| 367 | } | ||
| 368 | this._show(panel); | ||
| 369 | }, | ||
| 370 | |||
| 371 | /** | ||
| 372 | * Deactivates a tab with given index | ||
| 373 | */ | ||
| 374 | unselect: function(index) { | ||
| 375 | var panel = this.panels.eq(index), | ||
| 376 | header = panel.prev(); | ||
| 377 | |||
| 378 | header.attr('aria-expanded', false).children('.fa').removeClass('fa-caret-down').addClass('fa-caret-right'); | ||
| 379 | header.removeClass('ui-state-active ui-corner-top').addClass('ui-corner-all'); | ||
| 380 | panel.attr('aria-hidden', true).slideUp(); | ||
| 381 | |||
| 382 | this._removeFromSelection(index); | ||
| 383 | }, | ||
| 384 | |||
| 385 | _show: function(panel) { | ||
| 386 | //deactivate current | ||
| 387 | if(!this.options.multiple) { | ||
| 388 | var oldHeader = this.headers.filter('.ui-state-active'); | ||
| 389 | oldHeader.children('.fa').removeClass('fa-caret-down').addClass('fa-caret-right'); | ||
| 390 | oldHeader.attr('aria-expanded', false).removeClass('ui-state-active ui-corner-top').addClass('ui-corner-all').next().attr('aria-hidden', true).slideUp(); | ||
| 391 | } | ||
| 392 | |||
| 393 | //activate selected | ||
| 394 | var newHeader = panel.prev(); | ||
| 395 | newHeader.attr('aria-expanded', true).addClass('ui-state-active ui-corner-top').removeClass('ui-state-hover ui-corner-all') | ||
| 396 | .children('.fa').removeClass('fa-caret-right').addClass('fa-caret-down'); | ||
| 397 | |||
| 398 | panel.attr('aria-hidden', false).slideDown('normal'); | ||
| 399 | }, | ||
| 400 | |||
| 401 | _addToSelection: function(nodeId) { | ||
| 402 | this.options.activeIndex.push(nodeId); | ||
| 403 | }, | ||
| 404 | |||
| 405 | _removeFromSelection: function(index) { | ||
| 406 | this.options.activeIndex = $.grep(this.options.activeIndex, function(r) { | ||
| 407 | return r != index; | ||
| 408 | }); | ||
| 409 | }, | ||
| 410 | |||
| 411 | _setOption: function(key, value) { | ||
| 412 | if(key === 'activeIndex') { | ||
| 413 | this.select(value, true); | ||
| 414 | } | ||
| 415 | else { | ||
| 416 | $.Widget.prototype._setOption.apply(this, arguments); | ||
| 417 | } | ||
| 418 | } | ||
| 419 | |||
| 420 | }); | ||
| 421 | })(); | ||
| 422 | /** | ||
| 423 | * PrimeUI autocomplete widget | ||
| 424 | */ | ||
| 425 | (function() { | ||
| 426 | |||
| 427 | $.widget("primeui.puiautocomplete", { | ||
| 428 | |||
| 429 | options: { | ||
| 430 | delay: 300, | ||
| 431 | minQueryLength: 1, | ||
| 432 | multiple: false, | ||
| 433 | dropdown: false, | ||
| 434 | scrollHeight: 200, | ||
| 435 | forceSelection: false, | ||
| 436 | effect:null, | ||
| 437 | effectOptions: {}, | ||
| 438 | effectSpeed: 'normal', | ||
| 439 | content: null, | ||
| 440 | caseSensitive: false | ||
| 441 | }, | ||
| 442 | |||
| 443 | _create: function() { | ||
| 444 | this.element.wrap('<span class="ui-autocomplete ui-widget" />'); | ||
| 445 | this.element.puiinputtext(); | ||
| 446 | this.panel = $('<div class="ui-autocomplete-panel ui-widget-content ui-corner-all ui-helper-hidden ui-shadow"></div>').appendTo('body'); | ||
| 447 | |||
| 448 | if(this.options.multiple) { | ||
| 449 | this.element.wrap('<ul class="ui-autocomplete-multiple ui-widget ui-inputtext ui-state-default ui-corner-all">' + | ||
| 450 | '<li class="ui-autocomplete-input-token"></li></ul>'); | ||
| 451 | this.inputContainer = this.element.parent(); | ||
| 452 | this.multiContainer = this.inputContainer.parent(); | ||
| 453 | } | ||
| 454 | else { | ||
| 455 | if(this.options.dropdown) { | ||
| 456 | this.dropdown = $('<button type="button" class="ui-autocomplete-dropdown ui-button ui-widget ui-state-default ui-corner-right ui-button-icon-only">' + | ||
| 457 | '<span class="fa fa-fw fa-caret-down"></span><span class="ui-button-text"> </span></button>') | ||
| 458 | .insertAfter(this.element); | ||
| 459 | this.element.removeClass('ui-corner-all').addClass('ui-corner-left'); | ||
| 460 | } | ||
| 461 | } | ||
| 462 | |||
| 463 | this._bindEvents(); | ||
| 464 | }, | ||
| 465 | |||
| 466 | _bindEvents: function() { | ||
| 467 | var $this = this; | ||
| 468 | |||
| 469 | this._bindKeyEvents(); | ||
| 470 | |||
| 471 | if(this.options.dropdown) { | ||
| 472 | this.dropdown.on('mouseenter.puiautocomplete', function() { | ||
| 473 | if(!$this.element.prop('disabled')) { | ||
| 474 | $this.dropdown.addClass('ui-state-hover'); | ||
| 475 | } | ||
| 476 | }) | ||
| 477 | .on('mouseleave.puiautocomplete', function() { | ||
| 478 | $this.dropdown.removeClass('ui-state-hover'); | ||
| 479 | }) | ||
| 480 | .on('mousedown.puiautocomplete', function() { | ||
| 481 | if(!$this.element.prop('disabled')) { | ||
| 482 | $this.dropdown.addClass('ui-state-active'); | ||
| 483 | } | ||
| 484 | }) | ||
| 485 | .on('mouseup.puiautocomplete', function() { | ||
| 486 | if(!$this.element.prop('disabled')) { | ||
| 487 | $this.dropdown.removeClass('ui-state-active'); | ||
| 488 | $this.search(''); | ||
| 489 | $this.element.focus(); | ||
| 490 | } | ||
| 491 | }) | ||
| 492 | .on('focus.puiautocomplete', function() { | ||
| 493 | $this.dropdown.addClass('ui-state-focus'); | ||
| 494 | }) | ||
| 495 | .on('blur.puiautocomplete', function() { | ||
| 496 | $this.dropdown.removeClass('ui-state-focus'); | ||
| 497 | }) | ||
| 498 | .on('keydown.puiautocomplete', function(e) { | ||
| 499 | var keyCode = $.ui.keyCode; | ||
| 500 | |||
| 501 | if(e.which == keyCode.ENTER || e.which == keyCode.NUMPAD_ENTER) { | ||
| 502 | $this.search(''); | ||
| 503 | $this.input.focus(); | ||
| 504 | |||
| 505 | e.preventDefault(); | ||
| 506 | } | ||
| 507 | }); | ||
| 508 | } | ||
| 509 | |||
| 510 | if(this.options.multiple) { | ||
| 511 | this.multiContainer.on('hover.puiautocomplete', function() { | ||
| 512 | $(this).toggleClass('ui-state-hover'); | ||
| 513 | }) | ||
| 514 | .on('click.puiautocomplete', function() { | ||
| 515 | $this.element.trigger('focus'); | ||
| 516 | }); | ||
| 517 | |||
| 518 | this.element.on('focus.ui-autocomplete', function() { | ||
| 519 | $this.multiContainer.addClass('ui-state-focus'); | ||
| 520 | }) | ||
| 521 | .on('blur.ui-autocomplete', function(e) { | ||
| 522 | $this.multiContainer.removeClass('ui-state-focus'); | ||
| 523 | }); | ||
| 524 | } | ||
| 525 | |||
| 526 | if(this.options.forceSelection) { | ||
| 527 | this.currentItems = [this.element.val()]; | ||
| 528 | |||
| 529 | this.element.on('blur.puiautocomplete', function() { | ||
| 530 | var value = $(this).val(), | ||
| 531 | valid = false; | ||
| 532 | |||
| 533 | for(var i = 0; i < $this.currentItems.length; i++) { | ||
| 534 | if($this.currentItems[i] === value) { | ||
| 535 | valid = true; | ||
| 536 | break; | ||
| 537 | } | ||
| 538 | } | ||
| 539 | |||
| 540 | if(!valid) { | ||
| 541 | $this.element.val(''); | ||
| 542 | } | ||
| 543 | }); | ||
| 544 | } | ||
| 545 | |||
| 546 | $(document.body).bind('mousedown.puiautocomplete', function (e) { | ||
| 547 | if($this.panel.is(":hidden")) { | ||
| 548 | return; | ||
| 549 | } | ||
| 550 | |||
| 551 | if(e.target === $this.element.get(0)) { | ||
| 552 | return; | ||
| 553 | } | ||
| 554 | |||
| 555 | var offset = $this.panel.offset(); | ||
| 556 | if (e.pageX < offset.left || | ||
| 557 | e.pageX > offset.left + $this.panel.width() || | ||
| 558 | e.pageY < offset.top || | ||
| 559 | e.pageY > offset.top + $this.panel.height()) { | ||
| 560 | $this.hide(); | ||
| 561 | } | ||
| 562 | }); | ||
| 563 | |||
| 564 | $(window).bind('resize.' + this.element.id, function() { | ||
| 565 | if($this.panel.is(':visible')) { | ||
| 566 | $this._alignPanel(); | ||
| 567 | } | ||
| 568 | }); | ||
| 569 | }, | ||
| 570 | |||
| 571 | _bindKeyEvents: function() { | ||
| 572 | var $this = this; | ||
| 573 | |||
| 574 | this.element.on('keyup.puiautocomplete', function(e) { | ||
| 575 | var keyCode = $.ui.keyCode, | ||
| 576 | key = e.which, | ||
| 577 | shouldSearch = true; | ||
| 578 | |||
| 579 | if(key == keyCode.UP || | ||
| 580 | key == keyCode.LEFT || | ||
| 581 | key == keyCode.DOWN || | ||
| 582 | key == keyCode.RIGHT || | ||
| 583 | key == keyCode.TAB || | ||
| 584 | key == keyCode.SHIFT || | ||
| 585 | key == keyCode.ENTER || | ||
| 586 | key == keyCode.NUMPAD_ENTER) { | ||
| 587 | shouldSearch = false; | ||
| 588 | } | ||
| 589 | |||
| 590 | if(shouldSearch) { | ||
| 591 | var value = $this.element.val(); | ||
| 592 | |||
| 593 | if(!value.length) { | ||
| 594 | $this.hide(); | ||
| 595 | } | ||
| 596 | |||
| 597 | if(value.length >= $this.options.minQueryLength) { | ||
| 598 | if($this.timeout) { | ||
| 599 | window.clearTimeout($this.timeout); | ||
| 600 | } | ||
| 601 | |||
| 602 | $this.timeout = window.setTimeout(function() { | ||
| 603 | $this.search(value); | ||
| 604 | }, | ||
| 605 | $this.options.delay); | ||
| 606 | } | ||
| 607 | } | ||
| 608 | |||
| 609 | }).on('keydown.puiautocomplete', function(e) { | ||
| 610 | if($this.panel.is(':visible')) { | ||
| 611 | var keyCode = $.ui.keyCode, | ||
| 612 | highlightedItem = $this.items.filter('.ui-state-highlight'); | ||
| 613 | |||
| 614 | switch(e.which) { | ||
| 615 | case keyCode.UP: | ||
| 616 | case keyCode.LEFT: | ||
| 617 | var prev = highlightedItem.prev(); | ||
| 618 | |||
| 619 | if(prev.length == 1) { | ||
| 620 | highlightedItem.removeClass('ui-state-highlight'); | ||
| 621 | prev.addClass('ui-state-highlight'); | ||
| 622 | |||
| 623 | if($this.options.scrollHeight) { | ||
| 624 | PUI.scrollInView($this.panel, prev); | ||
| 625 | } | ||
| 626 | } | ||
| 627 | |||
| 628 | e.preventDefault(); | ||
| 629 | break; | ||
| 630 | |||
| 631 | case keyCode.DOWN: | ||
| 632 | case keyCode.RIGHT: | ||
| 633 | var next = highlightedItem.next(); | ||
| 634 | |||
| 635 | if(next.length == 1) { | ||
| 636 | highlightedItem.removeClass('ui-state-highlight'); | ||
| 637 | next.addClass('ui-state-highlight'); | ||
| 638 | |||
| 639 | if($this.options.scrollHeight) { | ||
| 640 | PUI.scrollInView($this.panel, next); | ||
| 641 | } | ||
| 642 | } | ||
| 643 | |||
| 644 | e.preventDefault(); | ||
| 645 | break; | ||
| 646 | |||
| 647 | case keyCode.ENTER: | ||
| 648 | case keyCode.NUMPAD_ENTER: | ||
| 649 | highlightedItem.trigger('click'); | ||
| 650 | |||
| 651 | e.preventDefault(); | ||
| 652 | break; | ||
| 653 | |||
| 654 | case keyCode.ALT: | ||
| 655 | case 224: | ||
| 656 | break; | ||
| 657 | |||
| 658 | case keyCode.TAB: | ||
| 659 | highlightedItem.trigger('click'); | ||
| 660 | $this.hide(); | ||
| 661 | break; | ||
| 662 | } | ||
| 663 | } | ||
| 664 | |||
| 665 | }); | ||
| 666 | }, | ||
| 667 | |||
| 668 | _bindDynamicEvents: function() { | ||
| 669 | var $this = this; | ||
| 670 | |||
| 671 | this.items.on('mouseover.puiautocomplete', function() { | ||
| 672 | var item = $(this); | ||
| 673 | |||
| 674 | if(!item.hasClass('ui-state-highlight')) { | ||
| 675 | $this.items.filter('.ui-state-highlight').removeClass('ui-state-highlight'); | ||
| 676 | item.addClass('ui-state-highlight'); | ||
| 677 | } | ||
| 678 | }) | ||
| 679 | .on('click.puiautocomplete', function(event) { | ||
| 680 | var item = $(this); | ||
| 681 | |||
| 682 | if($this.options.multiple) { | ||
| 683 | var tokenMarkup = '<li class="ui-autocomplete-token ui-state-active ui-corner-all ui-helper-hidden">'; | ||
| 684 | tokenMarkup += '<span class="ui-autocomplete-token-icon fa fa-fw fa-close" />'; | ||
| 685 | tokenMarkup += '<span class="ui-autocomplete-token-label">' + item.data('label') + '</span></li>'; | ||
| 686 | |||
| 687 | $(tokenMarkup).data(item.data()) | ||
| 688 | .insertBefore($this.inputContainer).fadeIn() | ||
| 689 | .children('.ui-autocomplete-token-icon').on('click.ui-autocomplete', function(e) { | ||
| 690 | var token = $(this).parent(); | ||
| 691 | $this._removeItem(token); | ||
| 692 | $this._trigger('unselect', e, token); | ||
| 693 | }); | ||
| 694 | |||
| 695 | $this.element.val('').trigger('focus'); | ||
| 696 | } | ||
| 697 | else { | ||
| 698 | $this.element.val(item.data('label')).focus(); | ||
| 699 | } | ||
| 700 | |||
| 701 | $this._trigger('select', event, item); | ||
| 702 | $this.hide(); | ||
| 703 | }); | ||
| 704 | }, | ||
| 705 | |||
| 706 | search: function(q) { | ||
| 707 | this.query = this.options.caseSensitive ? q : q.toLowerCase(); | ||
| 708 | |||
| 709 | var request = { | ||
| 710 | query: this.query | ||
| 711 | }; | ||
| 712 | |||
| 713 | if(this.options.completeSource) { | ||
| 714 | if($.isArray(this.options.completeSource)) { | ||
| 715 | var sourceArr = this.options.completeSource, | ||
| 716 | data = [], | ||
| 717 | emptyQuery = ($.trim(q) === ''); | ||
| 718 | |||
| 719 | for(var i = 0 ; i < sourceArr.length; i++) { | ||
| 720 | var item = sourceArr[i], | ||
| 721 | itemLabel = item.label||item; | ||
| 722 | |||
| 723 | if(!this.options.caseSensitive) { | ||
| 724 | itemLabel = itemLabel.toLowerCase(); | ||
| 725 | } | ||
| 726 | |||
| 727 | if(emptyQuery||itemLabel.indexOf(this.query) === 0) { | ||
| 728 | data.push({label:sourceArr[i], value: item}); | ||
| 729 | } | ||
| 730 | } | ||
| 731 | |||
| 732 | this._handleData(data); | ||
| 733 | } | ||
| 734 | else { | ||
| 735 | this.options.completeSource.call(this, request, this._handleData); | ||
| 736 | } | ||
| 737 | } | ||
| 738 | }, | ||
| 739 | |||
| 740 | _handleData: function(data) { | ||
| 741 | var $this = this; | ||
| 742 | this.panel.html(''); | ||
| 743 | this.listContainer = $('<ul class="ui-autocomplete-items ui-autocomplete-list ui-widget-content ui-widget ui-corner-all ui-helper-reset"></ul>').appendTo(this.panel); | ||
| 744 | |||
| 745 | for(var i = 0; i < data.length; i++) { | ||
| 746 | var item = $('<li class="ui-autocomplete-item ui-autocomplete-list-item ui-corner-all"></li>'); | ||
| 747 | item.data(data[i]); | ||
| 748 | |||
| 749 | if(this.options.content) | ||
| 750 | item.html(this.options.content.call(this, data[i])); | ||
| 751 | else | ||
| 752 | item.text(data[i].label); | ||
| 753 | |||
| 754 | this.listContainer.append(item); | ||
| 755 | } | ||
| 756 | |||
| 757 | this.items = this.listContainer.children('.ui-autocomplete-item'); | ||
| 758 | |||
| 759 | this._bindDynamicEvents(); | ||
| 760 | |||
| 761 | if(this.items.length > 0) { | ||
| 762 | var firstItem = $this.items.eq(0), | ||
| 763 | hidden = this.panel.is(':hidden'); | ||
| 764 | firstItem.addClass('ui-state-highlight'); | ||
| 765 | |||
| 766 | if($this.query.length > 0 && !$this.options.content) { | ||
| 767 | $this.items.each(function() { | ||
| 768 | var item = $(this), | ||
| 769 | text = item.html(), | ||
| 770 | re = new RegExp(PUI.escapeRegExp($this.query), 'gi'), | ||
| 771 | highlighedText = text.replace(re, '<span class="ui-autocomplete-query">$&</span>'); | ||
| 772 | |||
| 773 | item.html(highlighedText); | ||
| 774 | }); | ||
| 775 | } | ||
| 776 | |||
| 777 | if(this.options.forceSelection) { | ||
| 778 | this.currentItems = []; | ||
| 779 | $.each(data, function(i, item) { | ||
| 780 | $this.currentItems.push(item.label); | ||
| 781 | }); | ||
| 782 | } | ||
| 783 | |||
| 784 | //adjust height | ||
| 785 | if($this.options.scrollHeight) { | ||
| 786 | var heightConstraint = hidden ? $this.panel.height() : $this.panel.children().height(); | ||
| 787 | |||
| 788 | if(heightConstraint > $this.options.scrollHeight) | ||
| 789 | $this.panel.height($this.options.scrollHeight); | ||
| 790 | else | ||
| 791 | $this.panel.css('height', 'auto'); | ||
| 792 | |||
| 793 | } | ||
| 794 | |||
| 795 | if(hidden) { | ||
| 796 | $this.show(); | ||
| 797 | } | ||
| 798 | else { | ||
| 799 | $this._alignPanel(); | ||
| 800 | } | ||
| 801 | } | ||
| 802 | else { | ||
| 803 | this.panel.hide(); | ||
| 804 | } | ||
| 805 | }, | ||
| 806 | |||
| 807 | show: function() { | ||
| 808 | this._alignPanel(); | ||
| 809 | |||
| 810 | if(this.options.effect) | ||
| 811 | this.panel.show(this.options.effect, {}, this.options.effectSpeed); | ||
| 812 | else | ||
| 813 | this.panel.show(); | ||
| 814 | }, | ||
| 815 | |||
| 816 | hide: function() { | ||
| 817 | this.panel.hide(); | ||
| 818 | this.panel.css('height', 'auto'); | ||
| 819 | }, | ||
| 820 | |||
| 821 | _removeItem: function(item) { | ||
| 822 | item.fadeOut('fast', function() { | ||
| 823 | var token = $(this); | ||
| 824 | |||
| 825 | token.remove(); | ||
| 826 | }); | ||
| 827 | }, | ||
| 828 | |||
| 829 | _alignPanel: function() { | ||
| 830 | var panelWidth = null; | ||
| 831 | |||
| 832 | if(this.options.multiple) { | ||
| 833 | panelWidth = this.multiContainer.innerWidth() - (this.element.position().left - this.multiContainer.position().left); | ||
| 834 | } | ||
| 835 | else { | ||
| 836 | if(this.panel.is(':visible')) { | ||
| 837 | panelWidth = this.panel.children('.ui-autocomplete-items').outerWidth(); | ||
| 838 | } | ||
| 839 | else { | ||
| 840 | this.panel.css({'visibility':'hidden','display':'block'}); | ||
| 841 | panelWidth = this.panel.children('.ui-autocomplete-items').outerWidth(); | ||
| 842 | this.panel.css({'visibility':'visible','display':'none'}); | ||
| 843 | } | ||
| 844 | |||
| 845 | var inputWidth = this.element.outerWidth(); | ||
| 846 | if(panelWidth < inputWidth) { | ||
| 847 | panelWidth = inputWidth; | ||
| 848 | } | ||
| 849 | } | ||
| 850 | |||
| 851 | this.panel.css({ | ||
| 852 | 'left':'', | ||
| 853 | 'top':'', | ||
| 854 | 'width': panelWidth, | ||
| 855 | 'z-index': ++PUI.zindex | ||
| 856 | }) | ||
| 857 | .position({ | ||
| 858 | my: 'left top', | ||
| 859 | at: 'left bottom', | ||
| 860 | of: this.element | ||
| 861 | }); | ||
| 862 | } | ||
| 863 | }); | ||
| 864 | |||
| 865 | })(); | ||
| 866 | /** | ||
| 867 | * PrimeFaces Button Widget | ||
| 868 | */ | ||
| 869 | (function() { | ||
| 870 | |||
| 871 | $.widget("primeui.puibutton", { | ||
| 872 | |||
| 873 | options: { | ||
| 874 | value: null, | ||
| 875 | icon: null, | ||
| 876 | iconPos: 'left', | ||
| 877 | click: null | ||
| 878 | }, | ||
| 879 | |||
| 880 | _create: function() { | ||
| 881 | var element = this.element; | ||
| 882 | this.elementText = this.element.text(); | ||
| 883 | |||
| 884 | var value = this.options.value||(this.elementText === '' ? 'ui-button' : this.elementText), | ||
| 885 | disabled = element.prop('disabled'), | ||
| 886 | styleClass = null; | ||
| 887 | |||
| 888 | if(this.options.icon) { | ||
| 889 | styleClass = (value === 'ui-button') ? 'ui-button-icon-only' : 'ui-button-text-icon-' + this.options.iconPos; | ||
| 890 | } | ||
| 891 | else { | ||
| 892 | styleClass = 'ui-button-text-only'; | ||
| 893 | } | ||
| 894 | |||
| 895 | if(disabled) { | ||
| 896 | styleClass += ' ui-state-disabled'; | ||
| 897 | } | ||
| 898 | |||
| 899 | this.element.addClass('ui-button ui-widget ui-state-default ui-corner-all ' + styleClass).text(''); | ||
| 900 | |||
| 901 | if(this.options.icon) { | ||
| 902 | this.element.append('<span class="ui-button-icon-' + this.options.iconPos + ' ui-c fa fa-fw ' + this.options.icon + '" />'); | ||
| 903 | } | ||
| 904 | |||
| 905 | this.element.append('<span class="ui-button-text ui-c">' + value + '</span>'); | ||
| 906 | |||
| 907 | if(!disabled) { | ||
| 908 | this._bindEvents(); | ||
| 909 | } | ||
| 910 | }, | ||
| 911 | |||
| 912 | _destroy: function() { | ||
| 913 | this.element.removeClass('ui-button ui-widget ui-state-default ui-state-hover ui-state-active ui-state-disabled ui-state-focus ui-corner-all ' + | ||
| 914 | 'ui-button-text-only ui-button-icon-only ui-button-text-icon-right ui-button-text-icon-left'); | ||
| 915 | this._unbindEvents(); | ||
| 916 | this.element.children('.fa').remove(); | ||
| 917 | this.element.children('.ui-button-text').remove(); | ||
| 918 | this.element.text(this.elementText); | ||
| 919 | }, | ||
| 920 | |||
| 921 | _bindEvents: function() { | ||
| 922 | var element = this.element, | ||
| 923 | $this = this; | ||
| 924 | |||
| 925 | element.on('mouseover.puibutton', function(){ | ||
| 926 | if(!element.prop('disabled')) { | ||
| 927 | element.addClass('ui-state-hover'); | ||
| 928 | } | ||
| 929 | }).on('mouseout.puibutton', function() { | ||
| 930 | $(this).removeClass('ui-state-active ui-state-hover'); | ||
| 931 | }).on('mousedown.puibutton', function() { | ||
| 932 | if(!element.hasClass('ui-state-disabled')) { | ||
| 933 | element.addClass('ui-state-active').removeClass('ui-state-hover'); | ||
| 934 | } | ||
| 935 | }).on('mouseup.puibutton', function(e) { | ||
| 936 | element.removeClass('ui-state-active').addClass('ui-state-hover'); | ||
| 937 | |||
| 938 | $this._trigger('click', e); | ||
| 939 | }).on('focus.puibutton', function() { | ||
| 940 | element.addClass('ui-state-focus'); | ||
| 941 | }).on('blur.puibutton', function() { | ||
| 942 | element.removeClass('ui-state-focus'); | ||
| 943 | }).on('keydown.puibutton',function(e) { | ||
| 944 | if(e.keyCode == $.ui.keyCode.SPACE || e.keyCode == $.ui.keyCode.ENTER || e.keyCode == $.ui.keyCode.NUMPAD_ENTER) { | ||
| 945 | element.addClass('ui-state-active'); | ||
| 946 | } | ||
| 947 | }).on('keyup.puibutton', function() { | ||
| 948 | element.removeClass('ui-state-active'); | ||
| 949 | }); | ||
| 950 | |||
| 951 | return this; | ||
| 952 | }, | ||
| 953 | |||
| 954 | _unbindEvents: function() { | ||
| 955 | this.element.off('mouseover.puibutton mouseout.puibutton mousedown.puibutton mouseup.puibutton focus.puibutton blur.puibutton keydown.puibutton keyup.puibutton'); | ||
| 956 | }, | ||
| 957 | |||
| 958 | disable: function() { | ||
| 959 | this._unbindEvents(); | ||
| 960 | this.element.addClass('ui-state-disabled').prop('disabled',true); | ||
| 961 | }, | ||
| 962 | |||
| 963 | enable: function() { | ||
| 964 | if(this.element.prop('disabled')) { | ||
| 965 | this._bindEvents(); | ||
| 966 | this.element.prop('disabled', false).removeClass('ui-state-disabled'); | ||
| 967 | } | ||
| 968 | }, | ||
| 969 | |||
| 970 | _setOption: function(key, value) { | ||
| 971 | if(key === 'disabled') { | ||
| 972 | if(value) | ||
| 973 | this.disable(); | ||
| 974 | else | ||
| 975 | this.enable(); | ||
| 976 | } | ||
| 977 | else { | ||
| 978 | $.Widget.prototype._setOption.apply(this, arguments); | ||
| 979 | } | ||
| 980 | } | ||
| 981 | |||
| 982 | }); | ||
| 983 | })(); | ||
| 984 | /** | ||
| 985 | * PrimeUI Carousel widget | ||
| 986 | */ | ||
| 987 | (function() { | ||
| 988 | |||
| 989 | $.widget("primeui.puicarousel", { | ||
| 990 | |||
| 991 | options: { | ||
| 992 | datasource: null, | ||
| 993 | numVisible: 3, | ||
| 994 | firstVisible: 0, | ||
| 995 | headerText: null, | ||
| 996 | effectDuration: 500, | ||
| 997 | circular :false, | ||
| 998 | breakpoint: 560, | ||
| 999 | itemContent: null, | ||
| 1000 | responsive: true, | ||
| 1001 | autoplayInterval: 0, | ||
| 1002 | easing: 'easeInOutCirc', | ||
| 1003 | pageLinks: 3, | ||
| 1004 | style: null, | ||
| 1005 | styleClass: null, | ||
| 1006 | template: null, | ||
| 1007 | enhanced: false | ||
| 1008 | }, | ||
| 1009 | |||
| 1010 | _create: function() { | ||
| 1011 | this.id = this.element.attr('id'); | ||
| 1012 | if(!this.id) { | ||
| 1013 | this.id = this.element.uniqueId().attr('id'); | ||
| 1014 | } | ||
| 1015 | |||
| 1016 | if(!this.options.enhanced) { | ||
| 1017 | this.element.wrap('<div class="ui-carousel ui-widget ui-widget-content ui-corner-all"><div class="ui-carousel-viewport"></div></div>'); | ||
| 1018 | } | ||
| 1019 | |||
| 1020 | this.container = this.element.parent().parent(); | ||
| 1021 | this.element.addClass('ui-carousel-items'); | ||
| 1022 | this.viewport = this.element.parent(); | ||
| 1023 | this.container.prepend('<div class="ui-carousel-header ui-widget-header"><div class="ui-carousel-header-title"></div></div>'); | ||
| 1024 | this.header = this.container.children('.ui-carousel-header'); | ||
| 1025 | this.header.append('<span class="ui-carousel-button ui-carousel-next-button fa fa-arrow-circle-right"></span>' + | ||
| 1026 | '<span class="ui-carousel-button ui-carousel-prev-button fa fa-arrow-circle-left"></span>'); | ||
| 1027 | |||
| 1028 | if(this.options.headerText) { | ||
| 1029 | this.header.children('.ui-carousel-header-title').html(this.options.headerText); | ||
| 1030 | } | ||
| 1031 | |||
| 1032 | if(this.options.styleClass) { | ||
| 1033 | this.container.addClass(this.options.styleClass); | ||
| 1034 | } | ||
| 1035 | |||
| 1036 | if(this.options.style) { | ||
| 1037 | this.container.attr('style', this.options.style); | ||
| 1038 | } | ||
| 1039 | |||
| 1040 | if(this.options.datasource) | ||
| 1041 | this._loadData(); | ||
| 1042 | else | ||
| 1043 | this._render(); | ||
| 1044 | }, | ||
| 1045 | |||
| 1046 | _destroy: function() { | ||
| 1047 | this._unbindEvents(); | ||
| 1048 | this.header.remove(); | ||
| 1049 | this.items.removeClass('ui-carousel-item ui-widget-content ui-corner-all').css('width','auto'); | ||
| 1050 | this.element.removeClass('ui-carousel-items').css('left','auto'); | ||
| 1051 | |||
| 1052 | if(!this.options.enhanced) { | ||
| 1053 | this.element.unwrap().unwrap(); | ||
| 1054 | } | ||
| 1055 | |||
| 1056 | if(this.options.datasource) { | ||
| 1057 | this.items.remove(); | ||
| 1058 | } | ||
| 1059 | }, | ||
| 1060 | |||
| 1061 | _loadData: function() { | ||
| 1062 | if($.isArray(this.options.datasource)) | ||
| 1063 | this._render(this.options.datasource); | ||
| 1064 | else if($.type(this.options.datasource) === 'function') | ||
| 1065 | this.options.datasource.call(this, this._render); | ||
| 1066 | }, | ||
| 1067 | |||
| 1068 | _updateDatasource: function(value) { | ||
| 1069 | this.options.datasource = value; | ||
| 1070 | this.element.children().remove(); | ||
| 1071 | this.header.children('.ui-carousel-page-links').remove(); | ||
| 1072 | this.header.children('select').remove(); | ||
| 1073 | this._loadData(); | ||
| 1074 | }, | ||
| 1075 | |||
| 1076 | _render: function(data) { | ||
| 1077 | this.data = data; | ||
| 1078 | |||
| 1079 | if(this.data) { | ||
| 1080 | for(var i = 0; i < data.length; i++) { | ||
| 1081 | var itemContent = this._createItemContent(data[i]); | ||
| 1082 | if($.type(itemContent) === 'string') | ||
| 1083 | this.element.append('<li>' + itemContent + '</li>'); | ||
| 1084 | else | ||
| 1085 | this.element.append($('<li></li>').wrapInner(itemContent)); | ||
| 1086 | } | ||
| 1087 | } | ||
| 1088 | |||
| 1089 | this.items = this.element.children('li'); | ||
| 1090 | this.items.addClass('ui-carousel-item ui-widget-content ui-corner-all'); | ||
| 1091 | this.itemsCount = this.items.length; | ||
| 1092 | this.columns = this.options.numVisible; | ||
| 1093 | this.first = this.options.firstVisible; | ||
| 1094 | this.page = parseInt(this.first/this.columns); | ||
| 1095 | this.totalPages = Math.ceil(this.itemsCount/this.options.numVisible); | ||
| 1096 | |||
| 1097 | this._renderPageLinks(); | ||
| 1098 | |||
| 1099 | this.prevNav = this.header.children('.ui-carousel-prev-button'); | ||
| 1100 | this.nextNav = this.header.children('.ui-carousel-next-button'); | ||
| 1101 | this.pageLinks = this.header.find('> .ui-carousel-page-links > .ui-carousel-page-link'); | ||
| 1102 | this.dropdown = this.header.children('.ui-carousel-dropdown'); | ||
| 1103 | this.mobileDropdown = this.header.children('.ui-carousel-mobiledropdown'); | ||
| 1104 | |||
| 1105 | this._bindEvents(); | ||
| 1106 | |||
| 1107 | if(this.options.responsive) { | ||
| 1108 | this.refreshDimensions(); | ||
| 1109 | } | ||
| 1110 | else { | ||
| 1111 | this.calculateItemWidths(); | ||
| 1112 | this.container.width(this.container.width()); | ||
| 1113 | this.updateNavigators(); | ||
| 1114 | } | ||
| 1115 | }, | ||
| 1116 | |||
| 1117 | _renderPageLinks: function() { | ||
| 1118 | if(this.totalPages <= this.options.pageLinks) { | ||
| 1119 | this.pageLinksContainer = $('<div class="ui-carousel-page-links"></div>'); | ||
| 1120 | for(var i = 0; i < this.totalPages; i++) { | ||
| 1121 | this.pageLinksContainer.append('<a href="#" class="ui-carousel-page-link fa fa-circle-o"></a>'); | ||
| 1122 | } | ||
| 1123 | this.header.append(this.pageLinksContainer); | ||
| 1124 | } | ||
| 1125 | else { | ||
| 1126 | this.dropdown = $('<select class="ui-carousel-dropdown ui-widget ui-state-default ui-corner-left"></select>'); | ||
| 1127 | for(var i = 0; i < this.totalPages; i++) { | ||
| 1128 | var pageNumber = (i+1); | ||
| 1129 | this.dropdown.append('<option value="' + pageNumber + '">' + pageNumber + '</option>'); | ||
| 1130 | } | ||
| 1131 | this.header.append(this.dropdown); | ||
| 1132 | } | ||
| 1133 | |||
| 1134 | if(this.options.responsive) { | ||
| 1135 | this.mobileDropdown = $('<select class="ui-carousel-mobiledropdown ui-widget ui-state-default ui-corner-left"></select>'); | ||
| 1136 | for(var i = 0; i < this.itemsCount; i++) { | ||
| 1137 | var pageNumber = (i+1); | ||
| 1138 | this.mobileDropdown.append('<option value="' + pageNumber + '">' + pageNumber + '</option>'); | ||
| 1139 | } | ||
| 1140 | this.header.append(this.mobileDropdown); | ||
| 1141 | } | ||
| 1142 | }, | ||
| 1143 | |||
| 1144 | calculateItemWidths: function() { | ||
| 1145 | var firstItem = this.items.eq(0); | ||
| 1146 | if(firstItem.length) { | ||
| 1147 | var itemFrameWidth = firstItem.outerWidth(true) - firstItem.width(); //sum of margin, border and padding | ||
| 1148 | this.items.width((this.viewport.innerWidth() - itemFrameWidth * this.columns) / this.columns); | ||
| 1149 | } | ||
| 1150 | }, | ||
| 1151 | |||
| 1152 | refreshDimensions: function() { | ||
| 1153 | var win = $(window); | ||
| 1154 | if(win.width() <= this.options.breakpoint) { | ||
| 1155 | this.columns = 1; | ||
| 1156 | this.calculateItemWidths(this.columns); | ||
| 1157 | this.totalPages = this.itemsCount; | ||
| 1158 | this.mobileDropdown.show(); | ||
| 1159 | this.pageLinks.hide(); | ||
| 1160 | } | ||
| 1161 | else { | ||
| 1162 | this.columns = this.options.numVisible; | ||
| 1163 | this.calculateItemWidths(); | ||
| 1164 | this.totalPages = Math.ceil(this.itemsCount / this.options.numVisible); | ||
| 1165 | this.mobileDropdown.hide(); | ||
| 1166 | this.pageLinks.show(); | ||
| 1167 | } | ||
| 1168 | |||
| 1169 | this.page = parseInt(this.first / this.columns); | ||
| 1170 | this.updateNavigators(); | ||
| 1171 | this.element.css('left', (-1 * (this.viewport.innerWidth() * this.page))); | ||
| 1172 | }, | ||
| 1173 | |||
| 1174 | _bindEvents: function() { | ||
| 1175 | var $this = this; | ||
| 1176 | |||
| 1177 | if(this.eventsBound) { | ||
| 1178 | return; | ||
| 1179 | } | ||
| 1180 | |||
| 1181 | this.prevNav.on('click.puicarousel', function() { | ||
| 1182 | if($this.page !== 0) { | ||
| 1183 | $this.setPage($this.page - 1); | ||
| 1184 | } | ||
| 1185 | else if($this.options.circular) { | ||
| 1186 | $this.setPage($this.totalPages - 1); | ||
| 1187 | } | ||
| 1188 | }); | ||
| 1189 | |||
| 1190 | this.nextNav.on('click.puicarousel', function() { | ||
| 1191 | var lastPage = ($this.page === ($this.totalPages - 1)); | ||
| 1192 | |||
| 1193 | if(!lastPage) { | ||
| 1194 | $this.setPage($this.page + 1); | ||
| 1195 | } | ||
| 1196 | else if($this.options.circular) { | ||
| 1197 | $this.setPage(0); | ||
| 1198 | } | ||
| 1199 | }); | ||
| 1200 | |||
| 1201 | if($.swipe) { | ||
| 1202 | this.element.swipe({ | ||
| 1203 | swipe:function(event, direction) { | ||
| 1204 | if(direction === 'left') { | ||
| 1205 | if($this.page === ($this.totalPages - 1)) { | ||
| 1206 | if($this.options.circular) | ||
| 1207 | $this.setPage(0); | ||
| 1208 | } | ||
| 1209 | else { | ||
| 1210 | $this.setPage($this.page + 1); | ||
| 1211 | } | ||
| 1212 | } | ||
| 1213 | else if(direction === 'right') { | ||
| 1214 | if($this.page === 0) { | ||
| 1215 | if($this.options.circular) | ||
| 1216 | $this.setPage($this.totalPages - 1); | ||
| 1217 | } | ||
| 1218 | else { | ||
| 1219 | $this.setPage($this.page - 1); | ||
| 1220 | } | ||
| 1221 | } | ||
| 1222 | } | ||
| 1223 | }); | ||
| 1224 | } | ||
| 1225 | |||
| 1226 | if(this.pageLinks.length) { | ||
| 1227 | this.pageLinks.on('click.puicarousel', function(e) { | ||
| 1228 | $this.setPage($(this).index()); | ||
| 1229 | e.preventDefault(); | ||
| 1230 | }); | ||
| 1231 | } | ||
| 1232 | |||
| 1233 | this.header.children('select').on('change.puicarousel', function() { | ||
| 1234 | $this.setPage(parseInt($(this).val()) - 1); | ||
| 1235 | }); | ||
| 1236 | |||
| 1237 | if(this.options.autoplayInterval) { | ||
| 1238 | this.options.circular = true; | ||
| 1239 | this.startAutoplay(); | ||
| 1240 | } | ||
| 1241 | |||
| 1242 | if(this.options.responsive) { | ||
| 1243 | var resizeNS = 'resize.' + this.id; | ||
| 1244 | $(window).off(resizeNS).on(resizeNS, function() { | ||
| 1245 | $this.refreshDimensions(); | ||
| 1246 | }); | ||
| 1247 | } | ||
| 1248 | |||
| 1249 | this.eventsBound = true; | ||
| 1250 | }, | ||
| 1251 | |||
| 1252 | _unbindEvents: function() { | ||
| 1253 | this.prevNav.off('click.puicarousel'); | ||
| 1254 | this.nextNav.off('click.puicarousel'); | ||
| 1255 | if(this.pageLinks.length) { | ||
| 1256 | this.pageLinks.off('click.puicarousel'); | ||
| 1257 | } | ||
| 1258 | this.header.children('select').off('change.puicarousel'); | ||
| 1259 | |||
| 1260 | if(this.options.autoplayInterval) { | ||
| 1261 | this.stopAutoplay(); | ||
| 1262 | } | ||
| 1263 | |||
| 1264 | if(this.options.responsive) { | ||
| 1265 | $(window).off('resize.' + this.id) | ||
| 1266 | } | ||
| 1267 | }, | ||
| 1268 | |||
| 1269 | updateNavigators: function() { | ||
| 1270 | if(!this.options.circular) { | ||
| 1271 | if(this.page === 0) { | ||
| 1272 | this.prevNav.addClass('ui-state-disabled'); | ||
| 1273 | this.nextNav.removeClass('ui-state-disabled'); | ||
| 1274 | } | ||
| 1275 | else if(this.page === (this.totalPages - 1)) { | ||
| 1276 | this.prevNav.removeClass('ui-state-disabled'); | ||
| 1277 | this.nextNav.addClass('ui-state-disabled'); | ||
| 1278 | } | ||
| 1279 | else { | ||
| 1280 | this.prevNav.removeClass('ui-state-disabled'); | ||
| 1281 | this.nextNav.removeClass('ui-state-disabled'); | ||
| 1282 | } | ||
| 1283 | } | ||
| 1284 | |||
| 1285 | if(this.pageLinks.length) { | ||
| 1286 | this.pageLinks.filter('.fa-dot-circle-o').removeClass('fa-dot-circle-o'); | ||
| 1287 | this.pageLinks.eq(this.page).addClass('fa-dot-circle-o'); | ||
| 1288 | } | ||
| 1289 | |||
| 1290 | if(this.dropdown.length) { | ||
| 1291 | this.dropdown.val(this.page + 1); | ||
| 1292 | } | ||
| 1293 | |||
| 1294 | if(this.mobileDropdown.length) { | ||
| 1295 | this.mobileDropdown.val(this.page + 1); | ||
| 1296 | } | ||
| 1297 | }, | ||
| 1298 | |||
| 1299 | setPage: function(p) { | ||
| 1300 | if(p !== this.page && !this.element.is(':animated')) { | ||
| 1301 | var $this = this; | ||
| 1302 | |||
| 1303 | this.element.animate({ | ||
| 1304 | left: -1 * (this.viewport.innerWidth() * p) | ||
| 1305 | ,easing: this.options.easing | ||
| 1306 | }, | ||
| 1307 | { | ||
| 1308 | duration: this.options.effectDuration, | ||
| 1309 | easing: this.options.easing, | ||
| 1310 | complete: function() { | ||
| 1311 | $this.page = p; | ||
| 1312 | $this.first = $this.page * $this.columns; | ||
| 1313 | $this.updateNavigators(); | ||
| 1314 | $this._trigger('pageChange', null, {'page':p}); | ||
| 1315 | } | ||
| 1316 | }); | ||
| 1317 | } | ||
| 1318 | }, | ||
| 1319 | |||
| 1320 | startAutoplay: function() { | ||
| 1321 | var $this = this; | ||
| 1322 | |||
| 1323 | this.interval = setInterval(function() { | ||
| 1324 | if($this.page === ($this.totalPages - 1)) | ||
| 1325 | $this.setPage(0); | ||
| 1326 | else | ||
| 1327 | $this.setPage($this.page + 1); | ||
| 1328 | }, this.options.autoplayInterval); | ||
| 1329 | }, | ||
| 1330 | |||
| 1331 | stopAutoplay: function() { | ||
| 1332 | clearInterval(this.interval); | ||
| 1333 | }, | ||
| 1334 | |||
| 1335 | _setOption: function(key, value) { | ||
| 1336 | if(key === 'datasource') | ||
| 1337 | this._updateDatasource(value); | ||
| 1338 | else | ||
| 1339 | $.Widget.prototype._setOption.apply(this, arguments); | ||
| 1340 | }, | ||
| 1341 | |||
| 1342 | _createItemContent: function(obj) { | ||
| 1343 | if(this.options.template) { | ||
| 1344 | var template = this.options.template.html(); | ||
| 1345 | Mustache.parse(template); | ||
| 1346 | return Mustache.render(template, obj); | ||
| 1347 | } | ||
| 1348 | else { | ||
| 1349 | return this.options.itemContent.call(this, obj); | ||
| 1350 | } | ||
| 1351 | } | ||
| 1352 | |||
| 1353 | }); | ||
| 1354 | |||
| 1355 | })(); | ||
| 1356 | /** | ||
| 1357 | * PrimeUI checkbox widget | ||
| 1358 | */ | ||
| 1359 | (function() { | ||
| 1360 | |||
| 1361 | $.widget("primeui.puicheckbox", { | ||
| 1362 | |||
| 1363 | _create: function() { | ||
| 1364 | this.element.wrap('<div class="ui-chkbox ui-widget"><div class="ui-helper-hidden-accessible"></div></div>'); | ||
| 1365 | this.container = this.element.parent().parent(); | ||
| 1366 | this.box = $('<div class="ui-chkbox-box ui-widget ui-corner-all ui-state-default">').appendTo(this.container); | ||
| 1367 | this.icon = $('<span class="ui-chkbox-icon ui-c"></span>').appendTo(this.box); | ||
| 1368 | this.disabled = this.element.prop('disabled'); | ||
| 1369 | this.label = $('label[for="' + this.element.attr('id') + '"]'); | ||
| 1370 | |||
| 1371 | if(this.isChecked()) { | ||
| 1372 | this.box.addClass('ui-state-active'); | ||
| 1373 | this.icon.addClass('fa fa-fw fa-check'); | ||
| 1374 | } | ||
| 1375 | |||
| 1376 | if(this.disabled) { | ||
| 1377 | this.box.addClass('ui-state-disabled'); | ||
| 1378 | } else { | ||
| 1379 | this._bindEvents(); | ||
| 1380 | } | ||
| 1381 | }, | ||
| 1382 | |||
| 1383 | _bindEvents: function() { | ||
| 1384 | var $this = this; | ||
| 1385 | |||
| 1386 | this.box.on('mouseover.puicheckbox', function() { | ||
| 1387 | if(!$this.isChecked()) | ||
| 1388 | $this.box.addClass('ui-state-hover'); | ||
| 1389 | }) | ||
| 1390 | .on('mouseout.puicheckbox', function() { | ||
| 1391 | $this.box.removeClass('ui-state-hover'); | ||
| 1392 | }) | ||
| 1393 | .on('click.puicheckbox', function() { | ||
| 1394 | $this.toggle(); | ||
| 1395 | }); | ||
| 1396 | |||
| 1397 | this.element.on('focus.puicheckbox', function() { | ||
| 1398 | if($this.isChecked()) { | ||
| 1399 | $this.box.removeClass('ui-state-active'); | ||
| 1400 | } | ||
| 1401 | |||
| 1402 | $this.box.addClass('ui-state-focus'); | ||
| 1403 | }) | ||
| 1404 | .on('blur.puicheckbox', function() { | ||
| 1405 | if($this.isChecked()) { | ||
| 1406 | $this.box.addClass('ui-state-active'); | ||
| 1407 | } | ||
| 1408 | |||
| 1409 | $this.box.removeClass('ui-state-focus'); | ||
| 1410 | }) | ||
| 1411 | .on('keydown.puicheckbox', function(e) { | ||
| 1412 | var keyCode = $.ui.keyCode; | ||
| 1413 | if(e.which == keyCode.SPACE) { | ||
| 1414 | e.preventDefault(); | ||
| 1415 | } | ||
| 1416 | }) | ||
| 1417 | .on('keyup.puicheckbox', function(e) { | ||
| 1418 | var keyCode = $.ui.keyCode; | ||
| 1419 | if(e.which == keyCode.SPACE) { | ||
| 1420 | $this.toggle(true); | ||
| 1421 | |||
| 1422 | e.preventDefault(); | ||
| 1423 | } | ||
| 1424 | }); | ||
| 1425 | |||
| 1426 | this.label.on('click.puicheckbox', function(e) { | ||
| 1427 | $this.toggle(); | ||
| 1428 | e.preventDefault(); | ||
| 1429 | }); | ||
| 1430 | }, | ||
| 1431 | |||
| 1432 | toggle: function(keypress) { | ||
| 1433 | if(this.isChecked()) { | ||
| 1434 | this.uncheck(keypress); | ||
| 1435 | } else { | ||
| 1436 | this.check(keypress); | ||
| 1437 | } | ||
| 1438 | |||
| 1439 | this._trigger('change', null, this.isChecked()); | ||
| 1440 | }, | ||
| 1441 | |||
| 1442 | isChecked: function() { | ||
| 1443 | return this.element.prop('checked'); | ||
| 1444 | }, | ||
| 1445 | |||
| 1446 | check: function(activate, silent) { | ||
| 1447 | if(!this.isChecked()) { | ||
| 1448 | this.element.prop('checked', true); | ||
| 1449 | this.icon.addClass('fa fa-fw fa-check'); | ||
| 1450 | |||
| 1451 | if(!activate) { | ||
| 1452 | this.box.addClass('ui-state-active'); | ||
| 1453 | } | ||
| 1454 | |||
| 1455 | if(!silent) { | ||
| 1456 | this.element.trigger('change'); | ||
| 1457 | } | ||
| 1458 | } | ||
| 1459 | }, | ||
| 1460 | |||
| 1461 | uncheck: function() { | ||
| 1462 | if(this.isChecked()) { | ||
| 1463 | this.element.prop('checked', false); | ||
| 1464 | this.box.removeClass('ui-state-active'); | ||
| 1465 | this.icon.removeClass('fa fa-fw fa-check'); | ||
| 1466 | |||
| 1467 | this.element.trigger('change'); | ||
| 1468 | } | ||
| 1469 | }, | ||
| 1470 | |||
| 1471 | _unbindEvents: function() { | ||
| 1472 | this.box.off('mouseover.puicheckbox mouseout.puicheckbox click.puicheckbox'); | ||
| 1473 | this.element.off('focus.puicheckbox blur.puicheckbox keydown.puicheckbox keyup.puicheckbox'); | ||
| 1474 | |||
| 1475 | if (this.label.length) { | ||
| 1476 | this.label.off('click.puicheckbox'); | ||
| 1477 | } | ||
| 1478 | }, | ||
| 1479 | |||
| 1480 | disable: function() { | ||
| 1481 | this.box.prop('disabled', true); | ||
| 1482 | this.box.attr('aria-disabled', true); | ||
| 1483 | this.box.addClass('ui-state-disabled').removeClass('ui-state-hover'); | ||
| 1484 | this._unbindEvents(); | ||
| 1485 | }, | ||
| 1486 | |||
| 1487 | enable: function() { | ||
| 1488 | this.box.prop('disabled', false); | ||
| 1489 | this.box.attr('aria-disabled', false); | ||
| 1490 | this.box.removeClass('ui-state-disabled'); | ||
| 1491 | this._bindEvents(); | ||
| 1492 | }, | ||
| 1493 | |||
| 1494 | _destroy: function() { | ||
| 1495 | this._unbindEvents(); | ||
| 1496 | this.container.removeClass('ui-chkbox ui-widget'); | ||
| 1497 | this.box.remove(); | ||
| 1498 | this.element.unwrap().unwrap(); | ||
| 1499 | } | ||
| 1500 | |||
| 1501 | }); | ||
| 1502 | |||
| 1503 | })(); | ||
| 1504 | /** | ||
| 1505 | * PrimeUI Datagrid Widget | ||
| 1506 | */ | ||
| 1507 | (function() { | ||
| 1508 | |||
| 1509 | $.widget("primeui.puidatagrid", { | ||
| 1510 | |||
| 1511 | options: { | ||
| 1512 | columns: 3, | ||
| 1513 | datasource: null, | ||
| 1514 | paginator: null, | ||
| 1515 | header: null, | ||
| 1516 | footer: null, | ||
| 1517 | content: null, | ||
| 1518 | lazy: false, | ||
| 1519 | template: null | ||
| 1520 | }, | ||
| 1521 | |||
| 1522 | _create: function() { | ||
| 1523 | this.id = this.element.attr('id'); | ||
| 1524 | if(!this.id) { | ||
| 1525 | this.id = this.element.uniqueId().attr('id'); | ||
| 1526 | } | ||
| 1527 | |||
| 1528 | this.element.addClass('ui-datagrid ui-widget'); | ||
| 1529 | |||
| 1530 | //header | ||
| 1531 | if(this.options.header) { | ||
| 1532 | this.element.append('<div class="ui-datagrid-header ui-widget-header ui-corner-top">' + this.options.header + '</div>'); | ||
| 1533 | } | ||
| 1534 | |||
| 1535 | //content | ||
| 1536 | this.content = $('<div class="ui-datagrid-content ui-widget-content ui-datagrid-col-' + this.options.columns + '"></div>').appendTo(this.element); | ||
| 1537 | |||
| 1538 | //footer | ||
| 1539 | if(this.options.footer) { | ||
| 1540 | this.element.append('<div class="ui-datagrid-footer ui-widget-header ui-corner-top">' + this.options.footer + '</div>'); | ||
| 1541 | } | ||
| 1542 | |||
| 1543 | //data | ||
| 1544 | if(this.options.datasource) { | ||
| 1545 | this._initDatasource(); | ||
| 1546 | } | ||
| 1547 | }, | ||
| 1548 | |||
| 1549 | _onDataInit: function(data) { | ||
| 1550 | this._onDataUpdate(data); | ||
| 1551 | this._initPaginator(); | ||
| 1552 | }, | ||
| 1553 | |||
| 1554 | _onDataUpdate: function(data) { | ||
| 1555 | this.data = data; | ||
| 1556 | if(!this.data) { | ||
| 1557 | this.data = []; | ||
| 1558 | } | ||
| 1559 | |||
| 1560 | this.reset(); | ||
| 1561 | |||
| 1562 | this._renderData(); | ||
| 1563 | }, | ||
| 1564 | |||
| 1565 | _onLazyLoad: function(data) { | ||
| 1566 | this.data = data; | ||
| 1567 | if(!this.data) { | ||
| 1568 | this.data = []; | ||
| 1569 | } | ||
| 1570 | |||
| 1571 | this._renderData(); | ||
| 1572 | }, | ||
| 1573 | |||
| 1574 | reset: function() { | ||
| 1575 | if(this.paginator) { | ||
| 1576 | this.paginator.puipaginator('setState', { | ||
| 1577 | page: 0, | ||
| 1578 | totalRecords: this.options.lazy ? this.options.paginator.totalRecords : this.data.length | ||
| 1579 | }); | ||
| 1580 | } | ||
| 1581 | }, | ||
| 1582 | |||
| 1583 | paginate: function() { | ||
| 1584 | if(this.options.lazy) { | ||
| 1585 | this.options.datasource.call(this, this._onLazyLoad, this._createStateMeta()); | ||
| 1586 | } | ||
| 1587 | else { | ||
| 1588 | this._renderData(); | ||
| 1589 | } | ||
| 1590 | }, | ||
| 1591 | |||
| 1592 | _renderData: function() { | ||
| 1593 | if(this.data) { | ||
| 1594 | this.content.html(''); | ||
| 1595 | |||
| 1596 | var firstNonLazy = this._getFirst(), | ||
| 1597 | first = this.options.lazy ? 0 : firstNonLazy, | ||
| 1598 | rows = this._getRows(), | ||
| 1599 | gridRow = null; | ||
| 1600 | |||
| 1601 | for(var i = first; i < (first + rows); i++) { | ||
| 1602 | var dataValue = this.data[i]; | ||
| 1603 | |||
| 1604 | if(dataValue) { | ||
| 1605 | var gridColumn = $('<div></div>').appendTo(this.content), | ||
| 1606 | markup = this._createItemContent(dataValue); | ||
| 1607 | gridColumn.append(markup); | ||
| 1608 | } | ||
| 1609 | } | ||
| 1610 | } | ||
| 1611 | }, | ||
| 1612 | |||
| 1613 | _getFirst: function() { | ||
| 1614 | if(this.paginator) { | ||
| 1615 | var page = this.paginator.puipaginator('option', 'page'), | ||
| 1616 | rows = this.paginator.puipaginator('option', 'rows'); | ||
| 1617 | |||
| 1618 | return (page * rows); | ||
| 1619 | } | ||
| 1620 | else { | ||
| 1621 | return 0; | ||
| 1622 | } | ||
| 1623 | }, | ||
| 1624 | |||
| 1625 | _getRows: function() { | ||
| 1626 | if(this.options.paginator) | ||
| 1627 | return this.paginator ? this.paginator.puipaginator('option', 'rows') : this.options.paginator.rows; | ||
| 1628 | else | ||
| 1629 | return this.data ? this.data.length : 0; | ||
| 1630 | }, | ||
| 1631 | |||
| 1632 | _createStateMeta: function() { | ||
| 1633 | var state = { | ||
| 1634 | first: this._getFirst(), | ||
| 1635 | rows: this._getRows() | ||
| 1636 | }; | ||
| 1637 | |||
| 1638 | return state; | ||
| 1639 | }, | ||
| 1640 | |||
| 1641 | _initPaginator: function() { | ||
| 1642 | var $this = this; | ||
| 1643 | if(this.options.paginator) { | ||
| 1644 | this.options.paginator.paginate = function(event, state) { | ||
| 1645 | $this.paginate(); | ||
| 1646 | }; | ||
| 1647 | |||
| 1648 | this.options.paginator.totalRecords = this.options.lazy ? this.options.paginator.totalRecords : this.data.length; | ||
| 1649 | this.paginator = $('<div></div>').insertAfter(this.content).puipaginator(this.options.paginator); | ||
| 1650 | } | ||
| 1651 | }, | ||
| 1652 | |||
| 1653 | _initDatasource: function() { | ||
| 1654 | if($.isArray(this.options.datasource)) { | ||
| 1655 | this._onDataInit(this.options.datasource); | ||
| 1656 | } | ||
| 1657 | else { | ||
| 1658 | if($.type(this.options.datasource) === 'string') { | ||
| 1659 | var $this = this, | ||
| 1660 | dataURL = this.options.datasource; | ||
| 1661 | |||
| 1662 | this.options.datasource = function() { | ||
| 1663 | $.ajax({ | ||
| 1664 | type: 'GET', | ||
| 1665 | url: dataURL, | ||
| 1666 | dataType: "json", | ||
| 1667 | context: $this, | ||
| 1668 | success: function (response) { | ||
| 1669 | this._onDataInit(response); | ||
| 1670 | } | ||
| 1671 | }); | ||
| 1672 | }; | ||
| 1673 | } | ||
| 1674 | |||
| 1675 | if($.type(this.options.datasource) === 'function') { | ||
| 1676 | if(this.options.lazy) | ||
| 1677 | this.options.datasource.call(this, this._onDataInit, {first:0, rows: this._getRows()}); | ||
| 1678 | else | ||
| 1679 | this.options.datasource.call(this, this._onDataInit); | ||
| 1680 | } | ||
| 1681 | } | ||
| 1682 | }, | ||
| 1683 | |||
| 1684 | _updateDatasource: function(datasource) { | ||
| 1685 | this.options.datasource = datasource; | ||
| 1686 | |||
| 1687 | if($.isArray(this.options.datasource)) { | ||
| 1688 | this._onDataUpdate(this.options.datasource); | ||
| 1689 | } | ||
| 1690 | else if($.type(this.options.datasource) === 'function') { | ||
| 1691 | if(this.options.lazy) | ||
| 1692 | this.options.datasource.call(this, this._onDataUpdate, {first:0, rows: this._getRows()}); | ||
| 1693 | else | ||
| 1694 | this.options.datasource.call(this, this._onDataUpdate); | ||
| 1695 | } | ||
| 1696 | }, | ||
| 1697 | |||
| 1698 | _setOption: function(key, value) { | ||
| 1699 | if(key === 'datasource') { | ||
| 1700 | this._updateDatasource(value); | ||
| 1701 | } | ||
| 1702 | else { | ||
| 1703 | $.Widget.prototype._setOption.apply(this, arguments); | ||
| 1704 | } | ||
| 1705 | }, | ||
| 1706 | |||
| 1707 | _createItemContent: function(obj) { | ||
| 1708 | if(this.options.template) { | ||
| 1709 | var templateContent = this.options.template.html(); | ||
| 1710 | Mustache.parse(templateContent); | ||
| 1711 | return Mustache.render(templateContent, obj); | ||
| 1712 | } | ||
| 1713 | else { | ||
| 1714 | return this.options.content.call(this, obj); | ||
| 1715 | } | ||
| 1716 | } | ||
| 1717 | |||
| 1718 | }); | ||
| 1719 | })(); | ||
| 1720 | /** | ||
| 1721 | * PrimeUI Datascroller Widget | ||
| 1722 | */ | ||
| 1723 | (function() { | ||
| 1724 | |||
| 1725 | $.widget("primeui.puidatascroller", { | ||
| 1726 | |||
| 1727 | options: { | ||
| 1728 | header: null, | ||
| 1729 | buffer: 0.9, | ||
| 1730 | chunkSize: 10, | ||
| 1731 | datasource: null, | ||
| 1732 | lazy: false, | ||
| 1733 | content: null, | ||
| 1734 | template: null, | ||
| 1735 | mode: 'document', | ||
| 1736 | loader: null, | ||
| 1737 | scrollHeight: null, | ||
| 1738 | totalSize: null | ||
| 1739 | }, | ||
| 1740 | |||
| 1741 | _create: function() { | ||
| 1742 | this.id = this.element.attr('id'); | ||
| 1743 | if(!this.id) { | ||
| 1744 | this.id = this.element.uniqueId().attr('id'); | ||
| 1745 | } | ||
| 1746 | |||
| 1747 | this.element.addClass('ui-datascroller ui-widget'); | ||
| 1748 | if(this.options.header) { | ||
| 1749 | this.header = this.element.append('<div class="ui-datascroller-header ui-widget-header ui-corner-top">' + this.options.header + '</div>').children('.ui-datascroller-header'); | ||
| 1750 | } | ||
| 1751 | |||
| 1752 | this.content = this.element.append('<div class="ui-datascroller-content ui-widget-content ui-corner-bottom"></div>').children('.ui-datascroller-content'); | ||
| 1753 | this.list = this.content.append('<ul class="ui-datascroller-list"></ul>').children('.ui-datascroller-list'); | ||
| 1754 | this.loaderContainer = this.content.append('<div class="ui-datascroller-loader"></div>').children('.ui-datascroller-loader'); | ||
| 1755 | this.loadStatus = $('<div class="ui-datascroller-loading"></div>'); | ||
| 1756 | this.loading = false; | ||
| 1757 | this.allLoaded = false; | ||
| 1758 | this.offset = 0; | ||
| 1759 | |||
| 1760 | if(this.options.mode === 'self') { | ||
| 1761 | this.element.addClass('ui-datascroller-inline'); | ||
| 1762 | |||
| 1763 | if(this.options.scrollHeight) { | ||
| 1764 | this.content.css('height', this.options.scrollHeight); | ||
| 1765 | } | ||
| 1766 | } | ||
| 1767 | |||
| 1768 | if(this.options.loader) { | ||
| 1769 | this.bindManualLoader(); | ||
| 1770 | } | ||
| 1771 | else { | ||
| 1772 | this.bindScrollListener(); | ||
| 1773 | } | ||
| 1774 | |||
| 1775 | if(this.options.datasource) { | ||
| 1776 | if($.isArray(this.options.datasource)) { | ||
| 1777 | this._onDataInit(this.options.datasource); | ||
| 1778 | } | ||
| 1779 | else { | ||
| 1780 | if($.type(this.options.datasource) === 'string') { | ||
| 1781 | var $this = this, | ||
| 1782 | dataURL = this.options.datasource; | ||
| 1783 | |||
| 1784 | this.options.datasource = function() { | ||
| 1785 | $.ajax({ | ||
| 1786 | type: 'GET', | ||
| 1787 | url: dataURL, | ||
| 1788 | dataType: "json", | ||
| 1789 | context: $this, | ||
| 1790 | success: function (response) { | ||
| 1791 | this._onDataInit(response); | ||
| 1792 | } | ||
| 1793 | }); | ||
| 1794 | }; | ||
| 1795 | } | ||
| 1796 | |||
| 1797 | if($.type(this.options.datasource) === 'function') { | ||
| 1798 | if(this.options.lazy) | ||
| 1799 | this.options.datasource.call(this, this._onLazyLoad, {first:this.offset}); | ||
| 1800 | else | ||
| 1801 | this.options.datasource.call(this, this._onDataInit); | ||
| 1802 | } | ||
| 1803 | } | ||
| 1804 | } | ||
| 1805 | }, | ||
| 1806 | |||
| 1807 | _onDataInit: function(data) { | ||
| 1808 | this.data = data||[]; | ||
| 1809 | this.options.totalSize = this.data.length; | ||
| 1810 | |||
| 1811 | this._load(); | ||
| 1812 | }, | ||
| 1813 | |||
| 1814 | _onLazyLoad: function(data) { | ||
| 1815 | this._renderData(data, 0, this.options.chunkSize); | ||
| 1816 | |||
| 1817 | this._onloadComplete(); | ||
| 1818 | }, | ||
| 1819 | |||
| 1820 | bindScrollListener: function() { | ||
| 1821 | var $this = this; | ||
| 1822 | |||
| 1823 | if(this.options.mode === 'document') { | ||
| 1824 | var win = $(window), | ||
| 1825 | doc = $(document), | ||
| 1826 | $this = this, | ||
| 1827 | NS = 'scroll.' + this.id; | ||
| 1828 | |||
| 1829 | win.off(NS).on(NS, function () { | ||
| 1830 | if(win.scrollTop() >= ((doc.height() * $this.options.buffer) - win.height()) && $this.shouldLoad()) { | ||
| 1831 | $this._load(); | ||
| 1832 | } | ||
| 1833 | }); | ||
| 1834 | } | ||
| 1835 | else { | ||
| 1836 | this.content.on('scroll', function () { | ||
| 1837 | var scrollTop = this.scrollTop, | ||
| 1838 | scrollHeight = this.scrollHeight, | ||
| 1839 | viewportHeight = this.clientHeight; | ||
| 1840 | |||
| 1841 | if((scrollTop >= ((scrollHeight * $this.options.buffer) - (viewportHeight))) && $this.shouldLoad()) { | ||
| 1842 | $this._load(); | ||
| 1843 | } | ||
| 1844 | }); | ||
| 1845 | } | ||
| 1846 | }, | ||
| 1847 | |||
| 1848 | bindManualLoader: function() { | ||
| 1849 | var $this = this; | ||
| 1850 | |||
| 1851 | this.options.loader.on('click.dataScroller', function(e) { | ||
| 1852 | $this._load(); | ||
| 1853 | e.preventDefault(); | ||
| 1854 | }); | ||
| 1855 | }, | ||
| 1856 | |||
| 1857 | _load: function() { | ||
| 1858 | this.loading = true; | ||
| 1859 | this.loadStatus.appendTo(this.loaderContainer); | ||
| 1860 | if(this.options.loader) { | ||
| 1861 | this.options.loader.hide(); | ||
| 1862 | } | ||
| 1863 | |||
| 1864 | if(this.options.lazy) { | ||
| 1865 | this.options.datasource.call(this, this._onLazyLoad, {first: this.offset}); | ||
| 1866 | } | ||
| 1867 | else { | ||
| 1868 | this._renderData(this.data, this.offset, (this.offset + this.options.chunkSize)); | ||
| 1869 | this._onloadComplete(); | ||
| 1870 | } | ||
| 1871 | }, | ||
| 1872 | |||
| 1873 | _renderData: function(data, start, end) { | ||
| 1874 | if(data && data.length) { | ||
| 1875 | for(var i = start; i < end; i++) { | ||
| 1876 | var listItem = $('<li class="ui-datascroller-item"></li>'), | ||
| 1877 | content = this._createItemContent(data[i]); | ||
| 1878 | listItem.append(content); | ||
| 1879 | |||
| 1880 | this.list.append(listItem); | ||
| 1881 | } | ||
| 1882 | } | ||
| 1883 | }, | ||
| 1884 | |||
| 1885 | shouldLoad: function() { | ||
| 1886 | return (!this.loading && !this.allLoaded); | ||
| 1887 | }, | ||
| 1888 | |||
| 1889 | _createItemContent: function(obj) { | ||
| 1890 | if(this.options.template) { | ||
| 1891 | var template = this.options.template.html(); | ||
| 1892 | Mustache.parse(template); | ||
| 1893 | return Mustache.render(template, obj); | ||
| 1894 | } | ||
| 1895 | else { | ||
| 1896 | return this.options.content.call(this, obj); | ||
| 1897 | } | ||
| 1898 | }, | ||
| 1899 | |||
| 1900 | _onloadComplete: function() { | ||
| 1901 | this.offset += this.options.chunkSize; | ||
| 1902 | this.loading = false; | ||
| 1903 | this.allLoaded = this.offset >= this.options.totalSize; | ||
| 1904 | |||
| 1905 | this.loadStatus.remove(); | ||
| 1906 | |||
| 1907 | if(this.options.loader && !this.allLoaded) { | ||
| 1908 | this.options.loader.show(); | ||
| 1909 | } | ||
| 1910 | } | ||
| 1911 | |||
| 1912 | }); | ||
| 1913 | |||
| 1914 | })(); | ||
| 1915 | /** | ||
| 1916 | * PrimeUI Datatable Widget | ||
| 1917 | */ | ||
| 1918 | (function() { | ||
| 1919 | |||
| 1920 | $.widget("primeui.puidatatable", { | ||
| 1921 | |||
| 1922 | options: { | ||
| 1923 | columns: null, | ||
| 1924 | datasource: null, | ||
| 1925 | paginator: null, | ||
| 1926 | globalFilter:null, | ||
| 1927 | selectionMode: null, | ||
| 1928 | caption: null, | ||
| 1929 | footer: null, | ||
| 1930 | sortField: null, | ||
| 1931 | sortOrder: 1, | ||
| 1932 | sortMeta: [], | ||
| 1933 | sortMode: null, | ||
| 1934 | scrollable: false, | ||
| 1935 | scrollHeight: null, | ||
| 1936 | scrollWidth: null, | ||
| 1937 | responsive: false, | ||
| 1938 | expandableRows: false, | ||
| 1939 | expandedRowContent: null, | ||
| 1940 | rowExpandMode: 'multiple', | ||
| 1941 | draggableColumns: false, | ||
| 1942 | resizableColumns: false, | ||
| 1943 | columnResizeMode: 'fit', | ||
| 1944 | draggableRows: false, | ||
| 1945 | filterDelay: 300, | ||
| 1946 | stickyHeader: false, | ||
| 1947 | editMode: null, | ||
| 1948 | tabindex: 0, | ||
| 1949 | emptyMessage: 'No records found', | ||
| 1950 | sort: null, | ||
| 1951 | rowSelect: null, | ||
| 1952 | rowUnselect: null, | ||
| 1953 | rowSelectContextMenu: null, | ||
| 1954 | rowCollapse: null, | ||
| 1955 | rowExpand: null, | ||
| 1956 | colReorder: null, | ||
| 1957 | colResize: null, | ||
| 1958 | rowReorder: null, | ||
| 1959 | cellEdit: null | ||
| 1960 | }, | ||
| 1961 | |||
| 1962 | _create: function() { | ||
| 1963 | this.id = this.element.attr('id'); | ||
| 1964 | if(!this.id) { | ||
| 1965 | this.id = this.element.uniqueId().attr('id'); | ||
| 1966 | } | ||
| 1967 | |||
| 1968 | this.element.addClass('ui-datatable ui-widget'); | ||
| 1969 | if(this.options.responsive) { | ||
| 1970 | this.element.addClass('ui-datatable-reflow'); | ||
| 1971 | } | ||
| 1972 | |||
| 1973 | if(this.options.scrollable) { | ||
| 1974 | this._createScrollableDatatable(); | ||
| 1975 | } | ||
| 1976 | else { | ||
| 1977 | this._createRegularDatatable(); | ||
| 1978 | } | ||
| 1979 | |||
| 1980 | if(this.options.datasource) { | ||
| 1981 | if($.isArray(this.options.datasource)) { | ||
| 1982 | this._onDataInit(this.options.datasource); | ||
| 1983 | } | ||
| 1984 | else { | ||
| 1985 | if($.type(this.options.datasource) === 'string') { | ||
| 1986 | var $this = this, | ||
| 1987 | dataURL = this.options.datasource; | ||
| 1988 | |||
| 1989 | this.options.datasource = function() { | ||
| 1990 | $.ajax({ | ||
| 1991 | type: 'GET', | ||
| 1992 | url: dataURL, | ||
| 1993 | dataType: "json", | ||
| 1994 | context: $this, | ||
| 1995 | success: function (response) { | ||
| 1996 | this._onDataInit(response); | ||
| 1997 | } | ||
| 1998 | }); | ||
| 1999 | }; | ||
| 2000 | } | ||
| 2001 | |||
| 2002 | if($.type(this.options.datasource) === 'function') { | ||
| 2003 | if(this.options.lazy) | ||
| 2004 | this.options.datasource.call(this, this._onDataInit, {first:0, rows:this._getRows(), sortField:this.options.sortField, sortOrder:this.options.sortOrder, filters: this._createFilterMap()}); | ||
| 2005 | else | ||
| 2006 | this.options.datasource.call(this, this._onDataInit); | ||
| 2007 | } | ||
| 2008 | } | ||
| 2009 | } | ||
| 2010 | }, | ||
| 2011 | |||
| 2012 | _createRegularDatatable: function() { | ||
| 2013 | this.tableWrapper = $('<div class="ui-datatable-tablewrapper" />').appendTo(this.element); | ||
| 2014 | this.table = $('<table><thead></thead><tbody></tbody></table>').appendTo(this.tableWrapper); | ||
| 2015 | this.thead = this.table.children('thead'); | ||
| 2016 | this.tbody = this.table.children('tbody').addClass('ui-datatable-data ui-widget-content'); | ||
| 2017 | |||
| 2018 | if(this.containsFooter()) { | ||
| 2019 | this.tfoot = this.thead.after('<tfoot></tfoot>').next(); | ||
| 2020 | } | ||
| 2021 | }, | ||
| 2022 | |||
| 2023 | _createScrollableDatatable: function() { | ||
| 2024 | this.element.append('<div class="ui-widget-header ui-datatable-scrollable-header"><div class="ui-datatable-scrollable-header-box"><table><thead></thead></table></div></div>') | ||
| 2025 | .append('<div class="ui-datatable-scrollable-body"><table><tbody></tbody></table></div>'); | ||
| 2026 | |||
| 2027 | this.thead = this.element.find('> .ui-datatable-scrollable-header > .ui-datatable-scrollable-header-box > table > thead'); | ||
| 2028 | this.tbody = this.element.find('> .ui-datatable-scrollable-body > table > tbody'); | ||
| 2029 | |||
| 2030 | if(this.containsFooter()) { | ||
| 2031 | this.element.append('<div class="ui-widget-header ui-datatable-scrollable-footer"><div class="ui-datatable-scrollable-footer-box"><table><tfoot></tfoot></table></div></div>'); | ||
| 2032 | this.tfoot = this.element.find('> .ui-datatable-scrollable-footer > .ui-datatable-scrollable-footer-box > table > tfoot'); | ||
| 2033 | } | ||
| 2034 | }, | ||
| 2035 | |||
| 2036 | _initialize: function() { | ||
| 2037 | var $this = this; | ||
| 2038 | |||
| 2039 | this._initHeader(); | ||
| 2040 | this._initFooter(); | ||
| 2041 | |||
| 2042 | if(this.options.caption) { | ||
| 2043 | this.element.prepend('<div class="ui-datatable-header ui-widget-header">' + this.options.caption + '</div>'); | ||
| 2044 | } | ||
| 2045 | |||
| 2046 | if(this.options.paginator) { | ||
| 2047 | this.options.paginator.paginate = function(event, state) { | ||
| 2048 | $this.paginate(); | ||
| 2049 | }; | ||
| 2050 | |||
| 2051 | this.options.paginator.totalRecords = this.options.lazy ? this.options.paginator.totalRecords : this.data.length; | ||
| 2052 | this.paginator = $('<div></div>').insertAfter(this.tableWrapper).puipaginator(this.options.paginator); | ||
| 2053 | if(this.options.paginator.contentLeft) { | ||
| 2054 | this.paginator.prepend(this.options.paginator.contentLeft.call()); | ||
| 2055 | } | ||
| 2056 | if(this.options.paginator.contentRight) { | ||
| 2057 | this.paginator.append(this.options.paginator.contentRight.call()); | ||
| 2058 | } | ||
| 2059 | } | ||
| 2060 | |||
| 2061 | if(this.options.footer) { | ||
| 2062 | this.element.append('<div class="ui-datatable-footer ui-widget-header">' + this.options.footer + '</div>'); | ||
| 2063 | } | ||
| 2064 | |||
| 2065 | if(this._isSortingEnabled()) { | ||
| 2066 | this._initSorting(); | ||
| 2067 | } | ||
| 2068 | |||
| 2069 | if(this.hasFiltering) { | ||
| 2070 | this._initFiltering(); | ||
| 2071 | } | ||
| 2072 | |||
| 2073 | if(this.options.selectionMode) { | ||
| 2074 | this._initSelection(); | ||
| 2075 | } | ||
| 2076 | |||
| 2077 | if(this.options.expandableRows) { | ||
| 2078 | this._initExpandableRows(); | ||
| 2079 | } | ||
| 2080 | |||
| 2081 | if(this.options.draggableColumns) { | ||
| 2082 | this._initDraggableColumns(); | ||
| 2083 | } | ||
| 2084 | |||
| 2085 | if(this.options.stickyHeader) { | ||
| 2086 | this._initStickyHeader(); | ||
| 2087 | } | ||
| 2088 | |||
| 2089 | if ((this.options.sortField && this.options.sortOrder) || this.options.sortMeta.length) { | ||
| 2090 | this.sortByDefault(); | ||
| 2091 | } | ||
| 2092 | else { | ||
| 2093 | this._renderData(); | ||
| 2094 | } | ||
| 2095 | |||
| 2096 | if(this.options.scrollable) { | ||
| 2097 | this._initScrolling(); | ||
| 2098 | } | ||
| 2099 | |||
| 2100 | if(this.options.resizableColumns) { | ||
| 2101 | this._initResizableColumns(); | ||
| 2102 | } | ||
| 2103 | |||
| 2104 | if(this.options.draggableRows) { | ||
| 2105 | this._initDraggableRows(); | ||
| 2106 | } | ||
| 2107 | |||
| 2108 | if(this.options.editMode) { | ||
| 2109 | this._initEditing(); | ||
| 2110 | } | ||
| 2111 | |||
| 2112 | }, | ||
| 2113 | |||
| 2114 | _initHeader: function() { | ||
| 2115 | if(this.options.headerRows) { | ||
| 2116 | for(var i = 0; i < this.options.headerRows.length; i++) { | ||
| 2117 | this._initHeaderColumns(this.options.headerRows[i].columns); | ||
| 2118 | } | ||
| 2119 | } | ||
| 2120 | else if(this.options.columns) { | ||
| 2121 | this._initHeaderColumns(this.options.columns); | ||
| 2122 | } | ||
| 2123 | }, | ||
| 2124 | |||
| 2125 | _initFooter: function() { | ||
| 2126 | if(this.containsFooter()) { | ||
| 2127 | if(this.options.footerRows) { | ||
| 2128 | for(var i = 0; i < this.options.footerRows.length; i++) { | ||
| 2129 | this._initFooterColumns(this.options.footerRows[i].columns); | ||
| 2130 | } | ||
| 2131 | } | ||
| 2132 | else if(this.options.columns) { | ||
| 2133 | this._initFooterColumns(this.options.columns); | ||
| 2134 | } | ||
| 2135 | } | ||
| 2136 | }, | ||
| 2137 | |||
| 2138 | _initHeaderColumns: function(columns) { | ||
| 2139 | var headerRow = $('<tr class="ui-state-default"></tr>').appendTo(this.thead), | ||
| 2140 | $this = this; | ||
| 2141 | |||
| 2142 | $.each(columns, function(i, col) { | ||
| 2143 | var cell = $('<th class="ui-state-default"><span class="ui-column-title"></span></th>').data('field', col.field).uniqueId().appendTo(headerRow); | ||
| 2144 | |||
| 2145 | if(col.headerClass) { | ||
| 2146 | cell.addClass(col.headerClass); | ||
| 2147 | } | ||
| 2148 | |||
| 2149 | if(col.headerStyle) { | ||
| 2150 | cell.attr('style', col.headerStyle); | ||
| 2151 | } | ||
| 2152 | |||
| 2153 | if(col.headerText) | ||
| 2154 | cell.children('.ui-column-title').text(col.headerText); | ||
| 2155 | else if(col.headerContent) | ||
| 2156 | cell.children('.ui-column-title').append(col.headerContent.call(this, col)); | ||
| 2157 | |||
| 2158 | if(col.rowspan) { | ||
| 2159 | cell.attr('rowspan', col.rowspan); | ||
| 2160 | } | ||
| 2161 | |||
| 2162 | if(col.colspan) { | ||
| 2163 | cell.attr('colspan', col.colspan); | ||
| 2164 | } | ||
| 2165 | |||
| 2166 | if(col.sortable) { | ||
| 2167 | cell.addClass('ui-sortable-column') | ||
| 2168 | .data('order', 0) | ||
| 2169 | .append('<span class="ui-sortable-column-icon fa fa-fw fa-sort"></span>'); | ||
| 2170 | } | ||
| 2171 | |||
| 2172 | if(col.filter) { | ||
| 2173 | $this.hasFiltering = true; | ||
| 2174 | |||
| 2175 | var filterElement = $('<input type="text" class="ui-column-filter" />').puiinputtext().data({ | ||
| 2176 | 'field': col.field, | ||
| 2177 | 'filtermatchmode': col.filterMatchMode||'startsWith' | ||
| 2178 | }).appendTo(cell); | ||
| 2179 | |||
| 2180 | if(col.filterFunction) { | ||
| 2181 | filterElement.on('filter', function(event, dataValue, filterValue) { | ||
| 2182 | return col.filterFunction.call($this, dataValue, filterValue); | ||
| 2183 | }); | ||
| 2184 | } | ||
| 2185 | } | ||
| 2186 | }); | ||
| 2187 | }, | ||
| 2188 | |||
| 2189 | _initFooterColumns: function(columns) { | ||
| 2190 | var footerRow = $('<tr></tr>').appendTo(this.tfoot); | ||
| 2191 | $.each(columns, function(i, col) { | ||
| 2192 | var cell = $('<td class="ui-state-default"></td>'); | ||
| 2193 | if(col.footerText) { | ||
| 2194 | cell.text(col.footerText); | ||
| 2195 | } | ||
| 2196 | |||
| 2197 | if(col.rowspan) { | ||
| 2198 | cell.attr('rowspan', col.rowspan); | ||
| 2199 | } | ||
| 2200 | |||
| 2201 | if(col.colspan) { | ||
| 2202 | cell.attr('colspan', col.colspan); | ||
| 2203 | } | ||
| 2204 | |||
| 2205 | cell.appendTo(footerRow); | ||
| 2206 | }); | ||
| 2207 | }, | ||
| 2208 | |||
| 2209 | _indicateInitialSortColumn: function(sortField, sortOrder) { | ||
| 2210 | var $this = this; | ||
| 2211 | |||
| 2212 | $.each(this.sortableColumns, function(i, column) { | ||
| 2213 | var $column = $(column), | ||
| 2214 | data = $column.data(); | ||
| 2215 | |||
| 2216 | if (sortField === data.field) { | ||
| 2217 | var sortIcon = $column.children('.ui-sortable-column-icon'); | ||
| 2218 | $column.data('order', sortOrder).removeClass('ui-state-hover').addClass('ui-state-active'); | ||
| 2219 | |||
| 2220 | if(sortOrder == -1) | ||
| 2221 | sortIcon.removeClass('fa-sort fa-sort-asc').addClass('fa-sort-desc'); | ||
| 2222 | else if(sortOrder == 1) | ||
| 2223 | sortIcon.removeClass('fa-sort fa-sort-desc').addClass('fa-sort-asc'); | ||
| 2224 | } | ||
| 2225 | }); | ||
| 2226 | }, | ||
| 2227 | |||
| 2228 | _indicateInitialSortColumns: function() { | ||
| 2229 | var $this = this; | ||
| 2230 | |||
| 2231 | for(var i = 0; i < this.options.sortMeta.length; i++) { | ||
| 2232 | var meta = this.options.sortMeta[i]; | ||
| 2233 | this._indicateInitialSortColumn(meta.field, meta.order); | ||
| 2234 | } | ||
| 2235 | }, | ||
| 2236 | |||
| 2237 | _onDataInit: function(data) { | ||
| 2238 | this.data = data; | ||
| 2239 | if(!this.data) { | ||
| 2240 | this.data = []; | ||
| 2241 | } | ||
| 2242 | |||
| 2243 | this._initialize(); | ||
| 2244 | }, | ||
| 2245 | |||
| 2246 | _onDataUpdate: function(data) { | ||
| 2247 | this.data = data; | ||
| 2248 | if(!this.data) { | ||
| 2249 | this.data = []; | ||
| 2250 | } | ||
| 2251 | |||
| 2252 | this.reset(); | ||
| 2253 | |||
| 2254 | this._renderData(); | ||
| 2255 | }, | ||
| 2256 | |||
| 2257 | _onLazyLoad: function(data) { | ||
| 2258 | this.data = data; | ||
| 2259 | if(!this.data) { | ||
| 2260 | this.data = []; | ||
| 2261 | } | ||
| 2262 | |||
| 2263 | this._renderData(); | ||
| 2264 | }, | ||
| 2265 | |||
| 2266 | reset: function() { | ||
| 2267 | if(this.options.selectionMode) { | ||
| 2268 | this.selection = []; | ||
| 2269 | } | ||
| 2270 | |||
| 2271 | if(this.paginator) { | ||
| 2272 | this.paginator.puipaginator('setState', { | ||
| 2273 | page: 0, | ||
| 2274 | totalRecords: this.options.lazy ? this.options.paginator.totalRecords : this.data.length | ||
| 2275 | }); | ||
| 2276 | } | ||
| 2277 | |||
| 2278 | this.thead.find('> tr > th.ui-sortable-column').data('order', 0).filter('.ui-state-active').removeClass('ui-state-active') | ||
| 2279 | .children('span.ui-sortable-column-icon').removeClass('fa-sort-asc fa-sort-desc').addClass('fa-sort'); | ||
| 2280 | }, | ||
| 2281 | |||
| 2282 | _isMultiSort: function() { | ||
| 2283 | if(this.options.sortMode === 'multiple') | ||
| 2284 | return true; | ||
| 2285 | else | ||
| 2286 | return false; | ||
| 2287 | }, | ||
| 2288 | |||
| 2289 | _resetSortState: function(column) { | ||
| 2290 | this.sortableColumns.filter('.ui-state-active').data('order', 0).removeClass('ui-state-active').children('span.ui-sortable-column-icon') | ||
| 2291 | .removeClass('fa-sort-asc fa-sort-desc').addClass('fa-sort'); | ||
| 2292 | }, | ||
| 2293 | |||
| 2294 | _initSorting: function() { | ||
| 2295 | var $this = this; | ||
| 2296 | this.sortableColumns = this.thead.find('> tr > th.ui-sortable-column'); | ||
| 2297 | |||
| 2298 | this.sortableColumns.on('mouseover.puidatatable', function() { | ||
| 2299 | var column = $(this); | ||
| 2300 | |||
| 2301 | if(!column.hasClass('ui-state-active')) | ||
| 2302 | column.addClass('ui-state-hover'); | ||
| 2303 | }) | ||
| 2304 | .on('mouseout.puidatatable', function() { | ||
| 2305 | var column = $(this); | ||
| 2306 | |||
| 2307 | if(!column.hasClass('ui-state-active')) | ||
| 2308 | column.removeClass('ui-state-hover'); | ||
| 2309 | }) | ||
| 2310 | .on('click.puidatatable', function(event) { | ||
| 2311 | if(!$(event.target).is('th,span')) { | ||
| 2312 | return; | ||
| 2313 | } | ||
| 2314 | |||
| 2315 | var column = $(this), | ||
| 2316 | sortField = column.data('field'), | ||
| 2317 | order = column.data('order'), | ||
| 2318 | sortOrder = (order === 0) ? 1 : (order * -1), | ||
| 2319 | sortIcon = column.children('.ui-sortable-column-icon'), | ||
| 2320 | metaKey = event.metaKey||event.ctrlKey; | ||
| 2321 | |||
| 2322 | if($this._isMultiSort()) { | ||
| 2323 | if(metaKey) { | ||
| 2324 | $this._addSortMeta({field: sortField, order: sortOrder}); | ||
| 2325 | $this.sort(); | ||
| 2326 | } | ||
| 2327 | else { | ||
| 2328 | $this.options.sortMeta = []; | ||
| 2329 | $this._addSortMeta({field: sortField, order: sortOrder}); | ||
| 2330 | $this._resetSortState(column); | ||
| 2331 | $this.sort(); | ||
| 2332 | } | ||
| 2333 | } | ||
| 2334 | else { | ||
| 2335 | //update state | ||
| 2336 | $this.options.sortField = sortField; | ||
| 2337 | $this.options.sortOrder = sortOrder; | ||
| 2338 | |||
| 2339 | $this._resetSortState(column); | ||
| 2340 | $this.sort(); | ||
| 2341 | } | ||
| 2342 | |||
| 2343 | //update visuals | ||
| 2344 | column.data('order', sortOrder).removeClass('ui-state-hover').addClass('ui-state-active'); | ||
| 2345 | if(sortOrder === -1) | ||
| 2346 | sortIcon.removeClass('fa-sort fa-sort-asc').addClass('fa-sort-desc'); | ||
| 2347 | else if(sortOrder === 1) | ||
| 2348 | sortIcon.removeClass('fa-sort fa-sort-desc').addClass('fa-sort-asc'); | ||
| 2349 | |||
| 2350 | $this._trigger('sort', event, {'sortOrder': sortOrder, 'sortField': sortField}); | ||
| 2351 | }); | ||
| 2352 | }, | ||
| 2353 | |||
| 2354 | _addSortMeta: function(meta) { | ||
| 2355 | var index = -1; | ||
| 2356 | for(var i = 0; i < this.options.sortMeta.length; i++) { | ||
| 2357 | if(this.options.sortMeta[i].field === meta.field) { | ||
| 2358 | index = i; | ||
| 2359 | } | ||
| 2360 | } | ||
| 2361 | |||
| 2362 | if(index >= 0) | ||
| 2363 | this.options.sortMeta[index] = meta; | ||
| 2364 | else | ||
| 2365 | this.options.sortMeta.push(meta); | ||
| 2366 | }, | ||
| 2367 | |||
| 2368 | paginate: function() { | ||
| 2369 | if(this.options.lazy) { | ||
| 2370 | this.options.datasource.call(this, this._onLazyLoad, this._createStateMeta()); | ||
| 2371 | } | ||
| 2372 | else { | ||
| 2373 | this._renderData(); | ||
| 2374 | } | ||
| 2375 | }, | ||
| 2376 | |||
| 2377 | _multipleSort: function() { | ||
| 2378 | var $this = this; | ||
| 2379 | |||
| 2380 | function multisort(data1,data2,sortMeta,index) { | ||
| 2381 | var value1 = data1[sortMeta[index].field], | ||
| 2382 | value2 = data2[sortMeta[index].field], | ||
| 2383 | result = null; | ||
| 2384 | |||
| 2385 | if (typeof value1 == 'string' || value1 instanceof String) { | ||
| 2386 | if (value1.localeCompare && (value1 != value2)) { | ||
| 2387 | return (sortMeta[index].order * value1.localeCompare(value2)); | ||
| 2388 | } | ||
| 2389 | } | ||
| 2390 | else { | ||
| 2391 | result = (value1 < value2) ? -1 : 1; | ||
| 2392 | } | ||
| 2393 | |||
| 2394 | if(value1 == value2) { | ||
| 2395 | return (sortMeta.length - 1) > (index) ? (multisort(data1, data2, sortMeta, index + 1)) : 0; | ||
| 2396 | } | ||
| 2397 | |||
| 2398 | return (sortMeta[index].order * result); | ||
| 2399 | } | ||
| 2400 | |||
| 2401 | this.data.sort(function (data1,data2) { | ||
| 2402 | return multisort(data1, data2, $this.options.sortMeta, 0); | ||
| 2403 | }); | ||
| 2404 | |||
| 2405 | this._renderData(); | ||
| 2406 | }, | ||
| 2407 | |||
| 2408 | sort: function() { | ||
| 2409 | if(this.options.lazy) { | ||
| 2410 | this.options.datasource.call(this, this._onLazyLoad, this._createStateMeta()); | ||
| 2411 | } | ||
| 2412 | else { | ||
| 2413 | if(this._isMultiSort()) | ||
| 2414 | this._multipleSort(); | ||
| 2415 | else | ||
| 2416 | this._singleSort(); | ||
| 2417 | } | ||
| 2418 | }, | ||
| 2419 | |||
| 2420 | _singleSort: function() { | ||
| 2421 | var $this = this; | ||
| 2422 | |||
| 2423 | this.data.sort(function(data1, data2) { | ||
| 2424 | var value1 = data1[$this.options.sortField], value2 = data2[$this.options.sortField], | ||
| 2425 | result = null; | ||
| 2426 | |||
| 2427 | if (typeof value1 == 'string' || value1 instanceof String) { | ||
| 2428 | if ( value1.localeCompare ) { | ||
| 2429 | return ($this.options.sortOrder * value1.localeCompare(value2)); | ||
| 2430 | } | ||
| 2431 | else { | ||
| 2432 | if (value1.toLowerCase) { | ||
| 2433 | value1 = value1.toLowerCase(); | ||
| 2434 | } | ||
| 2435 | if (value2.toLowerCase) { | ||
| 2436 | value2 = value2.toLowerCase(); | ||
| 2437 | } | ||
| 2438 | result = (value1 < value2) ? -1 : (value1 > value2) ? 1 : 0; | ||
| 2439 | |||
| 2440 | } | ||
| 2441 | } | ||
| 2442 | else { | ||
| 2443 | result = (value1 < value2) ? -1 : (value1 > value2) ? 1 : 0; | ||
| 2444 | } | ||
| 2445 | |||
| 2446 | return ($this.options.sortOrder * result); | ||
| 2447 | }); | ||
| 2448 | |||
| 2449 | if(this.paginator) { | ||
| 2450 | this.paginator.puipaginator('option', 'page', 0); | ||
| 2451 | } | ||
| 2452 | |||
| 2453 | this._renderData(); | ||
| 2454 | }, | ||
| 2455 | |||
| 2456 | sortByField: function(a, b) { | ||
| 2457 | var aName = a.name.toLowerCase(); | ||
| 2458 | var bName = b.name.toLowerCase(); | ||
| 2459 | return ((aName < bName) ? -1 : ((aName > bName) ? 1 : 0)); | ||
| 2460 | }, | ||
| 2461 | |||
| 2462 | sortByDefault: function() { | ||
| 2463 | if(this._isMultiSort()) { | ||
| 2464 | if(this.options.sortMeta) { | ||
| 2465 | this._indicateInitialSortColumns(); | ||
| 2466 | this.sort(); | ||
| 2467 | } | ||
| 2468 | } | ||
| 2469 | else { | ||
| 2470 | this._indicateInitialSortColumn(this.options.sortField, this.options.sortOrder); | ||
| 2471 | this.sort(); | ||
| 2472 | } | ||
| 2473 | }, | ||
| 2474 | |||
| 2475 | _renderData: function() { | ||
| 2476 | this.tbody.html(''); | ||
| 2477 | |||
| 2478 | var dataToRender = this.filteredData||this.data; | ||
| 2479 | if(dataToRender && dataToRender.length) { | ||
| 2480 | var firstNonLazy = this._getFirst(), | ||
| 2481 | first = this.options.lazy ? 0 : firstNonLazy, | ||
| 2482 | rows = this._getRows(); | ||
| 2483 | |||
| 2484 | for(var i = first; i < (first + rows); i++) { | ||
| 2485 | var rowData = dataToRender[i]; | ||
| 2486 | |||
| 2487 | if(rowData) { | ||
| 2488 | var row = $('<tr class="ui-widget-content" />').appendTo(this.tbody), | ||
| 2489 | zebraStyle = (i%2 === 0) ? 'ui-datatable-even' : 'ui-datatable-odd', | ||
| 2490 | rowIndex = i; | ||
| 2491 | |||
| 2492 | row.addClass(zebraStyle); | ||
| 2493 | row.data('rowdata', rowData); | ||
| 2494 | |||
| 2495 | if(this.options.selectionMode && this._isSelected(rowData)) { | ||
| 2496 | row.addClass("ui-state-highlight"); | ||
| 2497 | } | ||
| 2498 | |||
| 2499 | for(var j = 0; j < this.options.columns.length; j++) { | ||
| 2500 | var column = $('<td />').appendTo(row), | ||
| 2501 | columnOptions = this.options.columns[j]; | ||
| 2502 | |||
| 2503 | if(columnOptions.bodyClass) { | ||
| 2504 | column.addClass(columnOptions.bodyClass); | ||
| 2505 | } | ||
| 2506 | |||
| 2507 | if(columnOptions.bodyStyle) { | ||
| 2508 | column.attr('style', columnOptions.bodyStyle); | ||
| 2509 | } | ||
| 2510 | |||
| 2511 | if(columnOptions.editor) { | ||
| 2512 | column.addClass('ui-editable-column').data({ | ||
| 2513 | 'editor': columnOptions.editor, | ||
| 2514 | 'rowdata': rowData, | ||
| 2515 | 'field': columnOptions.field | ||
| 2516 | }); | ||
| 2517 | } | ||
| 2518 | |||
| 2519 | if(columnOptions.content) { | ||
| 2520 | var content = columnOptions.content.call(this, rowData, columnOptions); | ||
| 2521 | if($.type(content) === 'string') | ||
| 2522 | column.html(content); | ||
| 2523 | else | ||
| 2524 | column.append(content); | ||
| 2525 | } | ||
| 2526 | else if(columnOptions.rowToggler) { | ||
| 2527 | column.append('<div class="ui-row-toggler fa fa-fw fa-chevron-circle-right ui-c"></div>'); | ||
| 2528 | } | ||
| 2529 | else if(columnOptions.field) { | ||
| 2530 | column.text(rowData[columnOptions.field]); | ||
| 2531 | } | ||
| 2532 | |||
| 2533 | if(this.options.responsive && columnOptions.headerText) { | ||
| 2534 | column.prepend('<span class="ui-column-title">' + columnOptions.headerText + '</span>'); | ||
| 2535 | } | ||
| 2536 | } | ||
| 2537 | } | ||
| 2538 | } | ||
| 2539 | } | ||
| 2540 | else { | ||
| 2541 | var emptyRow = $('<tr class="ui-widget-content"></tr>').appendTo(this.tbody); | ||
| 2542 | var emptyColumn = $('<td></td>').attr('colspan',this.options.columns.length).appendTo(emptyRow); | ||
| 2543 | emptyColumn.html(this.options.emptyMessage); | ||
| 2544 | } | ||
| 2545 | }, | ||
| 2546 | |||
| 2547 | _getFirst: function() { | ||
| 2548 | if(this.paginator) { | ||
| 2549 | var page = this.paginator.puipaginator('option', 'page'), | ||
| 2550 | rows = this.paginator.puipaginator('option', 'rows'); | ||
| 2551 | |||
| 2552 | return (page * rows); | ||
| 2553 | } | ||
| 2554 | else { | ||
| 2555 | return 0; | ||
| 2556 | } | ||
| 2557 | }, | ||
| 2558 | |||
| 2559 | _getRows: function() { | ||
| 2560 | return this.paginator ? this.paginator.puipaginator('option', 'rows') : (this.data ? this.data.length : 0); | ||
| 2561 | }, | ||
| 2562 | |||
| 2563 | _isSortingEnabled: function() { | ||
| 2564 | var cols = this.options.columns; | ||
| 2565 | if(cols) { | ||
| 2566 | for(var i = 0; i < cols.length; i++) { | ||
| 2567 | if(cols[i].sortable) { | ||
| 2568 | return true; | ||
| 2569 | } | ||
| 2570 | } | ||
| 2571 | } | ||
| 2572 | |||
| 2573 | return false; | ||
| 2574 | }, | ||
| 2575 | |||
| 2576 | _initSelection: function() { | ||
| 2577 | var $this = this; | ||
| 2578 | this.selection = []; | ||
| 2579 | this.rowSelector = '> tr.ui-widget-content:not(.ui-datatable-empty-message,.ui-datatable-unselectable)'; | ||
| 2580 | |||
| 2581 | //shift key based range selection | ||
| 2582 | if(this._isMultipleSelection()) { | ||
| 2583 | this.originRowIndex = 0; | ||
| 2584 | this.cursorIndex = null; | ||
| 2585 | } | ||
| 2586 | |||
| 2587 | this.tbody.off('mouseover.puidatatable mouseout.puidatatable mousedown.puidatatable click.puidatatable', this.rowSelector) | ||
| 2588 | .on('mouseover.datatable', this.rowSelector, null, function() { | ||
| 2589 | var element = $(this); | ||
| 2590 | |||
| 2591 | if(!element.hasClass('ui-state-highlight')) { | ||
| 2592 | element.addClass('ui-state-hover'); | ||
| 2593 | } | ||
| 2594 | }) | ||
| 2595 | .on('mouseout.datatable', this.rowSelector, null, function() { | ||
| 2596 | var element = $(this); | ||
| 2597 | |||
| 2598 | if(!element.hasClass('ui-state-highlight')) { | ||
| 2599 | element.removeClass('ui-state-hover'); | ||
| 2600 | } | ||
| 2601 | }) | ||
| 2602 | .on('mousedown.datatable', this.rowSelector, null, function() { | ||
| 2603 | $this.mousedownOnRow = true; | ||
| 2604 | }) | ||
| 2605 | .on('click.datatable', this.rowSelector, null, function(e) { | ||
| 2606 | $this._onRowClick(e, this); | ||
| 2607 | $this.mousedownOnRow = false; | ||
| 2608 | }); | ||
| 2609 | |||
| 2610 | this._bindSelectionKeyEvents(); | ||
| 2611 | }, | ||
| 2612 | |||
| 2613 | _onRowClick: function(event, rowElement) { | ||
| 2614 | if(!$(event.target).is(':input,:button,a,.ui-c')) { | ||
| 2615 | var row = $(rowElement), | ||
| 2616 | selected = row.hasClass('ui-state-highlight'), | ||
| 2617 | metaKey = event.metaKey||event.ctrlKey, | ||
| 2618 | shiftKey = event.shiftKey; | ||
| 2619 | |||
| 2620 | this.focusedRow = row; | ||
| 2621 | |||
| 2622 | //unselect a selected row if metakey is on | ||
| 2623 | if(selected && metaKey) { | ||
| 2624 | this.unselectRow(row); | ||
| 2625 | } | ||
| 2626 | else { | ||
| 2627 | //unselect previous selection if this is single selection or multiple one with no keys | ||
| 2628 | if(this._isSingleSelection() || (this._isMultipleSelection() && !metaKey && !shiftKey)) { | ||
| 2629 | if (this._isMultipleSelection()) { | ||
| 2630 | var selections = this.getSelection(); | ||
| 2631 | for (var i = 0; i < selections.length; i++) { | ||
| 2632 | this._trigger('rowUnselect', null, selections[i]); | ||
| 2633 | } | ||
| 2634 | } | ||
| 2635 | |||
| 2636 | this.unselectAllRows(); | ||
| 2637 | } | ||
| 2638 | |||
| 2639 | this.selectRow(row, false, event); | ||
| 2640 | } | ||
| 2641 | |||
| 2642 | PUI.clearSelection(); | ||
| 2643 | } | ||
| 2644 | }, | ||
| 2645 | |||
| 2646 | onRowRightClick: function(event, rowElement) { | ||
| 2647 | var row = $(rowElement), | ||
| 2648 | selectedData = row.data('rowdata'), | ||
| 2649 | selected = row.hasClass('ui-state-highlight'); | ||
| 2650 | |||
| 2651 | if(this._isSingleSelection() || !selected) { | ||
| 2652 | this.unselectAllRows(); | ||
| 2653 | } | ||
| 2654 | |||
| 2655 | this.selectRow(row, true); | ||
| 2656 | this.dataSelectedByContextMenu = selectedData; | ||
| 2657 | this._trigger('rowSelectContextMenu', event, selectedData); | ||
| 2658 | |||
| 2659 | PUI.clearSelection(); | ||
| 2660 | }, | ||
| 2661 | |||
| 2662 | _bindSelectionKeyEvents: function() { | ||
| 2663 | var $this = this; | ||
| 2664 | |||
| 2665 | this.tbody.attr('tabindex', this.options.tabindex).on('focus', function(e) { | ||
| 2666 | //ignore mouse click on row | ||
| 2667 | if(!$this.mousedownOnRow) { | ||
| 2668 | $this.focusedRow = $this.tbody.children('tr.ui-widget-content').eq(0); | ||
| 2669 | $this.focusedRow.addClass('ui-state-hover'); | ||
| 2670 | } | ||
| 2671 | }) | ||
| 2672 | .on('blur', function() { | ||
| 2673 | if($this.focusedRow) { | ||
| 2674 | $this.focusedRow.removeClass('ui-state-hover'); | ||
| 2675 | $this.focusedRow = null; | ||
| 2676 | } | ||
| 2677 | }) | ||
| 2678 | .on('keydown', function(e) { | ||
| 2679 | var keyCode = $.ui.keyCode, | ||
| 2680 | key = e.which; | ||
| 2681 | |||
| 2682 | if($this.focusedRow) { | ||
| 2683 | switch(key) { | ||
| 2684 | case keyCode.UP: | ||
| 2685 | var prevRow = $this.focusedRow.prev('tr.ui-widget-content'); | ||
| 2686 | if(prevRow.length) { | ||
| 2687 | $this.focusedRow.removeClass('ui-state-hover'); | ||
| 2688 | $this.focusedRow = prevRow; | ||
| 2689 | $this.focusedRow.addClass('ui-state-hover'); | ||
| 2690 | } | ||
| 2691 | e.preventDefault(); | ||
| 2692 | break; | ||
| 2693 | |||
| 2694 | case keyCode.DOWN: | ||
| 2695 | var nextRow = $this.focusedRow.next('tr.ui-widget-content'); | ||
| 2696 | if(nextRow.length) { | ||
| 2697 | $this.focusedRow.removeClass('ui-state-hover'); | ||
| 2698 | $this.focusedRow = nextRow; | ||
| 2699 | $this.focusedRow.addClass('ui-state-hover'); | ||
| 2700 | } | ||
| 2701 | e.preventDefault(); | ||
| 2702 | break; | ||
| 2703 | |||
| 2704 | case keyCode.ENTER: | ||
| 2705 | case keyCode.NUMPAD_ENTER: | ||
| 2706 | case keyCode.SPACE: | ||
| 2707 | e.target = $this.focusedRow.children().eq(0).get(0); | ||
| 2708 | $this._onRowClick(e, $this.focusedRow.get(0)); | ||
| 2709 | e.preventDefault(); | ||
| 2710 | break; | ||
| 2711 | |||
| 2712 | default: | ||
| 2713 | break; | ||
| 2714 | }; | ||
| 2715 | } | ||
| 2716 | }); | ||
| 2717 | |||
| 2718 | }, | ||
| 2719 | |||
| 2720 | _isSingleSelection: function() { | ||
| 2721 | return this.options.selectionMode === 'single'; | ||
| 2722 | }, | ||
| 2723 | |||
| 2724 | _isMultipleSelection: function() { | ||
| 2725 | return this.options.selectionMode === 'multiple'; | ||
| 2726 | }, | ||
| 2727 | |||
| 2728 | unselectAllRows: function() { | ||
| 2729 | this.tbody.children('tr.ui-state-highlight').removeClass('ui-state-highlight').attr('aria-selected', false); | ||
| 2730 | this.selection = []; | ||
| 2731 | }, | ||
| 2732 | |||
| 2733 | unselectRow: function(row, silent) { | ||
| 2734 | var unselectedData = row.data('rowdata'); | ||
| 2735 | row.removeClass('ui-state-highlight').attr('aria-selected', false); | ||
| 2736 | |||
| 2737 | this._removeSelection(unselectedData); | ||
| 2738 | |||
| 2739 | if(!silent) { | ||
| 2740 | this._trigger('rowUnselect', null, unselectedData); | ||
| 2741 | } | ||
| 2742 | }, | ||
| 2743 | |||
| 2744 | selectRow: function(row, silent, event) { | ||
| 2745 | var selectedData = row.data('rowdata'); | ||
| 2746 | row.removeClass('ui-state-hover').addClass('ui-state-highlight').attr('aria-selected', true); | ||
| 2747 | |||
| 2748 | this._addSelection(selectedData); | ||
| 2749 | |||
| 2750 | if(!silent) { | ||
| 2751 | this._trigger('rowSelect', event, selectedData); | ||
| 2752 | } | ||
| 2753 | }, | ||
| 2754 | |||
| 2755 | getSelection: function() { | ||
| 2756 | return this.selection; | ||
| 2757 | }, | ||
| 2758 | |||
| 2759 | _removeSelection: function(rowData) { | ||
| 2760 | this.selection = $.grep(this.selection, function(value) { | ||
| 2761 | return value !== rowData; | ||
| 2762 | }); | ||
| 2763 | }, | ||
| 2764 | |||
| 2765 | _addSelection: function(rowData) { | ||
| 2766 | if(!this._isSelected(rowData)) { | ||
| 2767 | this.selection.push(rowData); | ||
| 2768 | } | ||
| 2769 | }, | ||
| 2770 | |||
| 2771 | _isSelected: function(rowData) { | ||
| 2772 | return PUI.inArray(this.selection, rowData); | ||
| 2773 | }, | ||
| 2774 | |||
| 2775 | _initExpandableRows: function() { | ||
| 2776 | var $this = this, | ||
| 2777 | togglerSelector = '> tr > td > div.ui-row-toggler'; | ||
| 2778 | |||
| 2779 | this.tbody.off('click', togglerSelector) | ||
| 2780 | .on('click', togglerSelector, null, function() { | ||
| 2781 | $this.toggleExpansion($(this)); | ||
| 2782 | }) | ||
| 2783 | .on('keydown', togglerSelector, null, function(e) { | ||
| 2784 | var key = e.which, | ||
| 2785 | keyCode = $.ui.keyCode; | ||
| 2786 | |||
| 2787 | if((key === keyCode.ENTER||key === keyCode.NUMPAD_ENTER)) { | ||
| 2788 | $this.toggleExpansion($(this)); | ||
| 2789 | e.preventDefault(); | ||
| 2790 | } | ||
| 2791 | }); | ||
| 2792 | }, | ||
| 2793 | |||
| 2794 | toggleExpansion: function(toggler) { | ||
| 2795 | var row = toggler.closest('tr'), | ||
| 2796 | expanded = toggler.hasClass('fa-chevron-circle-down'); | ||
| 2797 | |||
| 2798 | if(expanded) { | ||
| 2799 | toggler.addClass('fa-chevron-circle-right').removeClass('fa-chevron-circle-down').attr('aria-expanded', false); | ||
| 2800 | |||
| 2801 | this.collapseRow(row); | ||
| 2802 | this._trigger('rowCollapse', null, row.data('rowdata')); | ||
| 2803 | } | ||
| 2804 | else { | ||
| 2805 | if(this.options.rowExpandMode === 'single') { | ||
| 2806 | this.collapseAllRows(); | ||
| 2807 | } | ||
| 2808 | |||
| 2809 | toggler.addClass('fa-chevron-circle-down').removeClass('fa-chevron-circle-right').attr('aria-expanded', true); | ||
| 2810 | |||
| 2811 | this.loadExpandedRowContent(row); | ||
| 2812 | } | ||
| 2813 | }, | ||
| 2814 | |||
| 2815 | loadExpandedRowContent: function(row) { | ||
| 2816 | var expandedRow = $('<tr class="ui-expanded-row-content ui-datatable-unselectable ui-widget-content"><td colspan="' + this.options.columns.length + '"></td></tr>'); | ||
| 2817 | expandedRow.children('td').append(this.options.expandedRowContent.call(this, row.data('rowdata'))); | ||
| 2818 | |||
| 2819 | row.addClass('ui-expanded-row').after(expandedRow); | ||
| 2820 | this._trigger('rowExpand', null, row.data('rowdata')); | ||
| 2821 | }, | ||
| 2822 | |||
| 2823 | collapseRow: function(row) { | ||
| 2824 | row.removeClass('ui-expanded-row').next('.ui-expanded-row-content').remove(); | ||
| 2825 | }, | ||
| 2826 | |||
| 2827 | collapseAllRows: function() { | ||
| 2828 | var $this = this; | ||
| 2829 | |||
| 2830 | this.getExpandedRows().each(function () { | ||
| 2831 | var expandedRow = $(this); | ||
| 2832 | $this.collapseRow(expandedRow); | ||
| 2833 | |||
| 2834 | var columns = expandedRow.children('td'); | ||
| 2835 | for (var i = 0; i < columns.length; i++) { | ||
| 2836 | var column = columns.eq(i), | ||
| 2837 | toggler = column.children('.ui-row-toggler'); | ||
| 2838 | |||
| 2839 | if (toggler.length) { | ||
| 2840 | toggler.addClass('fa-chevron-circle-right').removeClass('fa-chevron-circle-down'); | ||
| 2841 | } | ||
| 2842 | } | ||
| 2843 | }); | ||
| 2844 | }, | ||
| 2845 | |||
| 2846 | getExpandedRows: function () { | ||
| 2847 | return this.tbody.children('.ui-expanded-row'); | ||
| 2848 | }, | ||
| 2849 | |||
| 2850 | _createStateMeta: function() { | ||
| 2851 | var state = { | ||
| 2852 | first: this._getFirst(), | ||
| 2853 | rows: this._getRows(), | ||
| 2854 | sortField: this.options.sortField, | ||
| 2855 | sortOrder: this.options.sortOrder, | ||
| 2856 | sortMeta: this.options.sortMeta, | ||
| 2857 | filters: this.filterMetaMap | ||
| 2858 | }; | ||
| 2859 | |||
| 2860 | return state; | ||
| 2861 | }, | ||
| 2862 | |||
| 2863 | _updateDatasource: function(datasource) { | ||
| 2864 | this.options.datasource = datasource; | ||
| 2865 | |||
| 2866 | if($.isArray(this.options.datasource)) { | ||
| 2867 | this._onDataUpdate(this.options.datasource); | ||
| 2868 | } | ||
| 2869 | else if($.type(this.options.datasource) === 'function') { | ||
| 2870 | if(this.options.lazy) | ||
| 2871 | this.options.datasource.call(this, this._onDataUpdate, {first:0, rows: this._getRows(), sortField:this.options.sortField, sortorder:this.options.sortOrder, filters: this._createFilterMap()}); | ||
| 2872 | else | ||
| 2873 | this.options.datasource.call(this, this._onDataUpdate); | ||
| 2874 | } | ||
| 2875 | }, | ||
| 2876 | |||
| 2877 | _setOption: function(key, value) { | ||
| 2878 | if(key === 'datasource') { | ||
| 2879 | this._updateDatasource(value); | ||
| 2880 | } | ||
| 2881 | else { | ||
| 2882 | $.Widget.prototype._setOption.apply(this, arguments); | ||
| 2883 | } | ||
| 2884 | }, | ||
| 2885 | |||
| 2886 | _initScrolling: function() { | ||
| 2887 | this.scrollHeader = this.element.children('.ui-datatable-scrollable-header'); | ||
| 2888 | this.scrollBody = this.element.children('.ui-datatable-scrollable-body'); | ||
| 2889 | this.scrollHeaderBox = this.scrollHeader.children('.ui-datatable-scrollable-header-box'); | ||
| 2890 | this.headerTable = this.scrollHeaderBox.children('table'); | ||
| 2891 | this.bodyTable = this.scrollBody.children('table'); | ||
| 2892 | this.percentageScrollHeight = this.options.scrollHeight && (this.options.scrollHeight.indexOf('%') !== -1); | ||
| 2893 | this.percentageScrollWidth = this.options.scrollWidth && (this.options.scrollWidth.indexOf('%') !== -1); | ||
| 2894 | var $this = this, | ||
| 2895 | scrollBarWidth = this.getScrollbarWidth() + 'px'; | ||
| 2896 | |||
| 2897 | if(this.options.scrollHeight) { | ||
| 2898 | if(this.percentageScrollHeight) | ||
| 2899 | this.adjustScrollHeight(); | ||
| 2900 | else | ||
| 2901 | this.scrollBody.css('max-height', this.options.scrollHeight + 'px'); | ||
| 2902 | |||
| 2903 | if(this.hasVerticalOverflow()) { | ||
| 2904 | this.scrollHeaderBox.css('margin-right', scrollBarWidth); | ||
| 2905 | } | ||
| 2906 | } | ||
| 2907 | |||
| 2908 | this.fixColumnWidths(); | ||
| 2909 | |||
| 2910 | if(this.options.scrollWidth) { | ||
| 2911 | if(this.percentageScrollWidth) | ||
| 2912 | this.adjustScrollWidth(); | ||
| 2913 | else | ||
| 2914 | this.setScrollWidth(parseInt(this.options.scrollWidth)); | ||
| 2915 | } | ||
| 2916 | |||
| 2917 | this.cloneHead(); | ||
| 2918 | |||
| 2919 | this.scrollBody.on('scroll.dataTable', function() { | ||
| 2920 | var scrollLeft = $this.scrollBody.scrollLeft(); | ||
| 2921 | $this.scrollHeaderBox.css('margin-left', -scrollLeft); | ||
| 2922 | }); | ||
| 2923 | |||
| 2924 | this.scrollHeader.on('scroll.dataTable', function() { | ||
| 2925 | $this.scrollHeader.scrollLeft(0); | ||
| 2926 | }); | ||
| 2927 | |||
| 2928 | var resizeNS = 'resize.' + this.id; | ||
| 2929 | $(window).off(resizeNS).on(resizeNS, function() { | ||
| 2930 | if($this.element.is(':visible')) { | ||
| 2931 | if($this.percentageScrollHeight) | ||
| 2932 | $this.adjustScrollHeight(); | ||
| 2933 | |||
| 2934 | if($this.percentageScrollWidth) | ||
| 2935 | $this.adjustScrollWidth(); | ||
| 2936 | } | ||
| 2937 | }); | ||
| 2938 | }, | ||
| 2939 | |||
| 2940 | cloneHead: function() { | ||
| 2941 | this.theadClone = this.thead.clone(); | ||
| 2942 | this.theadClone.find('th').each(function() { | ||
| 2943 | var header = $(this); | ||
| 2944 | header.attr('id', header.attr('id') + '_clone'); | ||
| 2945 | $(this).children().not('.ui-column-title').remove(); | ||
| 2946 | }); | ||
| 2947 | this.theadClone.removeAttr('id').addClass('ui-datatable-scrollable-theadclone').height(0).prependTo(this.bodyTable); | ||
| 2948 | |||
| 2949 | //align horizontal scroller on keyboard tab | ||
| 2950 | if(this.options.scrollWidth) { | ||
| 2951 | var clonedSortableColumns = this.theadClone.find('> tr > th.ui-sortable-column'); | ||
| 2952 | clonedSortableColumns.each(function() { | ||
| 2953 | $(this).data('original', $(this).attr('id').split('_clone')[0]); | ||
| 2954 | }); | ||
| 2955 | |||
| 2956 | clonedSortableColumns.on('blur.dataTable', function() { | ||
| 2957 | $(PUI.escapeClientId($(this).data('original'))).removeClass('ui-state-focus'); | ||
| 2958 | }) | ||
| 2959 | .on('focus.dataTable', function() { | ||
| 2960 | $(PUI.escapeClientId($(this).data('original'))).addClass('ui-state-focus'); | ||
| 2961 | }) | ||
| 2962 | .on('keydown.dataTable', function(e) { | ||
| 2963 | var key = e.which, | ||
| 2964 | keyCode = $.ui.keyCode; | ||
| 2965 | |||
| 2966 | if((key === keyCode.ENTER||key === keyCode.NUMPAD_ENTER) && $(e.target).is(':not(:input)')) { | ||
| 2967 | $(PUI.escapeClientId($(this).data('original'))).trigger('click.dataTable', (e.metaKey||e.ctrlKey)); | ||
| 2968 | e.preventDefault(); | ||
| 2969 | } | ||
| 2970 | }); | ||
| 2971 | } | ||
| 2972 | }, | ||
| 2973 | |||
| 2974 | adjustScrollHeight: function() { | ||
| 2975 | var relativeHeight = this.element.parent().innerHeight() * (parseInt(this.options.scrollHeight) / 100), | ||
| 2976 | tableHeaderHeight = this.element.children('.ui-datatable-header').outerHeight(true), | ||
| 2977 | tableFooterHeight = this.element.children('.ui-datatable-footer').outerHeight(true), | ||
| 2978 | scrollersHeight = (this.scrollHeader.outerHeight(true) + this.scrollFooter.outerHeight(true)), | ||
| 2979 | paginatorsHeight = this.paginator ? this.paginator.getContainerHeight(true) : 0, | ||
| 2980 | height = (relativeHeight - (scrollersHeight + paginatorsHeight + tableHeaderHeight + tableFooterHeight)); | ||
| 2981 | |||
| 2982 | this.scrollBody.css('max-height', height + 'px'); | ||
| 2983 | }, | ||
| 2984 | |||
| 2985 | adjustScrollWidth: function() { | ||
| 2986 | var width = parseInt((this.element.parent().innerWidth() * (parseInt(this.options.scrollWidth) / 100))); | ||
| 2987 | this.setScrollWidth(width); | ||
| 2988 | }, | ||
| 2989 | |||
| 2990 | setOuterWidth: function(element, width) { | ||
| 2991 | var diff = element.outerWidth() - element.width(); | ||
| 2992 | element.width(width - diff); | ||
| 2993 | }, | ||
| 2994 | |||
| 2995 | setScrollWidth: function(width) { | ||
| 2996 | var $this = this; | ||
| 2997 | this.element.children('.ui-widget-header').each(function() { | ||
| 2998 | $this.setOuterWidth($(this), width); | ||
| 2999 | }); | ||
| 3000 | this.scrollHeader.width(width); | ||
| 3001 | this.scrollBody.css('margin-right', 0).width(width); | ||
| 3002 | }, | ||
| 3003 | |||
| 3004 | alignScrollBody: function() { | ||
| 3005 | var marginRight = this.hasVerticalOverflow() ? this.getScrollbarWidth() + 'px' : '0px'; | ||
| 3006 | |||
| 3007 | this.scrollHeaderBox.css('margin-right', marginRight); | ||
| 3008 | }, | ||
| 3009 | |||
| 3010 | getScrollbarWidth: function() { | ||
| 3011 | if(!this.scrollbarWidth) { | ||
| 3012 | this.scrollbarWidth = PUI.browser.webkit ? '15' : PUI.calculateScrollbarWidth(); | ||
| 3013 | } | ||
| 3014 | |||
| 3015 | return this.scrollbarWidth; | ||
| 3016 | }, | ||
| 3017 | |||
| 3018 | hasVerticalOverflow: function() { | ||
| 3019 | return (this.options.scrollHeight && this.bodyTable.outerHeight() > this.scrollBody.outerHeight()) | ||
| 3020 | }, | ||
| 3021 | |||
| 3022 | restoreScrollState: function() { | ||
| 3023 | var scrollState = this.scrollStateHolder.val(), | ||
| 3024 | scrollValues = scrollState.split(','); | ||
| 3025 | |||
| 3026 | this.scrollBody.scrollLeft(scrollValues[0]); | ||
| 3027 | this.scrollBody.scrollTop(scrollValues[1]); | ||
| 3028 | }, | ||
| 3029 | |||
| 3030 | saveScrollState: function() { | ||
| 3031 | var scrollState = this.scrollBody.scrollLeft() + ',' + this.scrollBody.scrollTop(); | ||
| 3032 | |||
| 3033 | this.scrollStateHolder.val(scrollState); | ||
| 3034 | }, | ||
| 3035 | |||
| 3036 | clearScrollState: function() { | ||
| 3037 | this.scrollStateHolder.val('0,0'); | ||
| 3038 | }, | ||
| 3039 | |||
| 3040 | fixColumnWidths: function() { | ||
| 3041 | if(!this.columnWidthsFixed) { | ||
| 3042 | if(this.options.scrollable) { | ||
| 3043 | this.scrollHeaderBox.find('> table > thead > tr > th').each(function() { | ||
| 3044 | var headerCol = $(this), | ||
| 3045 | width = headerCol.width(); | ||
| 3046 | headerCol.width(width); | ||
| 3047 | }); | ||
| 3048 | } | ||
| 3049 | else { | ||
| 3050 | this.element.find('> .ui-datatable-tablewrapper > table > thead > tr > th').each(function() { | ||
| 3051 | var col = $(this); | ||
| 3052 | col.width(col.width()); | ||
| 3053 | }); | ||
| 3054 | } | ||
| 3055 | |||
| 3056 | this.columnWidthsFixed = true; | ||
| 3057 | } | ||
| 3058 | }, | ||
| 3059 | |||
| 3060 | _initDraggableColumns: function() { | ||
| 3061 | var $this = this; | ||
| 3062 | |||
| 3063 | this.dragIndicatorTop = $('<span class="fa fa-arrow-down" style="position:absolute"/></span>').hide().appendTo(this.element); | ||
| 3064 | this.dragIndicatorBottom = $('<span class="fa fa-arrow-up" style="position:absolute"/></span>').hide().appendTo(this.element); | ||
| 3065 | |||
| 3066 | this.thead.find('> tr > th').draggable({ | ||
| 3067 | appendTo: 'body', | ||
| 3068 | opacity: 0.75, | ||
| 3069 | cursor: 'move', | ||
| 3070 | scope: this.id, | ||
| 3071 | cancel: ':input,.ui-column-resizer', | ||
| 3072 | drag: function(event, ui) { | ||
| 3073 | var droppable = ui.helper.data('droppable-column'); | ||
| 3074 | |||
| 3075 | if(droppable) { | ||
| 3076 | var droppableOffset = droppable.offset(), | ||
| 3077 | topArrowY = droppableOffset.top - 10, | ||
| 3078 | bottomArrowY = droppableOffset.top + droppable.height() + 8, | ||
| 3079 | arrowX = null; | ||
| 3080 | |||
| 3081 | //calculate coordinates of arrow depending on mouse location | ||
| 3082 | if(event.originalEvent.pageX >= droppableOffset.left + (droppable.width() / 2)) { | ||
| 3083 | var nextDroppable = droppable.next(); | ||
| 3084 | if(nextDroppable.length == 1) | ||
| 3085 | arrowX = nextDroppable.offset().left - 9; | ||
| 3086 | else | ||
| 3087 | arrowX = droppable.offset().left + droppable.innerWidth() - 9; | ||
| 3088 | |||
| 3089 | ui.helper.data('drop-location', 1); //right | ||
| 3090 | } | ||
| 3091 | else { | ||
| 3092 | arrowX = droppableOffset.left - 9; | ||
| 3093 | ui.helper.data('drop-location', -1); //left | ||
| 3094 | } | ||
| 3095 | |||
| 3096 | $this.dragIndicatorTop.offset({ | ||
| 3097 | 'left': arrowX, | ||
| 3098 | 'top': topArrowY - 3 | ||
| 3099 | }).show(); | ||
| 3100 | |||
| 3101 | $this.dragIndicatorBottom.offset({ | ||
| 3102 | 'left': arrowX, | ||
| 3103 | 'top': bottomArrowY - 3 | ||
| 3104 | }).show(); | ||
| 3105 | } | ||
| 3106 | }, | ||
| 3107 | stop: function(event, ui) { | ||
| 3108 | //hide dnd arrows | ||
| 3109 | $this.dragIndicatorTop.css({ | ||
| 3110 | 'left':0, | ||
| 3111 | 'top':0 | ||
| 3112 | }).hide(); | ||
| 3113 | |||
| 3114 | $this.dragIndicatorBottom.css({ | ||
| 3115 | 'left':0, | ||
| 3116 | 'top':0 | ||
| 3117 | }).hide(); | ||
| 3118 | }, | ||
| 3119 | helper: function() { | ||
| 3120 | var header = $(this), | ||
| 3121 | helper = $('<div class="ui-widget ui-state-default" style="padding:4px 10px;text-align:center;"></div>'); | ||
| 3122 | |||
| 3123 | helper.width(header.width()); | ||
| 3124 | helper.height(header.height()); | ||
| 3125 | |||
| 3126 | helper.html(header.html()); | ||
| 3127 | |||
| 3128 | return helper.get(0); | ||
| 3129 | } | ||
| 3130 | }).droppable({ | ||
| 3131 | hoverClass:'ui-state-highlight', | ||
| 3132 | tolerance:'pointer', | ||
| 3133 | scope: this.id, | ||
| 3134 | over: function(event, ui) { | ||
| 3135 | ui.helper.data('droppable-column', $(this)); | ||
| 3136 | }, | ||
| 3137 | drop: function(event, ui) { | ||
| 3138 | var draggedColumnHeader = ui.draggable, | ||
| 3139 | dropLocation = ui.helper.data('drop-location'), | ||
| 3140 | droppedColumnHeader = $(this), | ||
| 3141 | draggedColumnFooter = null, | ||
| 3142 | droppedColumnFooter = null; | ||
| 3143 | |||
| 3144 | var draggedCells = $this.tbody.find('> tr:not(.ui-expanded-row-content) > td:nth-child(' + (draggedColumnHeader.index() + 1) + ')'), | ||
| 3145 | droppedCells = $this.tbody.find('> tr:not(.ui-expanded-row-content) > td:nth-child(' + (droppedColumnHeader.index() + 1) + ')'); | ||
| 3146 | |||
| 3147 | if($this.containsFooter()) { | ||
| 3148 | var footerColumns = $this.tfoot.find('> tr > td'), | ||
| 3149 | draggedColumnFooter = footerColumns.eq(draggedColumnHeader.index()), | ||
| 3150 | droppedColumnFooter = footerColumns.eq(droppedColumnHeader.index()); | ||
| 3151 | } | ||
| 3152 | |||
| 3153 | //drop right | ||
| 3154 | if(dropLocation > 0) { | ||
| 3155 | /* TODO :Resizable columns | ||
| 3156 | * if($this.options.resizableColumns) { | ||
| 3157 | if(droppedColumnHeader.next().length) { | ||
| 3158 | droppedColumnHeader.children('span.ui-column-resizer').show(); | ||
| 3159 | draggedColumnHeader.children('span.ui-column-resizer').hide(); | ||
| 3160 | } | ||
| 3161 | }*/ | ||
| 3162 | |||
| 3163 | draggedColumnHeader.insertAfter(droppedColumnHeader); | ||
| 3164 | |||
| 3165 | draggedCells.each(function(i, item) { | ||
| 3166 | $(this).insertAfter(droppedCells.eq(i)); | ||
| 3167 | }); | ||
| 3168 | |||
| 3169 | if(draggedColumnFooter && droppedColumnFooter) { | ||
| 3170 | draggedColumnFooter.insertAfter(droppedColumnFooter); | ||
| 3171 | } | ||
| 3172 | |||
| 3173 | //sync clone | ||
| 3174 | if($this.options.scrollable) { | ||
| 3175 | var draggedColumnClone = $(document.getElementById(draggedColumnHeader.attr('id') + '_clone')), | ||
| 3176 | droppedColumnClone = $(document.getElementById(droppedColumnHeader.attr('id') + '_clone')); | ||
| 3177 | draggedColumnClone.insertAfter(droppedColumnClone); | ||
| 3178 | } | ||
| 3179 | } | ||
| 3180 | //drop left | ||
| 3181 | else { | ||
| 3182 | draggedColumnHeader.insertBefore(droppedColumnHeader); | ||
| 3183 | |||
| 3184 | draggedCells.each(function(i, item) { | ||
| 3185 | $(this).insertBefore(droppedCells.eq(i)); | ||
| 3186 | }); | ||
| 3187 | |||
| 3188 | if(draggedColumnFooter && droppedColumnFooter) { | ||
| 3189 | draggedColumnFooter.insertBefore(droppedColumnFooter); | ||
| 3190 | } | ||
| 3191 | |||
| 3192 | //sync clone | ||
| 3193 | if($this.options.scrollable) { | ||
| 3194 | var draggedColumnClone = $(document.getElementById(draggedColumnHeader.attr('id') + '_clone')), | ||
| 3195 | droppedColumnClone = $(document.getElementById(droppedColumnHeader.attr('id') + '_clone')); | ||
| 3196 | draggedColumnClone.insertBefore(droppedColumnClone); | ||
| 3197 | } | ||
| 3198 | } | ||
| 3199 | |||
| 3200 | //fire colReorder event | ||
| 3201 | $this._trigger('colReorder', null, { | ||
| 3202 | dragIndex: draggedColumnHeader.index(), | ||
| 3203 | dropIndex: droppedColumnHeader.index() | ||
| 3204 | }); | ||
| 3205 | } | ||
| 3206 | }); | ||
| 3207 | }, | ||
| 3208 | |||
| 3209 | containsFooter: function() { | ||
| 3210 | if(this.hasFooter === undefined) { | ||
| 3211 | this.hasFooter = this.options.footerRows !== undefined; | ||
| 3212 | if(!this.hasFooter) { | ||
| 3213 | if(this.options.columns) { | ||
| 3214 | for(var i = 0; i < this.options.columns.length; i++) { | ||
| 3215 | if(this.options.columns[i].footerText !== undefined) { | ||
| 3216 | this.hasFooter = true; | ||
| 3217 | break; | ||
| 3218 | } | ||
| 3219 | } | ||
| 3220 | } | ||
| 3221 | } | ||
| 3222 | } | ||
| 3223 | |||
| 3224 | return this.hasFooter; | ||
| 3225 | }, | ||
| 3226 | |||
| 3227 | _initResizableColumns: function() { | ||
| 3228 | this.element.addClass('ui-datatable-resizable'); | ||
| 3229 | this.thead.find('> tr > th').addClass('ui-resizable-column'); | ||
| 3230 | this.resizerHelper = $('<div class="ui-column-resizer-helper ui-state-highlight"></div>').appendTo(this.element); | ||
| 3231 | this.addResizers(); | ||
| 3232 | var resizers = this.thead.find('> tr > th > span.ui-column-resizer'), | ||
| 3233 | $this = this; | ||
| 3234 | |||
| 3235 | setTimeout(function() { | ||
| 3236 | $this.fixColumnWidths(); | ||
| 3237 | }, 5); | ||
| 3238 | |||
| 3239 | resizers.draggable({ | ||
| 3240 | axis: 'x', | ||
| 3241 | start: function(event, ui) { | ||
| 3242 | ui.helper.data('originalposition', ui.helper.offset()); | ||
| 3243 | |||
| 3244 | var height = $this.options.scrollable ? $this.scrollBody.height() : $this.thead.parent().height() - $this.thead.height() - 1; | ||
| 3245 | $this.resizerHelper.height(height); | ||
| 3246 | $this.resizerHelper.show(); | ||
| 3247 | }, | ||
| 3248 | drag: function(event, ui) { | ||
| 3249 | $this.resizerHelper.offset({ | ||
| 3250 | left: ui.helper.offset().left + ui.helper.width() / 2, | ||
| 3251 | top: $this.thead.offset().top + $this.thead.height() | ||
| 3252 | }); | ||
| 3253 | }, | ||
| 3254 | stop: function(event, ui) { | ||
| 3255 | ui.helper.css({ | ||
| 3256 | 'left': '', | ||
| 3257 | 'top': '0px', | ||
| 3258 | 'right': '0px' | ||
| 3259 | }); | ||
| 3260 | |||
| 3261 | $this.resize(event, ui); | ||
| 3262 | $this.resizerHelper.hide(); | ||
| 3263 | |||
| 3264 | if($this.options.columnResizeMode === 'expand') { | ||
| 3265 | setTimeout(function() { | ||
| 3266 | $this._trigger('colResize', null, {element: ui.helper.parent()}); | ||
| 3267 | }, 5); | ||
| 3268 | } | ||
| 3269 | else { | ||
| 3270 | $this._trigger('colResize', null, {element: ui.helper.parent()}); | ||
| 3271 | } | ||
| 3272 | |||
| 3273 | if($this.options.stickyHeader) { | ||
| 3274 | $this.thead.find('.ui-column-filter').prop('disabled', false); | ||
| 3275 | $this.clone = $this.thead.clone(true); | ||
| 3276 | $this.cloneContainer.find('thead').remove(); | ||
| 3277 | $this.cloneContainer.children('table').append($this.clone); | ||
| 3278 | $this.thead.find('.ui-column-filter').prop('disabled', true); | ||
| 3279 | } | ||
| 3280 | }, | ||
| 3281 | containment: this.element | ||
| 3282 | }); | ||
| 3283 | }, | ||
| 3284 | |||
| 3285 | resize: function(event, ui) { | ||
| 3286 | var columnHeader, nextColumnHeader, change = null, newWidth = null, nextColumnWidth = null, | ||
| 3287 | expandMode = (this.options.columnResizeMode === 'expand'), | ||
| 3288 | table = this.thead.parent(), | ||
| 3289 | columnHeader = ui.helper.parent(), | ||
| 3290 | nextColumnHeader = columnHeader.next(); | ||
| 3291 | |||
| 3292 | change = (ui.position.left - ui.originalPosition.left), | ||
| 3293 | newWidth = (columnHeader.width() + change), | ||
| 3294 | nextColumnWidth = (nextColumnHeader.width() - change); | ||
| 3295 | |||
| 3296 | if((newWidth > 15 && nextColumnWidth > 15) || (expandMode && newWidth > 15)) { | ||
| 3297 | if(expandMode) { | ||
| 3298 | table.width(table.width() + change); | ||
| 3299 | setTimeout(function() { | ||
| 3300 | columnHeader.width(newWidth); | ||
| 3301 | }, 1); | ||
| 3302 | } | ||
| 3303 | else { | ||
| 3304 | columnHeader.width(newWidth); | ||
| 3305 | nextColumnHeader.width(nextColumnWidth); | ||
| 3306 | } | ||
| 3307 | |||
| 3308 | if(this.options.scrollable) { | ||
| 3309 | var cloneTable = this.theadClone.parent(), | ||
| 3310 | colIndex = columnHeader.index(); | ||
| 3311 | |||
| 3312 | if(expandMode) { | ||
| 3313 | var $this = this; | ||
| 3314 | |||
| 3315 | //body | ||
| 3316 | cloneTable.width(cloneTable.width() + change); | ||
| 3317 | |||
| 3318 | //footer | ||
| 3319 | this.footerTable.width(this.footerTable.width() + change); | ||
| 3320 | |||
| 3321 | setTimeout(function() { | ||
| 3322 | if($this.hasColumnGroup) { | ||
| 3323 | $this.theadClone.find('> tr:first').children('th').eq(colIndex).width(newWidth); //body | ||
| 3324 | $this.footerTable.find('> tfoot > tr:first').children('th').eq(colIndex).width(newWidth); //footer | ||
| 3325 | } | ||
| 3326 | else { | ||
| 3327 | $this.theadClone.find(PUI.escapeClientId(columnHeader.attr('id') + '_clone')).width(newWidth); //body | ||
| 3328 | $this.footerCols.eq(colIndex).width(newWidth); //footer | ||
| 3329 | } | ||
| 3330 | }, 1); | ||
| 3331 | } | ||
| 3332 | else { | ||
| 3333 | //body | ||
| 3334 | this.theadClone.find(PUI.escapeClientId(columnHeader.attr('id') + '_clone')).width(newWidth); | ||
| 3335 | this.theadClone.find(PUI.escapeClientId(nextColumnHeader.attr('id') + '_clone')).width(nextColumnWidth); | ||
| 3336 | |||
| 3337 | //footer | ||
| 3338 | /*if(this.footerCols.length > 0) { | ||
| 3339 | var footerCol = this.footerCols.eq(colIndex), | ||
| 3340 | nextFooterCol = footerCol.next(); | ||
| 3341 | |||
| 3342 | footerCol.width(newWidth); | ||
| 3343 | nextFooterCol.width(nextColumnWidth); | ||
| 3344 | }*/ | ||
| 3345 | } | ||
| 3346 | } | ||
| 3347 | } | ||
| 3348 | }, | ||
| 3349 | |||
| 3350 | addResizers: function() { | ||
| 3351 | var resizableColumns = this.thead.find('> tr > th.ui-resizable-column'); | ||
| 3352 | resizableColumns.prepend('<span class="ui-column-resizer"> </span>'); | ||
| 3353 | |||
| 3354 | if(this.options.columnResizeMode === 'fit') { | ||
| 3355 | resizableColumns.filter(':last-child').children('span.ui-column-resizer').hide(); | ||
| 3356 | } | ||
| 3357 | }, | ||
| 3358 | |||
| 3359 | _initDraggableRows: function() { | ||
| 3360 | var $this = this; | ||
| 3361 | |||
| 3362 | this.tbody.sortable({ | ||
| 3363 | placeholder: 'ui-datatable-rowordering ui-state-active', | ||
| 3364 | cursor: 'move', | ||
| 3365 | handle: 'td,span:not(.ui-c)', | ||
| 3366 | appendTo: document.body, | ||
| 3367 | helper: function(event, ui) { | ||
| 3368 | var cells = ui.children(), | ||
| 3369 | helper = $('<div class="ui-datatable ui-widget"><table><tbody></tbody></table></div>'), | ||
| 3370 | helperRow = ui.clone(), | ||
| 3371 | helperCells = helperRow.children(); | ||
| 3372 | |||
| 3373 | for(var i = 0; i < helperCells.length; i++) { | ||
| 3374 | helperCells.eq(i).width(cells.eq(i).width()); | ||
| 3375 | } | ||
| 3376 | |||
| 3377 | helperRow.appendTo(helper.find('tbody')); | ||
| 3378 | |||
| 3379 | return helper; | ||
| 3380 | }, | ||
| 3381 | update: function(event, ui) { | ||
| 3382 | $this.syncRowParity(); | ||
| 3383 | |||
| 3384 | $this._trigger('rowReorder', null, { | ||
| 3385 | fromIndex: ui.item.data('ri'), | ||
| 3386 | toIndex: $this._getFirst() + ui.item.index() | ||
| 3387 | }); | ||
| 3388 | }, | ||
| 3389 | change: function(event, ui) { | ||
| 3390 | if($this.options.scrollable) { | ||
| 3391 | PUI.scrollInView($this.scrollBody, ui.placeholder); | ||
| 3392 | } | ||
| 3393 | } | ||
| 3394 | }); | ||
| 3395 | }, | ||
| 3396 | |||
| 3397 | syncRowParity: function() { | ||
| 3398 | var rows = this.tbody.children('tr.ui-widget-content'); | ||
| 3399 | |||
| 3400 | for(var i = this._getFirst(); i < rows.length; i++) { | ||
| 3401 | var row = rows.eq(i); | ||
| 3402 | |||
| 3403 | row.data('ri', i).removeClass('ui-datatable-even ui-datatable-odd'); | ||
| 3404 | |||
| 3405 | if(i % 2 === 0) | ||
| 3406 | row.addClass('ui-datatable-even'); | ||
| 3407 | else | ||
| 3408 | row.addClass('ui-datatable-odd'); | ||
| 3409 | |||
| 3410 | } | ||
| 3411 | }, | ||
| 3412 | |||
| 3413 | getContextMenuSelection: function(data) { | ||
| 3414 | return this.dataSelectedByContextMenu; | ||
| 3415 | }, | ||
| 3416 | |||
| 3417 | _initFiltering: function() { | ||
| 3418 | var $this = this; | ||
| 3419 | this.filterElements = this.thead.find('.ui-column-filter'); | ||
| 3420 | |||
| 3421 | this.filterElements.on('keyup', function() { | ||
| 3422 | if($this.filterTimeout) { | ||
| 3423 | clearTimeout($this.filterTimeout); | ||
| 3424 | } | ||
| 3425 | |||
| 3426 | $this.filterTimeout = setTimeout(function() { | ||
| 3427 | $this.filter(); | ||
| 3428 | $this.filterTimeout = null; | ||
| 3429 | }, | ||
| 3430 | $this.options.filterDelay); | ||
| 3431 | }); | ||
| 3432 | |||
| 3433 | if(this.options.globalFilter) { | ||
| 3434 | $(this.options.globalFilter).on('keyup.puidatatable', function() { | ||
| 3435 | $this.filter(); | ||
| 3436 | }); | ||
| 3437 | } | ||
| 3438 | }, | ||
| 3439 | |||
| 3440 | filter: function() { | ||
| 3441 | this.filterMetaMap = []; | ||
| 3442 | |||
| 3443 | for(var i = 0; i < this.filterElements.length; i++) { | ||
| 3444 | var filterElement = this.filterElements.eq(i), | ||
| 3445 | filterElementValue = filterElement.val(); | ||
| 3446 | |||
| 3447 | this.filterMetaMap.push({ | ||
| 3448 | field: filterElement.data('field'), | ||
| 3449 | filterMatchMode: filterElement.data('filtermatchmode'), | ||
| 3450 | value: filterElementValue.toLowerCase(), | ||
| 3451 | element: filterElement | ||
| 3452 | }); | ||
| 3453 | } | ||
| 3454 | |||
| 3455 | if(this.options.lazy) { | ||
| 3456 | this.options.datasource.call(this, this._onLazyLoad, this._createStateMeta()); | ||
| 3457 | } | ||
| 3458 | else { | ||
| 3459 | var globalFilterValue = $(this.options.globalFilter).val(); | ||
| 3460 | this.filteredData = []; | ||
| 3461 | |||
| 3462 | for(var i = 0; i < this.data.length; i++) { | ||
| 3463 | var localMatch = true; | ||
| 3464 | var globalMatch = false; | ||
| 3465 | |||
| 3466 | for(var j = 0; j < this.filterMetaMap.length; j++) { | ||
| 3467 | var filterMeta = this.filterMetaMap[j], | ||
| 3468 | filterValue = filterMeta.value, | ||
| 3469 | filterField = filterMeta.field, | ||
| 3470 | dataFieldValue = this.data[i][filterField]; | ||
| 3471 | |||
| 3472 | var filterConstraint = this.filterConstraints[filterMeta.filterMatchMode]; | ||
| 3473 | |||
| 3474 | //global | ||
| 3475 | if(this.options.globalFilter && !globalMatch) { | ||
| 3476 | var filterConstraint = this.filterConstraints['contains']; | ||
| 3477 | globalMatch = filterConstraint(dataFieldValue, globalFilterValue); | ||
| 3478 | |||
| 3479 | } | ||
| 3480 | |||
| 3481 | //local | ||
| 3482 | if(filterMeta.filterMatchMode === 'custom') { | ||
| 3483 | localMatch = filterMeta.element.triggerHandler('filter', [dataFieldValue, filterValue]); | ||
| 3484 | } | ||
| 3485 | else { | ||
| 3486 | var filterConstraint = this.filterConstraints[filterMeta.filterMatchMode]; | ||
| 3487 | if(!filterConstraint(dataFieldValue, filterValue)) { | ||
| 3488 | localMatch = false; | ||
| 3489 | } | ||
| 3490 | } | ||
| 3491 | |||
| 3492 | if(!localMatch) { | ||
| 3493 | break; | ||
| 3494 | } | ||
| 3495 | } | ||
| 3496 | |||
| 3497 | var matches = localMatch; | ||
| 3498 | |||
| 3499 | if(this.options.globalFilter) { | ||
| 3500 | matches = localMatch && globalMatch; | ||
| 3501 | } | ||
| 3502 | |||
| 3503 | if(matches) { | ||
| 3504 | this.filteredData.push(this.data[i]); | ||
| 3505 | } | ||
| 3506 | } | ||
| 3507 | |||
| 3508 | if(this.filteredData.length === this.data.length) { | ||
| 3509 | this.filteredData = null; | ||
| 3510 | } | ||
| 3511 | |||
| 3512 | if(this.paginator) { | ||
| 3513 | this.paginator.puipaginator('option', 'totalRecords', this.filteredData ? this.filteredData.length : this.data ? this.data.length : 0); | ||
| 3514 | } | ||
| 3515 | |||
| 3516 | this._renderData(); | ||
| 3517 | } | ||
| 3518 | }, | ||
| 3519 | |||
| 3520 | filterConstraints: { | ||
| 3521 | |||
| 3522 | startsWith: function(value, filter) { | ||
| 3523 | if(filter === undefined || filter === null || $.trim(filter) === '') { | ||
| 3524 | return true; | ||
| 3525 | } | ||
| 3526 | |||
| 3527 | if(value === undefined || value === null) { | ||
| 3528 | return false; | ||
| 3529 | } | ||
| 3530 | |||
| 3531 | return value.toString().toLowerCase().slice(0, filter.length) === filter; | ||
| 3532 | }, | ||
| 3533 | |||
| 3534 | contains: function(value, filter) { | ||
| 3535 | if(filter === undefined || filter === null || $.trim(filter) === '') { | ||
| 3536 | return true; | ||
| 3537 | } | ||
| 3538 | |||
| 3539 | if(value === undefined || value === null) { | ||
| 3540 | return false; | ||
| 3541 | } | ||
| 3542 | |||
| 3543 | return value.toString().toLowerCase().indexOf(filter) !== -1; | ||
| 3544 | } | ||
| 3545 | |||
| 3546 | }, | ||
| 3547 | |||
| 3548 | _initStickyHeader: function() { | ||
| 3549 | var table = this.thead.parent(), | ||
| 3550 | offset = table.offset(), | ||
| 3551 | win = $(window), | ||
| 3552 | $this = this, | ||
| 3553 | stickyNS = 'scroll.' + this.id, | ||
| 3554 | resizeNS = 'resize.sticky-' + this.id; | ||
| 3555 | |||
| 3556 | this.cloneContainer = $('<div class="ui-datatable ui-datatable-sticky ui-widget"><table></table></div>'); | ||
| 3557 | this.clone = this.thead.clone(true); | ||
| 3558 | this.cloneContainer.children('table').append(this.clone); | ||
| 3559 | |||
| 3560 | this.cloneContainer.css({ | ||
| 3561 | position: 'absolute', | ||
| 3562 | width: table.outerWidth(), | ||
| 3563 | top: offset.top, | ||
| 3564 | left: offset.left, | ||
| 3565 | 'z-index': ++PUI.zindex | ||
| 3566 | }) | ||
| 3567 | .appendTo(this.element); | ||
| 3568 | |||
| 3569 | win.off(stickyNS).on(stickyNS, function() { | ||
| 3570 | var scrollTop = win.scrollTop(), | ||
| 3571 | tableOffset = table.offset(); | ||
| 3572 | |||
| 3573 | if(scrollTop > tableOffset.top) { | ||
| 3574 | $this.cloneContainer.css({ | ||
| 3575 | 'position': 'fixed', | ||
| 3576 | 'top': '0px' | ||
| 3577 | }) | ||
| 3578 | .addClass('ui-shadow ui-sticky'); | ||
| 3579 | |||
| 3580 | if(scrollTop >= (tableOffset.top + $this.tbody.height())) | ||
| 3581 | $this.cloneContainer.hide(); | ||
| 3582 | else | ||
| 3583 | $this.cloneContainer.show(); | ||
| 3584 | } | ||
| 3585 | else { | ||
| 3586 | $this.cloneContainer.css({ | ||
| 3587 | 'position': 'absolute', | ||
| 3588 | 'top': tableOffset.top | ||
| 3589 | }) | ||
| 3590 | .removeClass('ui-shadow ui-sticky'); | ||
| 3591 | } | ||
| 3592 | }) | ||
| 3593 | .off(resizeNS).on(resizeNS, function() { | ||
| 3594 | $this.cloneContainer.width(table.outerWidth()); | ||
| 3595 | }); | ||
| 3596 | |||
| 3597 | //filter support | ||
| 3598 | this.thead.find('.ui-column-filter').prop('disabled', true); | ||
| 3599 | }, | ||
| 3600 | |||
| 3601 | _initEditing: function() { | ||
| 3602 | var cellSelector = '> tr > td.ui-editable-column', | ||
| 3603 | $this = this; | ||
| 3604 | |||
| 3605 | this.tbody.off('click', cellSelector) | ||
| 3606 | .on('click', cellSelector, null, function(e) { | ||
| 3607 | var cell = $(this); | ||
| 3608 | if(!cell.hasClass('ui-cell-editing')) { | ||
| 3609 | $this._showCellEditor(cell); | ||
| 3610 | e.stopPropagation(); | ||
| 3611 | } | ||
| 3612 | }); | ||
| 3613 | }, | ||
| 3614 | |||
| 3615 | _showCellEditor: function(cell) { | ||
| 3616 | var editor = this.editors[cell.data('editor')].call(), | ||
| 3617 | $this = this; | ||
| 3618 | |||
| 3619 | editor.val(cell.data('rowdata')[cell.data('field')]); | ||
| 3620 | |||
| 3621 | cell.addClass('ui-cell-editing').html('').append(editor); | ||
| 3622 | |||
| 3623 | editor.focus().on('change', function() { | ||
| 3624 | $this._onCellEditorChange(cell); | ||
| 3625 | }) | ||
| 3626 | .on('blur', function() { | ||
| 3627 | $this._onCellEditorBlur(cell); | ||
| 3628 | }) | ||
| 3629 | .on('keydown', function(e) { | ||
| 3630 | var key = e.which, | ||
| 3631 | keyCode = $.ui.keyCode; | ||
| 3632 | |||
| 3633 | if((key === keyCode.ENTER||key === keyCode.NUMPAD_ENTER)) { | ||
| 3634 | $(this).trigger('change').trigger('blur'); | ||
| 3635 | e.preventDefault(); | ||
| 3636 | } | ||
| 3637 | else if(key === keyCode.TAB) { | ||
| 3638 | if(e.shiftKey) { | ||
| 3639 | var prevCell = cell.prevAll('td.ui-editable-column').eq(0); | ||
| 3640 | if(!prevCell.length) { | ||
| 3641 | prevCell = cell.parent().prev('tr').children('td.ui-editable-column:last'); | ||
| 3642 | } | ||
| 3643 | if(prevCell.length) { | ||
| 3644 | $this._showCellEditor(prevCell); | ||
| 3645 | } | ||
| 3646 | } | ||
| 3647 | else { | ||
| 3648 | var nextCell = cell.nextAll('td.ui-editable-column').eq(0); | ||
| 3649 | if(!nextCell.length) { | ||
| 3650 | nextCell = cell.parent().next('tr').children('td.ui-editable-column').eq(0); | ||
| 3651 | } | ||
| 3652 | if(nextCell.length) { | ||
| 3653 | $this._showCellEditor(nextCell); | ||
| 3654 | } | ||
| 3655 | } | ||
| 3656 | |||
| 3657 | e.preventDefault(); | ||
| 3658 | } else if(key === keyCode.ESCAPE) { | ||
| 3659 | $this._onCellEditorBlur(cell); | ||
| 3660 | } | ||
| 3661 | |||
| 3662 | }); | ||
| 3663 | }, | ||
| 3664 | |||
| 3665 | _onCellEditorChange: function(cell) { | ||
| 3666 | var newCellValue = cell.children('.ui-cell-editor').val(); | ||
| 3667 | |||
| 3668 | var retVal = this._trigger('cellEdit', null, { | ||
| 3669 | oldValue: cell.data('rowdata')[cell.data('field')], | ||
| 3670 | newValue: newCellValue, | ||
| 3671 | data: cell.data('rowdata'), | ||
| 3672 | field: cell.data('field') | ||
| 3673 | }); | ||
| 3674 | |||
| 3675 | if(retVal !== false) { | ||
| 3676 | cell.data('rowdata')[cell.data('field')] = newCellValue; | ||
| 3677 | } | ||
| 3678 | }, | ||
| 3679 | |||
| 3680 | _onCellEditorBlur: function(cell) { | ||
| 3681 | cell.removeClass('ui-cell-editing').text(cell.data('rowdata')[cell.data('field')]) | ||
| 3682 | .children('.ui-cell-editor').remove(); | ||
| 3683 | }, | ||
| 3684 | |||
| 3685 | reload: function() { | ||
| 3686 | this._updateDatasource(this.options.datasource); | ||
| 3687 | }, | ||
| 3688 | |||
| 3689 | getPaginator: function() { | ||
| 3690 | return this.paginator; | ||
| 3691 | }, | ||
| 3692 | |||
| 3693 | setTotalRecords: function(val) { | ||
| 3694 | this.paginator.puipaginator('option','totalRecords', val); | ||
| 3695 | }, | ||
| 3696 | |||
| 3697 | _createFilterMap: function() { | ||
| 3698 | var filters = null; | ||
| 3699 | if(this.filterElements) { | ||
| 3700 | filters = {}; | ||
| 3701 | for(var i = 0; i < this.filterElements.length; i++) { | ||
| 3702 | var filterElement = this.filterElements.eq(i), | ||
| 3703 | value = filterElement.val(); | ||
| 3704 | if($.trim(value).length) { | ||
| 3705 | filters[filterElement.data('field')] = value; | ||
| 3706 | } | ||
| 3707 | } | ||
| 3708 | } | ||
| 3709 | |||
| 3710 | return filters; | ||
| 3711 | }, | ||
| 3712 | |||
| 3713 | editors: { | ||
| 3714 | |||
| 3715 | 'input': function() { | ||
| 3716 | return $('<input type="text" class="ui-cell-editor"/>'); | ||
| 3717 | } | ||
| 3718 | } | ||
| 3719 | |||
| 3720 | }); | ||
| 3721 | })(); | ||
| 3722 | |||
| 3723 | /** | ||
| 3724 | * PrimeUI Dialog Widget | ||
| 3725 | */ | ||
| 3726 | (function() { | ||
| 3727 | |||
| 3728 | $.widget("primeui.puidialog", { | ||
| 3729 | |||
| 3730 | options: { | ||
| 3731 | draggable: true, | ||
| 3732 | resizable: true, | ||
| 3733 | location: 'center', | ||
| 3734 | minWidth: 150, | ||
| 3735 | minHeight: 25, | ||
| 3736 | height: 'auto', | ||
| 3737 | width: '300px', | ||
| 3738 | visible: false, | ||
| 3739 | modal: false, | ||
| 3740 | showEffect: null, | ||
| 3741 | hideEffect: null, | ||
| 3742 | effectOptions: {}, | ||
| 3743 | effectSpeed: 'normal', | ||
| 3744 | closeOnEscape: true, | ||
| 3745 | rtl: false, | ||
| 3746 | closable: true, | ||
| 3747 | minimizable: false, | ||
| 3748 | maximizable: false, | ||
| 3749 | appendTo: null, | ||
| 3750 | buttons: null, | ||
| 3751 | responsive: false, | ||
| 3752 | title: null, | ||
| 3753 | enhanced: false | ||
| 3754 | }, | ||
| 3755 | |||
| 3756 | _create: function() { | ||
| 3757 | this.id = this.element.attr('id'); | ||
| 3758 | if(!this.id) { | ||
| 3759 | this.id = this.element.uniqueId().attr('id'); | ||
| 3760 | } | ||
| 3761 | |||
| 3762 | //container | ||
| 3763 | if(!this.options.enhanced) { | ||
| 3764 | this.element.addClass('ui-dialog ui-widget ui-widget-content ui-helper-hidden ui-corner-all ui-shadow') | ||
| 3765 | .contents().wrapAll('<div class="ui-dialog-content ui-widget-content" />'); | ||
| 3766 | |||
| 3767 | //header | ||
| 3768 | var title = this.options.title||this.element.attr('title'); | ||
| 3769 | this.element.prepend('<div class="ui-dialog-titlebar ui-widget-header ui-helper-clearfix ui-corner-top">' + | ||
| 3770 | '<span id="' + this.element.attr('id') + '_label" class="ui-dialog-title">' + title + '</span>') | ||
| 3771 | .removeAttr('title'); | ||
| 3772 | |||
| 3773 | //footer | ||
| 3774 | if(this.options.buttons) { | ||
| 3775 | this.footer = $('<div class="ui-dialog-buttonpane ui-widget-content ui-helper-clearfix"></div>').appendTo(this.element); | ||
| 3776 | for(var i = 0; i < this.options.buttons.length; i++) { | ||
| 3777 | var buttonMeta = this.options.buttons[i], | ||
| 3778 | button = $('<button type="button"></button>').appendTo(this.footer); | ||
| 3779 | if(buttonMeta.text) { | ||
| 3780 | button.text(buttonMeta.text); | ||
| 3781 | } | ||
| 3782 | |||
| 3783 | button.puibutton(buttonMeta); | ||
| 3784 | } | ||
| 3785 | } | ||
| 3786 | |||
| 3787 | if(this.options.rtl) { | ||
| 3788 | this.element.addClass('ui-dialog-rtl'); | ||
| 3789 | } | ||
| 3790 | } | ||
| 3791 | |||
| 3792 | //elements | ||
| 3793 | this.content = this.element.children('.ui-dialog-content'); | ||
| 3794 | this.titlebar = this.element.children('.ui-dialog-titlebar'); | ||
| 3795 | |||
| 3796 | if(!this.options.enhanced) { | ||
| 3797 | if(this.options.closable) { | ||
| 3798 | this._renderHeaderIcon('ui-dialog-titlebar-close', 'fa-close'); | ||
| 3799 | } | ||
| 3800 | |||
| 3801 | if(this.options.maximizable) { | ||
| 3802 | this._renderHeaderIcon('ui-dialog-titlebar-maximize', 'fa-sort'); | ||
| 3803 | } | ||
| 3804 | |||
| 3805 | if(this.options.minimizable) { | ||
| 3806 | this._renderHeaderIcon('ui-dialog-titlebar-minimize', 'fa-minus'); | ||
| 3807 | } | ||
| 3808 | } | ||
| 3809 | |||
| 3810 | //icons | ||
| 3811 | this.icons = this.titlebar.children('.ui-dialog-titlebar-icon'); | ||
| 3812 | this.closeIcon = this.titlebar.children('.ui-dialog-titlebar-close'); | ||
| 3813 | this.minimizeIcon = this.titlebar.children('.ui-dialog-titlebar-minimize'); | ||
| 3814 | this.maximizeIcon = this.titlebar.children('.ui-dialog-titlebar-maximize'); | ||
| 3815 | |||
| 3816 | this.blockEvents = 'focus.puidialog mousedown.puidialog mouseup.puidialog keydown.puidialog keyup.puidialog'; | ||
| 3817 | this.parent = this.element.parent(); | ||
| 3818 | |||
| 3819 | //size | ||
| 3820 | this.element.css({'width': this.options.width, 'height': 'auto'}); | ||
| 3821 | this.content.height(this.options.height); | ||
| 3822 | |||
| 3823 | //events | ||
| 3824 | this._bindEvents(); | ||
| 3825 | |||
| 3826 | if(this.options.draggable) { | ||
| 3827 | this._setupDraggable(); | ||
| 3828 | } | ||
| 3829 | |||
| 3830 | if(this.options.resizable) { | ||
| 3831 | this._setupResizable(); | ||
| 3832 | } | ||
| 3833 | |||
| 3834 | if(this.options.appendTo) { | ||
| 3835 | this.element.appendTo(this.options.appendTo); | ||
| 3836 | } | ||
| 3837 | |||
| 3838 | if(this.options.responsive) { | ||
| 3839 | this.resizeNS = 'resize.' + this.id; | ||
| 3840 | } | ||
| 3841 | |||
| 3842 | //docking zone | ||
| 3843 | if($(document.body).children('.ui-dialog-docking-zone').length === 0) { | ||
| 3844 | $(document.body).append('<div class="ui-dialog-docking-zone"></div>'); | ||
| 3845 | } | ||
| 3846 | |||
| 3847 | //aria | ||
| 3848 | this._applyARIA(); | ||
| 3849 | |||
| 3850 | if(this.options.visible) { | ||
| 3851 | this.show(); | ||
| 3852 | } | ||
| 3853 | }, | ||
| 3854 | |||
| 3855 | _destroy: function() { | ||
| 3856 | //restore dom | ||
| 3857 | if(!this.options.enhanced) { | ||
| 3858 | this.element.removeClass('ui-dialog ui-widget ui-widget-content ui-helper-hidden ui-corner-all ui-shadow'); | ||
| 3859 | |||
| 3860 | if(this.options.buttons) { | ||
| 3861 | this.footer.children('button').puibutton('destroy'); | ||
| 3862 | this.footer.remove(); | ||
| 3863 | } | ||
| 3864 | |||
| 3865 | if(this.options.rtl) { | ||
| 3866 | this.element.removeClass('ui-dialog-rtl'); | ||
| 3867 | } | ||
| 3868 | |||
| 3869 | var title = this.titlebar.children('.ui-dialog-title').text()||this.options.title; | ||
| 3870 | if(title) { | ||
| 3871 | this.element.attr('title', title); | ||
| 3872 | } | ||
| 3873 | this.titlebar.remove(); | ||
| 3874 | |||
| 3875 | this.content.contents().unwrap(); | ||
| 3876 | } | ||
| 3877 | |||
| 3878 | //remove events | ||
| 3879 | this._unbindEvents(); | ||
| 3880 | |||
| 3881 | if(this.options.draggable) { | ||
| 3882 | this.element.draggable('destroy'); | ||
| 3883 | } | ||
| 3884 | |||
| 3885 | if(this.options.resizable) { | ||
| 3886 | this.element.resizable('destroy'); | ||
| 3887 | } | ||
| 3888 | |||
| 3889 | if(this.options.appendTo) { | ||
| 3890 | this.element.appendTo(this.parent); | ||
| 3891 | } | ||
| 3892 | |||
| 3893 | this._unbindResizeListener(); | ||
| 3894 | |||
| 3895 | if(this.options.modal) { | ||
| 3896 | this._disableModality(); | ||
| 3897 | } | ||
| 3898 | |||
| 3899 | this._removeARIA(); | ||
| 3900 | this.element.css({ | ||
| 3901 | 'width': 'auto', | ||
| 3902 | 'height': 'auto' | ||
| 3903 | }); | ||
| 3904 | }, | ||
| 3905 | |||
| 3906 | _renderHeaderIcon: function(styleClass, icon) { | ||
| 3907 | this.titlebar.append('<a class="ui-dialog-titlebar-icon ' + styleClass + ' ui-corner-all" href="#" role="button">' + | ||
| 3908 | '<span class="fa fa-fw ' + icon + '"></span></a>'); | ||
| 3909 | }, | ||
| 3910 | |||
| 3911 | _enableModality: function() { | ||
| 3912 | var $this = this, | ||
| 3913 | doc = $(document); | ||
| 3914 | |||
| 3915 | this.modality = $('<div id="' + this.element.attr('id') + '_modal" class="ui-widget-overlay ui-dialog-mask"></div>').appendTo(document.body) | ||
| 3916 | .css('z-index', this.element.css('z-index') - 1); | ||
| 3917 | |||
| 3918 | //Disable tabbing out of modal dialog and stop events from targets outside of dialog | ||
| 3919 | doc.on('keydown.puidialog', | ||
| 3920 | function(event) { | ||
| 3921 | if(event.keyCode == $.ui.keyCode.TAB) { | ||
| 3922 | var tabbables = $this.content.find(':tabbable'), | ||
| 3923 | first = tabbables.filter(':first'), | ||
| 3924 | last = tabbables.filter(':last'); | ||
| 3925 | |||
| 3926 | if(event.target === last[0] && !event.shiftKey) { | ||
| 3927 | first.focus(1); | ||
| 3928 | return false; | ||
| 3929 | } | ||
| 3930 | else if (event.target === first[0] && event.shiftKey) { | ||
| 3931 | last.focus(1); | ||
| 3932 | return false; | ||
| 3933 | } | ||
| 3934 | } | ||
| 3935 | }) | ||
| 3936 | .bind(this.blockEvents, function(event) { | ||
| 3937 | if ($(event.target).zIndex() < $this.element.zIndex()) { | ||
| 3938 | return false; | ||
| 3939 | } | ||
| 3940 | }); | ||
| 3941 | }, | ||
| 3942 | |||
| 3943 | _disableModality: function() { | ||
| 3944 | if(this.modality) { | ||
| 3945 | this.modality.remove(); | ||
| 3946 | this.modality = null; | ||
| 3947 | } | ||
| 3948 | |||
| 3949 | $(document).off(this.blockEvents).off('keydown.dialog'); | ||
| 3950 | }, | ||
| 3951 | |||
| 3952 | show: function() { | ||
| 3953 | if(this.element.is(':visible')) { | ||
| 3954 | return; | ||
| 3955 | } | ||
| 3956 | |||
| 3957 | if(!this.positionInitialized) { | ||
| 3958 | this._initPosition(); | ||
| 3959 | } | ||
| 3960 | |||
| 3961 | this._trigger('beforeShow', null); | ||
| 3962 | |||
| 3963 | if(this.options.showEffect) { | ||
| 3964 | var $this = this; | ||
| 3965 | |||
| 3966 | this.element.show(this.options.showEffect, this.options.effectOptions, this.options.effectSpeed, function() { | ||
| 3967 | $this._postShow(); | ||
| 3968 | }); | ||
| 3969 | } | ||
| 3970 | else { | ||
| 3971 | this.element.show(); | ||
| 3972 | |||
| 3973 | this._postShow(); | ||
| 3974 | } | ||
| 3975 | |||
| 3976 | this._moveToTop(); | ||
| 3977 | |||
| 3978 | if(this.options.modal) { | ||
| 3979 | this._enableModality(); | ||
| 3980 | } | ||
| 3981 | }, | ||
| 3982 | |||
| 3983 | _postShow: function() { | ||
| 3984 | //execute user defined callback | ||
| 3985 | this._trigger('afterShow', null); | ||
| 3986 | |||
| 3987 | this.element.attr({ | ||
| 3988 | 'aria-hidden': false, | ||
| 3989 | 'aria-live': 'polite' | ||
| 3990 | }); | ||
| 3991 | |||
| 3992 | this._applyFocus(); | ||
| 3993 | |||
| 3994 | if(this.options.responsive) { | ||
| 3995 | this._bindResizeListener(); | ||
| 3996 | } | ||
| 3997 | }, | ||
| 3998 | |||
| 3999 | hide: function() { | ||
| 4000 | if(this.element.is(':hidden')) { | ||
| 4001 | return; | ||
| 4002 | } | ||
| 4003 | |||
| 4004 | this._trigger('beforeHide', null); | ||
| 4005 | |||
| 4006 | if(this.options.hideEffect) { | ||
| 4007 | var _self = this; | ||
| 4008 | |||
| 4009 | this.element.hide(this.options.hideEffect, this.options.effectOptions, this.options.effectSpeed, function() { | ||
| 4010 | _self._postHide(); | ||
| 4011 | }); | ||
| 4012 | } | ||
| 4013 | else { | ||
| 4014 | this.element.hide(); | ||
| 4015 | |||
| 4016 | this._postHide(); | ||
| 4017 | } | ||
| 4018 | |||
| 4019 | if(this.options.modal) { | ||
| 4020 | this._disableModality(); | ||
| 4021 | } | ||
| 4022 | }, | ||
| 4023 | |||
| 4024 | _postHide: function() { | ||
| 4025 | //execute user defined callback | ||
| 4026 | this._trigger('afterHide', null); | ||
| 4027 | |||
| 4028 | this.element.attr({ | ||
| 4029 | 'aria-hidden': true, | ||
| 4030 | 'aria-live': 'off' | ||
| 4031 | }); | ||
| 4032 | |||
| 4033 | if(this.options.responsive) { | ||
| 4034 | this._unbindResizeListener(); | ||
| 4035 | } | ||
| 4036 | }, | ||
| 4037 | |||
| 4038 | _applyFocus: function() { | ||
| 4039 | this.element.find(':not(:submit):not(:button):input:visible:enabled:first').focus(); | ||
| 4040 | }, | ||
| 4041 | |||
| 4042 | _bindEvents: function() { | ||
| 4043 | var $this = this; | ||
| 4044 | this.element.on('mousedown.puidialog', function(e) { | ||
| 4045 | if(!$(e.target).data('ui-widget-overlay')) { | ||
| 4046 | $this._moveToTop(); | ||
| 4047 | } | ||
| 4048 | }); | ||
| 4049 | |||
| 4050 | this.icons.mouseover(function() { | ||
| 4051 | $(this).addClass('ui-state-hover'); | ||
| 4052 | }).mouseout(function() { | ||
| 4053 | $(this).removeClass('ui-state-hover'); | ||
| 4054 | }); | ||
| 4055 | |||
| 4056 | this.closeIcon.on('click.puidialog', function(e) { | ||
| 4057 | $this.hide(); | ||
| 4058 | $this._trigger('clickClose'); | ||
| 4059 | e.preventDefault(); | ||
| 4060 | }); | ||
| 4061 | |||
| 4062 | this.maximizeIcon.click(function(e) { | ||
| 4063 | $this.toggleMaximize(); | ||
| 4064 | e.preventDefault(); | ||
| 4065 | }); | ||
| 4066 | |||
| 4067 | this.minimizeIcon.click(function(e) { | ||
| 4068 | $this.toggleMinimize(); | ||
| 4069 | e.preventDefault(); | ||
| 4070 | }); | ||
| 4071 | |||
| 4072 | if(this.options.closeOnEscape) { | ||
| 4073 | $(document).on('keydown.dialog_' + this.id, function(e) { | ||
| 4074 | var keyCode = $.ui.keyCode, | ||
| 4075 | active = parseInt($this.element.css('z-index'), 10) === PUI.zindex; | ||
| 4076 | |||
| 4077 | if(e.which === keyCode.ESCAPE && $this.element.is(':visible') && active) { | ||
| 4078 | $this.hide(); | ||
| 4079 | $this._trigger('hideWithEscape'); | ||
| 4080 | } | ||
| 4081 | }); | ||
| 4082 | } | ||
| 4083 | }, | ||
| 4084 | |||
| 4085 | _unbindEvents: function() { | ||
| 4086 | this.element.off('mousedown.puidialog'); | ||
| 4087 | this.icons.off(); | ||
| 4088 | $(document).off('keydown.dialog_' + this.id); | ||
| 4089 | }, | ||
| 4090 | |||
| 4091 | _setupDraggable: function() { | ||
| 4092 | this.element.draggable({ | ||
| 4093 | cancel: '.ui-dialog-content, .ui-dialog-titlebar-close', | ||
| 4094 | handle: '.ui-dialog-titlebar', | ||
| 4095 | containment : 'document' | ||
| 4096 | }); | ||
| 4097 | }, | ||
| 4098 | |||
| 4099 | _setupResizable: function() { | ||
| 4100 | var $this = this; | ||
| 4101 | |||
| 4102 | this.element.resizable({ | ||
| 4103 | minWidth : this.options.minWidth, | ||
| 4104 | minHeight : this.options.minHeight, | ||
| 4105 | alsoResize : this.content, | ||
| 4106 | containment: 'document', | ||
| 4107 | start: function(event, ui) { | ||
| 4108 | $this.element.data('offset', $this.element.offset()); | ||
| 4109 | }, | ||
| 4110 | stop: function(event, ui) { | ||
| 4111 | var offset = $this.element.data('offset'); | ||
| 4112 | |||
| 4113 | $this.element.css('position', 'fixed'); | ||
| 4114 | $this.element.offset(offset); | ||
| 4115 | } | ||
| 4116 | }); | ||
| 4117 | |||
| 4118 | this.resizers = this.element.children('.ui-resizable-handle'); | ||
| 4119 | }, | ||
| 4120 | |||
| 4121 | _initPosition: function() { | ||
| 4122 | //reset | ||
| 4123 | this.element.css({left:0,top:0}); | ||
| 4124 | |||
| 4125 | if(/(center|left|top|right|bottom)/.test(this.options.location)) { | ||
| 4126 | this.options.location = this.options.location.replace(',', ' '); | ||
| 4127 | |||
| 4128 | this.element.position({ | ||
| 4129 | my: 'center', | ||
| 4130 | at: this.options.location, | ||
| 4131 | collision: 'fit', | ||
| 4132 | of: window, | ||
| 4133 | //make sure dialog stays in viewport | ||
| 4134 | using: function(pos) { | ||
| 4135 | var l = pos.left < 0 ? 0 : pos.left, | ||
| 4136 | t = pos.top < 0 ? 0 : pos.top; | ||
| 4137 | |||
| 4138 | $(this).css({ | ||
| 4139 | left: l, | ||
| 4140 | top: t | ||
| 4141 | }); | ||
| 4142 | } | ||
| 4143 | }); | ||
| 4144 | } | ||
| 4145 | else { | ||
| 4146 | var coords = this.options.position.split(','), | ||
| 4147 | x = $.trim(coords[0]), | ||
| 4148 | y = $.trim(coords[1]); | ||
| 4149 | |||
| 4150 | this.element.offset({ | ||
| 4151 | left: x, | ||
| 4152 | top: y | ||
| 4153 | }); | ||
| 4154 | } | ||
| 4155 | |||
| 4156 | this.positionInitialized = true; | ||
| 4157 | }, | ||
| 4158 | |||
| 4159 | _moveToTop: function() { | ||
| 4160 | this.element.css('z-index',++PUI.zindex); | ||
| 4161 | }, | ||
| 4162 | |||
| 4163 | toggleMaximize: function() { | ||
| 4164 | if(this.minimized) { | ||
| 4165 | this.toggleMinimize(); | ||
| 4166 | } | ||
| 4167 | |||
| 4168 | if(this.maximized) { | ||
| 4169 | this.element.removeClass('ui-dialog-maximized'); | ||
| 4170 | this._restoreState(); | ||
| 4171 | |||
| 4172 | this.maximizeIcon.removeClass('ui-state-hover'); | ||
| 4173 | this.maximized = false; | ||
| 4174 | } | ||
| 4175 | else { | ||
| 4176 | this._saveState(); | ||
| 4177 | |||
| 4178 | var win = $(window); | ||
| 4179 | |||
| 4180 | this.element.addClass('ui-dialog-maximized').css({ | ||
| 4181 | 'width': win.width() - 6, | ||
| 4182 | 'height': win.height() | ||
| 4183 | }).offset({ | ||
| 4184 | top: win.scrollTop(), | ||
| 4185 | left: win.scrollLeft() | ||
| 4186 | }); | ||
| 4187 | |||
| 4188 | //maximize content | ||
| 4189 | this.content.css({ | ||
| 4190 | width: 'auto', | ||
| 4191 | height: 'auto' | ||
| 4192 | }); | ||
| 4193 | |||
| 4194 | this.maximizeIcon.removeClass('ui-state-hover'); | ||
| 4195 | this.maximized = true; | ||
| 4196 | this._trigger('maximize'); | ||
| 4197 | } | ||
| 4198 | }, | ||
| 4199 | |||
| 4200 | toggleMinimize: function() { | ||
| 4201 | var animate = true, | ||
| 4202 | dockingZone = $(document.body).children('.ui-dialog-docking-zone'); | ||
| 4203 | |||
| 4204 | if(this.maximized) { | ||
| 4205 | this.toggleMaximize(); | ||
| 4206 | animate = false; | ||
| 4207 | } | ||
| 4208 | |||
| 4209 | var $this = this; | ||
| 4210 | |||
| 4211 | if(this.minimized) { | ||
| 4212 | this.element.appendTo(this.parent).removeClass('ui-dialog-minimized').css({'position':'fixed', 'float':'none'}); | ||
| 4213 | this._restoreState(); | ||
| 4214 | this.content.show(); | ||
| 4215 | this.minimizeIcon.removeClass('ui-state-hover').children('.fa').removeClass('fa-plus').addClass('fa-minus'); | ||
| 4216 | this.minimized = false; | ||
| 4217 | |||
| 4218 | if(this.options.resizable) { | ||
| 4219 | this.resizers.show(); | ||
| 4220 | } | ||
| 4221 | |||
| 4222 | if(this.footer) { | ||
| 4223 | this.footer.show(); | ||
| 4224 | } | ||
| 4225 | } | ||
| 4226 | else { | ||
| 4227 | this._saveState(); | ||
| 4228 | |||
| 4229 | if(animate) { | ||
| 4230 | this.element.effect('transfer', { | ||
| 4231 | to: dockingZone, | ||
| 4232 | className: 'ui-dialog-minimizing' | ||
| 4233 | }, 500, | ||
| 4234 | function() { | ||
| 4235 | $this._dock(dockingZone); | ||
| 4236 | $this.element.addClass('ui-dialog-minimized'); | ||
| 4237 | }); | ||
| 4238 | } | ||
| 4239 | else { | ||
| 4240 | this._dock(dockingZone); | ||
| 4241 | } | ||
| 4242 | } | ||
| 4243 | }, | ||
| 4244 | |||
| 4245 | _dock: function(zone) { | ||
| 4246 | this.element.appendTo(zone).css('position', 'static'); | ||
| 4247 | this.element.css({'height':'auto', 'width':'auto', 'float': 'left'}); | ||
| 4248 | this.content.hide(); | ||
| 4249 | this.minimizeIcon.removeClass('ui-state-hover').children('.fa').removeClass('fa-minus').addClass('fa-plus'); | ||
| 4250 | this.minimized = true; | ||
| 4251 | |||
| 4252 | if(this.options.resizable) { | ||
| 4253 | this.resizers.hide(); | ||
| 4254 | } | ||
| 4255 | |||
| 4256 | if(this.footer) { | ||
| 4257 | this.footer.hide(); | ||
| 4258 | } | ||
| 4259 | |||
| 4260 | zone.css('z-index',++PUI.zindex); | ||
| 4261 | |||
| 4262 | this._trigger('minimize'); | ||
| 4263 | }, | ||
| 4264 | |||
| 4265 | _saveState: function() { | ||
| 4266 | this.state = { | ||
| 4267 | width: this.element.width(), | ||
| 4268 | height: this.element.height() | ||
| 4269 | }; | ||
| 4270 | |||
| 4271 | var win = $(window); | ||
| 4272 | this.state.offset = this.element.offset(); | ||
| 4273 | this.state.windowScrollLeft = win.scrollLeft(); | ||
| 4274 | this.state.windowScrollTop = win.scrollTop(); | ||
| 4275 | }, | ||
| 4276 | |||
| 4277 | _restoreState: function() { | ||
| 4278 | this.element.width(this.state.width).height(this.state.height); | ||
| 4279 | |||
| 4280 | var win = $(window); | ||
| 4281 | this.element.offset({ | ||
| 4282 | top: this.state.offset.top + (win.scrollTop() - this.state.windowScrollTop), | ||
| 4283 | left: this.state.offset.left + (win.scrollLeft() - this.state.windowScrollLeft) | ||
| 4284 | }); | ||
| 4285 | }, | ||
| 4286 | |||
| 4287 | _applyARIA: function() { | ||
| 4288 | this.element.attr({ | ||
| 4289 | 'role': 'dialog', | ||
| 4290 | 'aria-labelledby': this.element.attr('id') + '_title', | ||
| 4291 | 'aria-hidden': !this.options.visible | ||
| 4292 | }); | ||
| 4293 | |||
| 4294 | this.titlebar.children('a.ui-dialog-titlebar-icon').attr('role', 'button'); | ||
| 4295 | }, | ||
| 4296 | |||
| 4297 | _removeARIA: function() { | ||
| 4298 | this.element.removeAttr('role').removeAttr('aria-labelledby').removeAttr('aria-hidden') | ||
| 4299 | .removeAttr('aria-live').removeAttr('aria-hidden'); | ||
| 4300 | }, | ||
| 4301 | |||
| 4302 | _bindResizeListener: function() { | ||
| 4303 | var $this = this; | ||
| 4304 | $(window).on(this.resizeNS, function(e) { | ||
| 4305 | if(e.target === window) { | ||
| 4306 | $this._initPosition(); | ||
| 4307 | } | ||
| 4308 | }); | ||
| 4309 | }, | ||
| 4310 | |||
| 4311 | _unbindResizeListener: function() { | ||
| 4312 | $(window).off(this.resizeNS); | ||
| 4313 | }, | ||
| 4314 | |||
| 4315 | _setOption: function(key, value) { | ||
| 4316 | if(key === 'visible') { | ||
| 4317 | if(value) | ||
| 4318 | this.show(); | ||
| 4319 | else | ||
| 4320 | this.hide(); | ||
| 4321 | } | ||
| 4322 | else { | ||
| 4323 | $.Widget.prototype._setOption.apply(this, arguments); | ||
| 4324 | } | ||
| 4325 | } | ||
| 4326 | }); | ||
| 4327 | })(); | ||
| 4328 | /** | ||
| 4329 | * PrimeUI dropdown widget | ||
| 4330 | */ | ||
| 4331 | (function() { | ||
| 4332 | |||
| 4333 | $.widget("primeui.puidropdown", { | ||
| 4334 | |||
| 4335 | options: { | ||
| 4336 | effect: 'fade', | ||
| 4337 | effectSpeed: 'normal', | ||
| 4338 | filter: false, | ||
| 4339 | filterMatchMode: 'startsWith', | ||
| 4340 | caseSensitiveFilter: false, | ||
| 4341 | filterFunction: null, | ||
| 4342 | data: null, | ||
| 4343 | content: null, | ||
| 4344 | scrollHeight: 200, | ||
| 4345 | appendTo: 'body', | ||
| 4346 | editable: false, | ||
| 4347 | value: null, | ||
| 4348 | style: null, | ||
| 4349 | styleClass: null | ||
| 4350 | }, | ||
| 4351 | |||
| 4352 | _create: function() { | ||
| 4353 | this.id = this.element.attr('id'); | ||
| 4354 | if(!this.id) { | ||
| 4355 | this.id = this.element.uniqueId().attr('id'); | ||
| 4356 | } | ||
| 4357 | |||
| 4358 | if(!this.options.enhanced) { | ||
| 4359 | if(this.options.data) { | ||
| 4360 | if($.isArray(this.options.data)) { | ||
| 4361 | this._generateOptionElements(this.options.data); | ||
| 4362 | } | ||
| 4363 | else { | ||
| 4364 | if($.type(this.options.data) === 'function') { | ||
| 4365 | this.options.data.call(this, this._onRemoteOptionsLoad); | ||
| 4366 | return; | ||
| 4367 | } | ||
| 4368 | else { | ||
| 4369 | if($.type(this.options.data) === 'string') { | ||
| 4370 | var $this = this, | ||
| 4371 | dataURL = this.options.data; | ||
| 4372 | |||
| 4373 | var loader = function() { | ||
| 4374 | $.ajax({ | ||
| 4375 | type: 'GET', | ||
| 4376 | url: dataURL, | ||
| 4377 | dataType: "json", | ||
| 4378 | context: $this, | ||
| 4379 | success: function (response) { | ||
| 4380 | this._onRemoteOptionsLoad(response); | ||
| 4381 | } | ||
| 4382 | }); | ||
| 4383 | }; | ||
| 4384 | loader.call(this); | ||
| 4385 | } | ||
| 4386 | } | ||
| 4387 | return; | ||
| 4388 | } | ||
| 4389 | } | ||
| 4390 | |||
| 4391 | this._render(); | ||
| 4392 | } | ||
| 4393 | else { | ||
| 4394 | this.choices = this.element.children('option'); | ||
| 4395 | this.container = this.element.closest('.ui-dropdown'); | ||
| 4396 | this.focusElementContainer = this.container.children('.ui-helper-hidden-accessible:last'); | ||
| 4397 | this.focusElement = this.focusElementContainer.children('input'); | ||
| 4398 | this.label = this.container.children('.ui-dropdown-label'); | ||
| 4399 | this.menuIcon = this.container.children('.ui-dropdown-trigger'); | ||
| 4400 | this.panel = this.container.children('.ui-dropdown-panel'); | ||
| 4401 | this.itemsWrapper = this.panel.children('.ui-dropdown-items-wrapper'); | ||
| 4402 | this.itemsContainer = this.itemsWrapper.children('ul'); | ||
| 4403 | this.itemsContainer.addClass('ui-dropdown-items ui-dropdown-list ui-widget-content ui-widget ui-corner-all ui-helper-reset'); | ||
| 4404 | this.items = this.itemsContainer.children('li').addClass('ui-dropdown-item ui-dropdown-list-item ui-corner-all'); | ||
| 4405 | |||
| 4406 | var $this = this; | ||
| 4407 | this.items.each(function(i) { | ||
| 4408 | $(this).data('label', $this.choices.eq(i).text()); | ||
| 4409 | }); | ||
| 4410 | |||
| 4411 | if(this.options.filter) { | ||
| 4412 | this.filterContainer = this.panel.children('.ui-dropdown-filter-container'); | ||
| 4413 | this.filterInput = this.filterContainer.children('input'); | ||
| 4414 | } | ||
| 4415 | } | ||
| 4416 | |||
| 4417 | this._postRender(); | ||
| 4418 | }, | ||
| 4419 | |||
| 4420 | _render: function() { | ||
| 4421 | this.choices = this.element.children('option'); | ||
| 4422 | this.element.attr('tabindex', '-1').wrap('<div class="ui-dropdown ui-widget ui-state-default ui-corner-all ui-helper-clearfix" />') | ||
| 4423 | .wrap('<div class="ui-helper-hidden-accessible" />'); | ||
| 4424 | |||
| 4425 | this.container = this.element.closest('.ui-dropdown'); | ||
| 4426 | this.focusElementContainer = $('<div class="ui-helper-hidden-accessible"><input type="text" /></div>').appendTo(this.container); | ||
| 4427 | this.focusElement = this.focusElementContainer.children('input'); | ||
| 4428 | this.label = this.options.editable ? $('<input type="text" class="ui-dropdown-label ui-inputtext ui-corner-all"">') | ||
| 4429 | : $('<label class="ui-dropdown-label ui-inputtext ui-corner-all"/>'); | ||
| 4430 | this.label.appendTo(this.container); | ||
| 4431 | this.menuIcon = $('<div class="ui-dropdown-trigger ui-state-default ui-corner-right"><span class="fa fa-fw fa-caret-down"></span></div>') | ||
| 4432 | .appendTo(this.container); | ||
| 4433 | |||
| 4434 | //panel | ||
| 4435 | this.panel = $('<div class="ui-dropdown-panel ui-widget-content ui-corner-all ui-helper-hidden ui-shadow" />'); | ||
| 4436 | this.itemsWrapper = $('<div class="ui-dropdown-items-wrapper" />').appendTo(this.panel); | ||
| 4437 | this.itemsContainer = $('<ul class="ui-dropdown-items ui-dropdown-list ui-widget-content ui-widget ui-corner-all ui-helper-reset"></ul>') | ||
| 4438 | .appendTo(this.itemsWrapper); | ||
| 4439 | |||
| 4440 | this.optGroupsSize = this.itemsContainer.children('li.puiselectonemenu-item-group').length; | ||
| 4441 | |||
| 4442 | if(this.options.filter) { | ||
| 4443 | this.filterContainer = $('<div class="ui-dropdown-filter-container" />').prependTo(this.panel); | ||
| 4444 | this.filterInput = $('<input type="text" autocomplete="off" class="ui-dropdown-filter ui-inputtext ui-widget ui-state-default ui-corner-all" />') | ||
| 4445 | .appendTo(this.filterContainer); | ||
| 4446 | this.filterContainer.append('<span class="fa fa-search"></span>'); | ||
| 4447 | } | ||
| 4448 | |||
| 4449 | this._generateItems(); | ||
| 4450 | }, | ||
| 4451 | |||
| 4452 | _postRender: function() { | ||
| 4453 | if(this.options.style) { | ||
| 4454 | this.container.attr('style', this.options.style); | ||
| 4455 | } | ||
| 4456 | |||
| 4457 | if(this.options.styleClass) { | ||
| 4458 | this.container.addClass(this.options.styleClass); | ||
| 4459 | } | ||
| 4460 | |||
| 4461 | this.disabled = this.element.prop('disabled')||this.options.disabled; | ||
| 4462 | |||
| 4463 | if(this.options.appendTo === 'self') | ||
| 4464 | this.panel.appendTo(this.container); | ||
| 4465 | else | ||
| 4466 | this.panel.appendTo(this.options.appendTo); | ||
| 4467 | |||
| 4468 | if(this.options.scrollHeight && this.panel.outerHeight() > this.options.scrollHeight) { | ||
| 4469 | this.itemsWrapper.height(this.options.scrollHeight); | ||
| 4470 | } | ||
| 4471 | |||
| 4472 | var $this = this; | ||
| 4473 | |||
| 4474 | //preselection via value option | ||
| 4475 | if(this.options.value) { | ||
| 4476 | this.choices.filter('[value="'+this.options.value+'"]').prop('selected', true); | ||
| 4477 | } | ||
| 4478 | |||
| 4479 | var selectedOption = this.choices.filter(':selected'); | ||
| 4480 | |||
| 4481 | //disable options | ||
| 4482 | this.choices.filter(':disabled').each(function() { | ||
| 4483 | $this.items.eq($(this).index()).addClass('ui-state-disabled'); | ||
| 4484 | }); | ||
| 4485 | |||
| 4486 | //triggers | ||
| 4487 | this.triggers = this.options.editable ? this.menuIcon : this.container.children('.ui-dropdown-trigger, .ui-dropdown-label'); | ||
| 4488 | |||
| 4489 | //activate selected | ||
| 4490 | if(this.options.editable) { | ||
| 4491 | var customInputVal = this.label.val(); | ||
| 4492 | |||
| 4493 | //predefined input | ||
| 4494 | if(customInputVal === selectedOption.text()) { | ||
| 4495 | this._highlightItem(this.items.eq(selectedOption.index())); | ||
| 4496 | } | ||
| 4497 | //custom input | ||
| 4498 | else { | ||
| 4499 | this.items.eq(0).addClass('ui-state-highlight'); | ||
| 4500 | this.customInput = true; | ||
| 4501 | this.customInputVal = customInputVal; | ||
| 4502 | } | ||
| 4503 | } | ||
| 4504 | else { | ||
| 4505 | this._highlightItem(this.items.eq(selectedOption.index())); | ||
| 4506 | } | ||
| 4507 | |||
| 4508 | if(!this.disabled) { | ||
| 4509 | this._bindEvents(); | ||
| 4510 | this._bindConstantEvents(); | ||
| 4511 | } | ||
| 4512 | }, | ||
| 4513 | |||
| 4514 | _onRemoteOptionsLoad: function(data) { | ||
| 4515 | this._generateOptionElements(data); | ||
| 4516 | this._render(); | ||
| 4517 | this._postRender(); | ||
| 4518 | }, | ||
| 4519 | |||
| 4520 | _generateOptionElements: function(data) { | ||
| 4521 | for(var i = 0; i < data.length; i++) { | ||
| 4522 | var choice = data[i]; | ||
| 4523 | if(choice.label) | ||
| 4524 | this.element.append('<option value="' + choice.value + '">' + choice.label + '</option>'); | ||
| 4525 | else | ||
| 4526 | this.element.append('<option value="' + choice + '">' + choice + '</option>'); | ||
| 4527 | } | ||
| 4528 | }, | ||
| 4529 | |||
| 4530 | _generateItems: function() { | ||
| 4531 | for(var i = 0; i < this.choices.length; i++) { | ||
| 4532 | var option = this.choices.eq(i), | ||
| 4533 | optionLabel = option.text(), | ||
| 4534 | content = this.options.content ? this.options.content.call(this, this.options.data[i]) : optionLabel; | ||
| 4535 | |||
| 4536 | this.itemsContainer.append('<li data-label="' + optionLabel + '" class="ui-dropdown-item ui-dropdown-list-item ui-corner-all">' + content + '</li>'); | ||
| 4537 | } | ||
| 4538 | |||
| 4539 | this.items = this.itemsContainer.children('.ui-dropdown-item'); | ||
| 4540 | }, | ||
| 4541 | |||
| 4542 | _bindEvents: function() { | ||
| 4543 | var $this = this; | ||
| 4544 | |||
| 4545 | this.items.filter(':not(.ui-state-disabled)').each(function(i, item) { | ||
| 4546 | $this._bindItemEvents($(item)); | ||
| 4547 | }); | ||
| 4548 | |||
| 4549 | this.triggers.on('mouseenter.puidropdown', function() { | ||
| 4550 | if(!$this.container.hasClass('ui-state-focus')) { | ||
| 4551 | $this.container.addClass('ui-state-hover'); | ||
| 4552 | $this.menuIcon.addClass('ui-state-hover'); | ||
| 4553 | } | ||
| 4554 | }) | ||
| 4555 | .on('mouseleave.puidropdown', function() { | ||
| 4556 | $this.container.removeClass('ui-state-hover'); | ||
| 4557 | $this.menuIcon.removeClass('ui-state-hover'); | ||
| 4558 | }) | ||
| 4559 | .on('click.puidropdown', function(e) { | ||
| 4560 | if($this.panel.is(":hidden")) { | ||
| 4561 | $this._show(); | ||
| 4562 | } | ||
| 4563 | else { | ||
| 4564 | $this._hide(); | ||
| 4565 | |||
| 4566 | $this._revert(); | ||
| 4567 | } | ||
| 4568 | |||
| 4569 | $this.container.removeClass('ui-state-hover'); | ||
| 4570 | $this.menuIcon.removeClass('ui-state-hover'); | ||
| 4571 | $this.focusElement.trigger('focus.puidropdown'); | ||
| 4572 | e.preventDefault(); | ||
| 4573 | }); | ||
| 4574 | |||
| 4575 | this.focusElement.on('focus.puidropdown', function() { | ||
| 4576 | $this.container.addClass('ui-state-focus'); | ||
| 4577 | $this.menuIcon.addClass('ui-state-focus'); | ||
| 4578 | }) | ||
| 4579 | .on('blur.puidropdown', function() { | ||
| 4580 | $this.container.removeClass('ui-state-focus'); | ||
| 4581 | $this.menuIcon.removeClass('ui-state-focus'); | ||
| 4582 | }); | ||
| 4583 | |||
| 4584 | if(this.options.editable) { | ||
| 4585 | this.label.on('change.ui-dropdown', function() { | ||
| 4586 | $this._triggerChange(true); | ||
| 4587 | $this.customInput = true; | ||
| 4588 | $this.customInputVal = $(this).val(); | ||
| 4589 | $this.items.filter('.ui-state-highlight').removeClass('ui-state-highlight'); | ||
| 4590 | $this.items.eq(0).addClass('ui-state-highlight'); | ||
| 4591 | }); | ||
| 4592 | } | ||
| 4593 | |||
| 4594 | this._bindKeyEvents(); | ||
| 4595 | |||
| 4596 | if(this.options.filter) { | ||
| 4597 | this._setupFilterMatcher(); | ||
| 4598 | |||
| 4599 | this.filterInput.puiinputtext(); | ||
| 4600 | |||
| 4601 | this.filterInput.on('keyup.ui-dropdown', function() { | ||
| 4602 | $this._filter($(this).val()); | ||
| 4603 | }); | ||
| 4604 | } | ||
| 4605 | }, | ||
| 4606 | |||
| 4607 | _bindItemEvents: function(item) { | ||
| 4608 | var $this = this; | ||
| 4609 | |||
| 4610 | item.on('mouseover.puidropdown', function() { | ||
| 4611 | var el = $(this); | ||
| 4612 | |||
| 4613 | if(!el.hasClass('ui-state-highlight')) | ||
| 4614 | $(this).addClass('ui-state-hover'); | ||
| 4615 | }) | ||
| 4616 | .on('mouseout.puidropdown', function() { | ||
| 4617 | $(this).removeClass('ui-state-hover'); | ||
| 4618 | }) | ||
| 4619 | .on('click.puidropdown', function() { | ||
| 4620 | $this._selectItem($(this)); | ||
| 4621 | }); | ||
| 4622 | }, | ||
| 4623 | |||
| 4624 | _bindConstantEvents: function() { | ||
| 4625 | var $this = this; | ||
| 4626 | |||
| 4627 | $(document.body).on('mousedown.ui-dropdown-' + this.id, function (e) { | ||
| 4628 | if($this.panel.is(":hidden")) { | ||
| 4629 | return; | ||
| 4630 | } | ||
| 4631 | |||
| 4632 | var offset = $this.panel.offset(); | ||
| 4633 | if (e.target === $this.label.get(0) || | ||
| 4634 | e.target === $this.menuIcon.get(0) || | ||
| 4635 | e.target === $this.menuIcon.children().get(0)) { | ||
| 4636 | return; | ||
| 4637 | } | ||
| 4638 | |||
| 4639 | if (e.pageX < offset.left || | ||
| 4640 | e.pageX > offset.left + $this.panel.width() || | ||
| 4641 | e.pageY < offset.top || | ||
| 4642 | e.pageY > offset.top + $this.panel.height()) { | ||
| 4643 | |||
| 4644 | $this._hide(); | ||
| 4645 | $this._revert(); | ||
| 4646 | } | ||
| 4647 | }); | ||
| 4648 | |||
| 4649 | this.resizeNS = 'resize.' + this.id; | ||
| 4650 | this._unbindResize(); | ||
| 4651 | this._bindResize(); | ||
| 4652 | }, | ||
| 4653 | |||
| 4654 | _bindKeyEvents: function() { | ||
| 4655 | var $this = this; | ||
| 4656 | |||
| 4657 | this.focusElement.on('keydown.puidropdown', function(e) { | ||
| 4658 | var keyCode = $.ui.keyCode, | ||
| 4659 | key = e.which, | ||
| 4660 | activeItem; | ||
| 4661 | |||
| 4662 | switch(key) { | ||
| 4663 | case keyCode.UP: | ||
| 4664 | case keyCode.LEFT: | ||
| 4665 | activeItem = $this._getActiveItem(); | ||
| 4666 | var prev = activeItem.prevAll(':not(.ui-state-disabled,.ui-selectonemenu-item-group):first'); | ||
| 4667 | |||
| 4668 | if(prev.length == 1) { | ||
| 4669 | if($this.panel.is(':hidden')) { | ||
| 4670 | $this._selectItem(prev); | ||
| 4671 | } | ||
| 4672 | else { | ||
| 4673 | $this._highlightItem(prev); | ||
| 4674 | PUI.scrollInView($this.itemsWrapper, prev); | ||
| 4675 | } | ||
| 4676 | } | ||
| 4677 | |||
| 4678 | e.preventDefault(); | ||
| 4679 | break; | ||
| 4680 | |||
| 4681 | case keyCode.DOWN: | ||
| 4682 | case keyCode.RIGHT: | ||
| 4683 | activeItem = $this._getActiveItem(); | ||
| 4684 | var next = activeItem.nextAll(':not(.ui-state-disabled,.ui-selectonemenu-item-group):first'); | ||
| 4685 | |||
| 4686 | if(next.length == 1) { | ||
| 4687 | if($this.panel.is(':hidden')) { | ||
| 4688 | if(e.altKey) { | ||
| 4689 | $this._show(); | ||
| 4690 | } else { | ||
| 4691 | $this._selectItem(next); | ||
| 4692 | } | ||
| 4693 | } | ||
| 4694 | else { | ||
| 4695 | $this._highlightItem(next); | ||
| 4696 | PUI.scrollInView($this.itemsWrapper, next); | ||
| 4697 | } | ||
| 4698 | } | ||
| 4699 | |||
| 4700 | e.preventDefault(); | ||
| 4701 | break; | ||
| 4702 | |||
| 4703 | case keyCode.ENTER: | ||
| 4704 | case keyCode.NUMPAD_ENTER: | ||
| 4705 | if($this.panel.is(':hidden')) { | ||
| 4706 | $this._show(); | ||
| 4707 | } | ||
| 4708 | else { | ||
| 4709 | $this._selectItem($this._getActiveItem()); | ||
| 4710 | } | ||
| 4711 | |||
| 4712 | e.preventDefault(); | ||
| 4713 | break; | ||
| 4714 | |||
| 4715 | case keyCode.TAB: | ||
| 4716 | if($this.panel.is(':visible')) { | ||
| 4717 | $this._revert(); | ||
| 4718 | $this._hide(); | ||
| 4719 | } | ||
| 4720 | break; | ||
| 4721 | |||
| 4722 | case keyCode.ESCAPE: | ||
| 4723 | if($this.panel.is(':visible')) { | ||
| 4724 | $this._revert(); | ||
| 4725 | $this._hide(); | ||
| 4726 | } | ||
| 4727 | break; | ||
| 4728 | |||
| 4729 | default: | ||
| 4730 | var k = String.fromCharCode((96 <= key && key <= 105)? key-48 : key), | ||
| 4731 | currentItem = $this.items.filter('.ui-state-highlight'); | ||
| 4732 | |||
| 4733 | //Search items forward from current to end and on no result, search from start until current | ||
| 4734 | var highlightItem = $this._search(k, currentItem.index() + 1, $this.options.length); | ||
| 4735 | if(!highlightItem) { | ||
| 4736 | highlightItem = $this._search(k, 0, currentItem.index()); | ||
| 4737 | } | ||
| 4738 | |||
| 4739 | if(highlightItem) { | ||
| 4740 | if($this.panel.is(':hidden')) { | ||
| 4741 | $this._selectItem(highlightItem); | ||
| 4742 | } | ||
| 4743 | else { | ||
| 4744 | $this._highlightItem(highlightItem); | ||
| 4745 | PUI.scrollInView($this.itemsWrapper, highlightItem); | ||
| 4746 | } | ||
| 4747 | } | ||
| 4748 | |||
| 4749 | break; | ||
| 4750 | } | ||
| 4751 | }); | ||
| 4752 | }, | ||
| 4753 | |||
| 4754 | _unbindEvents: function() { | ||
| 4755 | this.items.off('mouseover.puidropdown mouseout.puidropdown click.puidropdown'); | ||
| 4756 | this.triggers.off('mouseenter.puidropdown mouseleave.puidropdown click.puidropdown'); | ||
| 4757 | this.focusElement.off('keydown.puidropdown focus.puidropdown blur.puidropdown'); | ||
| 4758 | |||
| 4759 | if(this.options.editable) { | ||
| 4760 | this.label.off('change.puidropdown'); | ||
| 4761 | } | ||
| 4762 | |||
| 4763 | if(this.options.filter) { | ||
| 4764 | this.filterInput.off('keyup.ui-dropdown'); | ||
| 4765 | } | ||
| 4766 | |||
| 4767 | $(document.body).off('mousedown.ui-dropdown-' + this.id); | ||
| 4768 | this._unbindResize(); | ||
| 4769 | }, | ||
| 4770 | |||
| 4771 | _selectItem: function(item, silent) { | ||
| 4772 | var selectedOption = this.choices.eq(this._resolveItemIndex(item)), | ||
| 4773 | currentOption = this.choices.filter(':selected'), | ||
| 4774 | sameOption = selectedOption.val() == currentOption.val(), | ||
| 4775 | shouldChange = null; | ||
| 4776 | |||
| 4777 | if(this.options.editable) { | ||
| 4778 | shouldChange = (!sameOption)||(selectedOption.text() != this.label.val()); | ||
| 4779 | } | ||
| 4780 | else { | ||
| 4781 | shouldChange = !sameOption; | ||
| 4782 | } | ||
| 4783 | |||
| 4784 | if(shouldChange) { | ||
| 4785 | this._highlightItem(item); | ||
| 4786 | this.element.val(selectedOption.val()); | ||
| 4787 | |||
| 4788 | this._triggerChange(); | ||
| 4789 | |||
| 4790 | if(this.options.editable) { | ||
| 4791 | this.customInput = false; | ||
| 4792 | } | ||
| 4793 | } | ||
| 4794 | |||
| 4795 | if(!silent) { | ||
| 4796 | this.focusElement.trigger('focus.puidropdown'); | ||
| 4797 | } | ||
| 4798 | |||
| 4799 | if(this.panel.is(':visible')) { | ||
| 4800 | this._hide(); | ||
| 4801 | } | ||
| 4802 | }, | ||
| 4803 | |||
| 4804 | _highlightItem: function(item) { | ||
| 4805 | this.items.filter('.ui-state-highlight').removeClass('ui-state-highlight'); | ||
| 4806 | |||
| 4807 | if(item.length) { | ||
| 4808 | item.addClass('ui-state-highlight'); | ||
| 4809 | |||
| 4810 | this._setLabel(item.data('label')); | ||
| 4811 | } | ||
| 4812 | else { | ||
| 4813 | this._setLabel(' '); | ||
| 4814 | } | ||
| 4815 | }, | ||
| 4816 | |||
| 4817 | _triggerChange: function(edited) { | ||
| 4818 | this.changed = false; | ||
| 4819 | var selectedOption = this.choices.filter(':selected'); | ||
| 4820 | |||
| 4821 | if(this.options.change) { | ||
| 4822 | this._trigger('change', null, { | ||
| 4823 | value: selectedOption.val(), | ||
| 4824 | index: selectedOption.index() | ||
| 4825 | }); | ||
| 4826 | } | ||
| 4827 | |||
| 4828 | if(!edited) { | ||
| 4829 | this.value = this.choices.filter(':selected').val(); | ||
| 4830 | } | ||
| 4831 | }, | ||
| 4832 | |||
| 4833 | _resolveItemIndex: function(item) { | ||
| 4834 | if(this.optGroupsSize === 0) { | ||
| 4835 | return item.index(); | ||
| 4836 | } | ||
| 4837 | else { | ||
| 4838 | return item.index() - item.prevAll('li.ui-dropdown-item-group').length; | ||
| 4839 | } | ||
| 4840 | }, | ||
| 4841 | |||
| 4842 | _setLabel: function(value) { | ||
| 4843 | if(this.options.editable) { | ||
| 4844 | this.label.val(value); | ||
| 4845 | } | ||
| 4846 | else { | ||
| 4847 | if(value === ' ') { | ||
| 4848 | this.label.html(' '); | ||
| 4849 | } | ||
| 4850 | else { | ||
| 4851 | this.label.text(value); | ||
| 4852 | } | ||
| 4853 | } | ||
| 4854 | }, | ||
| 4855 | |||
| 4856 | _bindResize: function() { | ||
| 4857 | var $this = this; | ||
| 4858 | |||
| 4859 | $(window).bind(this.resizeNS, function(e) { | ||
| 4860 | if($this.panel.is(':visible')) { | ||
| 4861 | $this._alignPanel(); | ||
| 4862 | } | ||
| 4863 | }); | ||
| 4864 | }, | ||
| 4865 | |||
| 4866 | _unbindResize: function() { | ||
| 4867 | $(window).unbind(this.resizeNS); | ||
| 4868 | }, | ||
| 4869 | |||
| 4870 | _alignPanelWidth: function() { | ||
| 4871 | if(!this.panelWidthAdjusted) { | ||
| 4872 | var jqWidth = this.container.outerWidth(); | ||
| 4873 | if(this.panel.outerWidth() < jqWidth) { | ||
| 4874 | this.panel.width(jqWidth); | ||
| 4875 | } | ||
| 4876 | |||
| 4877 | this.panelWidthAdjusted = true; | ||
| 4878 | } | ||
| 4879 | }, | ||
| 4880 | |||
| 4881 | _alignPanel: function() { | ||
| 4882 | if(this.panel.parent().is(this.container)) { | ||
| 4883 | this.panel.css({ | ||
| 4884 | left: '0px', | ||
| 4885 | top: this.container.outerHeight() + 'px' | ||
| 4886 | }) | ||
| 4887 | .width(this.container.outerWidth()); | ||
| 4888 | } | ||
| 4889 | else { | ||
| 4890 | this._alignPanelWidth(); | ||
| 4891 | this.panel.css({left:'', top:''}).position({ | ||
| 4892 | my: 'left top', | ||
| 4893 | at: 'left bottom', | ||
| 4894 | of: this.container, | ||
| 4895 | collision: 'flipfit' | ||
| 4896 | }); | ||
| 4897 | } | ||
| 4898 | }, | ||
| 4899 | |||
| 4900 | _show: function() { | ||
| 4901 | this._alignPanel(); | ||
| 4902 | |||
| 4903 | this.panel.css('z-index', ++PUI.zindex); | ||
| 4904 | |||
| 4905 | if(this.options.effect !== 'none') { | ||
| 4906 | this.panel.show(this.options.effect, {}, this.options.effectSpeed); | ||
| 4907 | } | ||
| 4908 | else { | ||
| 4909 | this.panel.show(); | ||
| 4910 | } | ||
| 4911 | this.preShowValue = this.choices.filter(':selected'); | ||
| 4912 | }, | ||
| 4913 | |||
| 4914 | _hide: function() { | ||
| 4915 | this.panel.hide(); | ||
| 4916 | }, | ||
| 4917 | |||
| 4918 | _revert: function() { | ||
| 4919 | if(this.options.editable && this.customInput) { | ||
| 4920 | this._setLabel(this.customInputVal); | ||
| 4921 | this.items.filter('.ui-state-active').removeClass('ui-state-active'); | ||
| 4922 | this.items.eq(0).addClass('ui-state-active'); | ||
| 4923 | } | ||
| 4924 | else { | ||
| 4925 | this._highlightItem(this.items.eq(this.preShowValue.index())); | ||
| 4926 | } | ||
| 4927 | }, | ||
| 4928 | |||
| 4929 | _getActiveItem: function() { | ||
| 4930 | return this.items.filter('.ui-state-highlight'); | ||
| 4931 | }, | ||
| 4932 | |||
| 4933 | _setupFilterMatcher: function() { | ||
| 4934 | this.filterMatchers = { | ||
| 4935 | 'startsWith': this._startsWithFilter, | ||
| 4936 | 'contains': this._containsFilter, | ||
| 4937 | 'endsWith': this._endsWithFilter, | ||
| 4938 | 'custom': this.options.filterFunction | ||
| 4939 | }; | ||
| 4940 | |||
| 4941 | this.filterMatcher = this.filterMatchers[this.options.filterMatchMode]; | ||
| 4942 | }, | ||
| 4943 | |||
| 4944 | _startsWithFilter: function(value, filter) { | ||
| 4945 | return value.indexOf(filter) === 0; | ||
| 4946 | }, | ||
| 4947 | |||
| 4948 | _containsFilter: function(value, filter) { | ||
| 4949 | return value.indexOf(filter) !== -1; | ||
| 4950 | }, | ||
| 4951 | |||
| 4952 | _endsWithFilter: function(value, filter) { | ||
| 4953 | return value.indexOf(filter, value.length - filter.length) !== -1; | ||
| 4954 | }, | ||
| 4955 | |||
| 4956 | _filter: function(value) { | ||
| 4957 | this.initialHeight = this.initialHeight||this.itemsWrapper.height(); | ||
| 4958 | var filterValue = this.options.caseSensitiveFilter ? $.trim(value) : $.trim(value).toLowerCase(); | ||
| 4959 | |||
| 4960 | if(filterValue === '') { | ||
| 4961 | this.items.filter(':hidden').show(); | ||
| 4962 | } | ||
| 4963 | else { | ||
| 4964 | for(var i = 0; i < this.choices.length; i++) { | ||
| 4965 | var option = this.choices.eq(i), | ||
| 4966 | itemLabel = this.options.caseSensitiveFilter ? option.text() : option.text().toLowerCase(), | ||
| 4967 | item = this.items.eq(i); | ||
| 4968 | |||
| 4969 | if(this.filterMatcher(itemLabel, filterValue)) | ||
| 4970 | item.show(); | ||
| 4971 | else | ||
| 4972 | item.hide(); | ||
| 4973 | } | ||
| 4974 | } | ||
| 4975 | |||
| 4976 | if(this.itemsContainer.height() < this.initialHeight) { | ||
| 4977 | this.itemsWrapper.css('height', 'auto'); | ||
| 4978 | } | ||
| 4979 | else { | ||
| 4980 | this.itemsWrapper.height(this.initialHeight); | ||
| 4981 | } | ||
| 4982 | |||
| 4983 | this._alignPanel(); | ||
| 4984 | }, | ||
| 4985 | |||
| 4986 | _search: function(text, start, end) { | ||
| 4987 | for(var i = start; i < end; i++) { | ||
| 4988 | var option = this.choices.eq(i); | ||
| 4989 | |||
| 4990 | if(option.text().indexOf(text) === 0) { | ||
| 4991 | return this.items.eq(i); | ||
| 4992 | } | ||
| 4993 | } | ||
| 4994 | |||
| 4995 | return null; | ||
| 4996 | }, | ||
| 4997 | |||
| 4998 | getSelectedValue: function() { | ||
| 4999 | return this.element.val(); | ||
8964 more lines aren’t shown here.