vendor: 4,408 bytes, lines 1-180
1/*! 2 * jQuery JavaScript Library v1.12.4 3 * http://jquery.com/ 4 * 5 * Includes Sizzle.js 6 * http://sizzlejs.com/ 7 * 8 * Copyright jQuery Foundation and other contributors 9 * Released under the MIT license 10 * http://jquery.org/license 11 * 12 * Date: 2016-05-20T17:17Z 13 */ 14 15(function( global, factory ) { 16 17 if ( typeof module === "object" && typeof module.exports === "object" ) { 18 // For CommonJS and CommonJS-like environments where a proper `window` 19 // is present, execute the factory and get jQuery. 20 // For environments that do not have a `window` with a `document` 21 // (such as Node.js), expose a factory as module.exports. 22 // This accentuates the need for the creation of a real `window`. 23 // e.g. var jQuery = require("jquery")(window); 24 // See ticket #14549 for more info. 25 module.exports = global.document ? 26 factory( global, true ) : 27 function( w ) { 28 if ( !w.document ) { 29 throw new Error( "jQuery requires a window with a document" ); 30 } 31 return factory( w ); 32 }; 33 } else { 34 factory( global ); 35 } 36 37// Pass this if window is not defined yet 38}(typeof window !== "undefined" ? window : this, function( window, noGlobal ) { 39 40// Support: Firefox 18+ 41// Can't be in strict mode, several libs including ASP.NET trace 42// the stack via arguments.caller.callee and Firefox dies if 43// you try to trace through "use strict" call chains. (#13335) 44//"use strict"; 45var deletedIds = []; 46 47var document = window.document; 48 49var slice = deletedIds.slice; 50 51var concat = deletedIds.concat; 52 53var push = deletedIds.push; 54 55var indexOf = deletedIds.indexOf; 56 57var class2type = {}; 58 59var toString = class2type.toString; 60 61var hasOwn = class2type.hasOwnProperty; 62 63var support = {}; 64 65 66 67var 68 version = "1.12.4", 69 70 // Define a local copy of jQuery 71 jQuery = function( selector, context ) { 72 73 // The jQuery object is actually just the init constructor 'enhanced' 74 // Need init if jQuery is called (just allow error to be thrown if not included) 75 return new jQuery.fn.init( selector, context ); 76 }, 77 78 // Support: Android<4.1, IE<9 79 // Make sure we trim BOM and NBSP 80 rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, 81 82 // Matches dashed string for camelizing 83 rmsPrefix = /^-ms-/, 84 rdashAlpha = /-([\da-z])/gi, 85 86 // Used by jQuery.camelCase as callback to replace() 87 fcamelCase = function( all, letter ) { 88 return letter.toUpperCase(); 89 }; 90 91jQuery.fn = jQuery.prototype = { 92 93 // The current version of jQuery being used 94 jquery: version, 95 96 constructor: jQuery, 97 98 // Start with an empty selector 99 selector: "", 100 101 // The default length of a jQuery object is 0 102 length: 0, 103 104 toArray: function() { 105 return slice.call( this ); 106 }, 107 108 // Get the Nth element in the matched element set OR 109 // Get the whole matched element set as a clean array 110 get: function( num ) { 111 return num != null ? 112 113 // Return just the one element from the set 114 ( num < 0 ? this[ num + this.length ] : this[ num ] ) : 115 116 // Return all the elements in a clean array 117 slice.call( this ); 118 }, 119 120 // Take an array of elements and push it onto the stack 121 // (returning the new matched element set) 122 pushStack: function( elems ) { 123 124 // Build a new jQuery matched element set 125 var ret = jQuery.merge( this.constructor(), elems ); 126 127 // Add the old object onto the stack (as a reference) 128 ret.prevObject = this; 129 ret.context = this.context; 130 131 // Return the newly-formed element set 132 return ret; 133 }, 134 135 // Execute a callback for every element in the matched set. 136 each: function( callback ) { 137 return jQuery.each( this, callback ); 138 }, 139 140 map: function( callback ) { 141 return this.pushStack( jQuery.map( this, function( elem, i ) { 142 return callback.call( elem, i, elem ); 143 } ) ); 144 }, 145 146 slice: function() { 147 return this.pushStack( slice.apply( this, arguments ) ); 148 }, 149 150 first: function() { 151 return this.eq( 0 ); 152 }, 153 154 last: function() { 155 return this.eq( -1 ); 156 }, 157 158 eq: function( i ) { 159 var len = this.length, 160 j = +i + ( i < 0 ? len : 0 ); 161 return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); 162 }, 163 164 end: function() { 165 return this.prevObject || this.constructor(); 166 }, 167 168 // For internal use only. 169 // Behaves like an Array's method, not like a jQuery method. 170 push: push, 171 sort: deletedIds.sort, 172 splice: deletedIds.splice 173}; 174 175jQuery.extend = jQuery.fn.extend = function() { 176 var src, copyIsArray, copy, name, options, clone, 177 target = arguments[ 0 ] || {}, 178 i = 1, 179 length = arguments.length, 180 deep = false;
vendor: 8,863 bytes, lines 181-553
181 182 // Handle a deep copy situation 183 if ( typeof target === "boolean" ) { 184 deep = target; 185 186 // skip the boolean and the target 187 target = arguments[ i ] || {}; 188 i++; 189 } 190 191 // Handle case when target is a string or something (possible in deep copy) 192 if ( typeof target !== "object" && !jQuery.isFunction( target ) ) { 193 target = {}; 194 } 195 196 // extend jQuery itself if only one argument is passed 197 if ( i === length ) { 198 target = this; 199 i--; 200 } 201 202 for ( ; i < length; i++ ) { 203 204 // Only deal with non-null/undefined values 205 if ( ( options = arguments[ i ] ) != null ) { 206 207 // Extend the base object 208 for ( name in options ) { 209 src = target[ name ]; 210 copy = options[ name ]; 211 212 // Prevent never-ending loop 213 if ( target === copy ) { 214 continue; 215 } 216 217 // Recurse if we're merging plain objects or arrays 218 if ( deep && copy && ( jQuery.isPlainObject( copy ) || 219 ( copyIsArray = jQuery.isArray( copy ) ) ) ) { 220 221 if ( copyIsArray ) { 222 copyIsArray = false; 223 clone = src && jQuery.isArray( src ) ? src : []; 224 225 } else { 226 clone = src && jQuery.isPlainObject( src ) ? src : {}; 227 } 228 229 // Never move original objects, clone them 230 target[ name ] = jQuery.extend( deep, clone, copy ); 231 232 // Don't bring in undefined values 233 } else if ( copy !== undefined ) { 234 target[ name ] = copy; 235 } 236 } 237 } 238 } 239 240 // Return the modified object 241 return target; 242}; 243 244jQuery.extend( { 245 246 // Unique for each copy of jQuery on the page 247 expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), 248 249 // Assume jQuery is ready without the ready module 250 isReady: true, 251 252 error: function( msg ) { 253 throw new Error( msg ); 254 }, 255 256 noop: function() {}, 257 258 // See test/unit/core.js for details concerning isFunction. 259 // Since version 1.3, DOM methods and functions like alert 260 // aren't supported. They return false on IE (#2968). 261 isFunction: function( obj ) { 262 return jQuery.type( obj ) === "function"; 263 }, 264 265 isArray: Array.isArray || function( obj ) { 266 return jQuery.type( obj ) === "array"; 267 }, 268 269 isWindow: function( obj ) { 270 /* jshint eqeqeq: false */ 271 return obj != null && obj == obj.window; 272 }, 273 274 isNumeric: function( obj ) { 275 276 // parseFloat NaNs numeric-cast false positives (null|true|false|"") 277 // ...but misinterprets leading-number strings, particularly hex literals ("0x...") 278 // subtraction forces infinities to NaN 279 // adding 1 corrects loss of precision from parseFloat (#15100) 280 var realStringObj = obj && obj.toString(); 281 return !jQuery.isArray( obj ) && ( realStringObj - parseFloat( realStringObj ) + 1 ) >= 0; 282 }, 283 284 isEmptyObject: function( obj ) { 285 var name; 286 for ( name in obj ) { 287 return false; 288 } 289 return true; 290 }, 291 292 isPlainObject: function( obj ) { 293 var key; 294 295 // Must be an Object. 296 // Because of IE, we also have to check the presence of the constructor property. 297 // Make sure that DOM nodes and window objects don't pass through, as well 298 if ( !obj || jQuery.type( obj ) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { 299 return false; 300 } 301 302 try { 303 304 // Not own constructor property must be Object 305 if ( obj.constructor && 306 !hasOwn.call( obj, "constructor" ) && 307 !hasOwn.call( obj.constructor.prototype, "isPrototypeOf" ) ) { 308 return false; 309 } 310 } catch ( e ) { 311 312 // IE8,9 Will throw exceptions on certain host objects #9897 313 return false; 314 } 315 316 // Support: IE<9 317 // Handle iteration over inherited properties before own properties. 318 if ( !support.ownFirst ) { 319 for ( key in obj ) { 320 return hasOwn.call( obj, key ); 321 } 322 } 323 324 // Own properties are enumerated firstly, so to speed up, 325 // if last one is own, then all properties are own. 326 for ( key in obj ) {} 327 328 return key === undefined || hasOwn.call( obj, key ); 329 }, 330 331 type: function( obj ) { 332 if ( obj == null ) { 333 return obj + ""; 334 } 335 return typeof obj === "object" || typeof obj === "function" ? 336 class2type[ toString.call( obj ) ] || "object" : 337 typeof obj; 338 }, 339 340 // Workarounds based on findings by Jim Driscoll 341 // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context 342 globalEval: function( data ) { 343 if ( data && jQuery.trim( data ) ) { 344 345 // We use execScript on Internet Explorer 346 // We use an anonymous function so that context is window 347 // rather than jQuery in Firefox 348 ( window.execScript || function( data ) { 349 window[ "eval" ].call( window, data ); // jscs:ignore requireDotNotation 350 } )( data ); 351 } 352 }, 353 354 // Convert dashed to camelCase; used by the css and data modules 355 // Microsoft forgot to hump their vendor prefix (#9572) 356 camelCase: function( string ) { 357 return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); 358 }, 359 360 nodeName: function( elem, name ) { 361 return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); 362 }, 363 364 each: function( obj, callback ) { 365 var length, i = 0; 366 367 if ( isArrayLike( obj ) ) { 368 length = obj.length; 369 for ( ; i < length; i++ ) { 370 if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { 371 break; 372 } 373 } 374 } else { 375 for ( i in obj ) { 376 if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { 377 break; 378 } 379 } 380 } 381 382 return obj; 383 }, 384 385 // Support: Android<4.1, IE<9 386 trim: function( text ) { 387 return text == null ? 388 "" : 389 ( text + "" ).replace( rtrim, "" ); 390 }, 391 392 // results is for internal usage only 393 makeArray: function( arr, results ) { 394 var ret = results || []; 395 396 if ( arr != null ) { 397 if ( isArrayLike( Object( arr ) ) ) { 398 jQuery.merge( ret, 399 typeof arr === "string" ? 400 [ arr ] : arr 401 ); 402 } else { 403 push.call( ret, arr ); 404 } 405 } 406 407 return ret; 408 }, 409 410 inArray: function( elem, arr, i ) { 411 var len; 412 413 if ( arr ) { 414 if ( indexOf ) { 415 return indexOf.call( arr, elem, i ); 416 } 417 418 len = arr.length; 419 i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0; 420 421 for ( ; i < len; i++ ) { 422 423 // Skip accessing in sparse arrays 424 if ( i in arr && arr[ i ] === elem ) { 425 return i; 426 } 427 } 428 } 429 430 return -1; 431 }, 432 433 merge: function( first, second ) { 434 var len = +second.length, 435 j = 0, 436 i = first.length; 437 438 while ( j < len ) { 439 first[ i++ ] = second[ j++ ]; 440 } 441 442 // Support: IE<9 443 // Workaround casting of .length to NaN on otherwise arraylike objects (e.g., NodeLists) 444 if ( len !== len ) { 445 while ( second[ j ] !== undefined ) { 446 first[ i++ ] = second[ j++ ]; 447 } 448 } 449 450 first.length = i; 451 452 return first; 453 }, 454 455 grep: function( elems, callback, invert ) { 456 var callbackInverse, 457 matches = [], 458 i = 0, 459 length = elems.length, 460 callbackExpect = !invert; 461 462 // Go through the array, only saving the items 463 // that pass the validator function 464 for ( ; i < length; i++ ) { 465 callbackInverse = !callback( elems[ i ], i ); 466 if ( callbackInverse !== callbackExpect ) { 467 matches.push( elems[ i ] ); 468 } 469 } 470 471 return matches; 472 }, 473 474 // arg is for internal usage only 475 map: function( elems, callback, arg ) { 476 var length, value, 477 i = 0, 478 ret = []; 479 480 // Go through the array, translating each of the items to their new values 481 if ( isArrayLike( elems ) ) { 482 length = elems.length; 483 for ( ; i < length; i++ ) { 484 value = callback( elems[ i ], i, arg ); 485 486 if ( value != null ) { 487 ret.push( value ); 488 } 489 } 490 491 // Go through every key on the object, 492 } else { 493 for ( i in elems ) { 494 value = callback( elems[ i ], i, arg ); 495 496 if ( value != null ) { 497 ret.push( value ); 498 } 499 } 500 } 501 502 // Flatten any nested arrays 503 return concat.apply( [], ret ); 504 }, 505 506 // A global GUID counter for objects 507 guid: 1, 508 509 // Bind a function to a context, optionally partially applying any 510 // arguments. 511 proxy: function( fn, context ) { 512 var args, proxy, tmp; 513 514 if ( typeof context === "string" ) { 515 tmp = fn[ context ]; 516 context = fn; 517 fn = tmp; 518 } 519 520 // Quick check to determine if target is callable, in the spec 521 // this throws a TypeError, but we will just return undefined. 522 if ( !jQuery.isFunction( fn ) ) { 523 return undefined; 524 } 525 526 // Simulated bind 527 args = slice.call( arguments, 2 ); 528 proxy = function() { 529 return fn.apply( context || this, args.concat( slice.call( arguments ) ) ); 530 }; 531 532 // Set the guid of unique handler to the same of original handler, so it can be removed 533 proxy.guid = fn.guid = fn.guid || jQuery.guid++; 534 535 return proxy; 536 }, 537 538 now: function() { 539 return +( new Date() ); 540 }, 541 542 // jQuery.support is not used in Core but other projects attach their 543 // properties to it so it needs to exist. 544 support: support 545} ); 546 547// JSHint would error on this code due to the Symbol not being defined in ES5. 548// Defining this global in .jshintrc would create a danger of using the global 549// unguarded in another place, it seems safer to just disable JSHint for these 550// three lines. 551/* jshint ignore: start */ 552if ( typeof Symbol === "function" ) { 553 jQuery.fn[ Symbol.iterator ] = deletedIds
vendor: 63,327 bytes, lines 553-2790
553[ Symbol.iterator ]; 554} 555/* jshint ignore: end */ 556 557// Populate the class2type map 558jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), 559function( i, name ) { 560 class2type[ "[object " + name + "]" ] = name.toLowerCase(); 561} ); 562 563function isArrayLike( obj ) { 564 565 // Support: iOS 8.2 (not reproducible in simulator) 566 // `in` check used to prevent JIT error (gh-2145) 567 // hasOwn isn't used here due to false negatives 568 // regarding Nodelist length in IE 569 var length = !!obj && "length" in obj && obj.length, 570 type = jQuery.type( obj ); 571 572 if ( type === "function" || jQuery.isWindow( obj ) ) { 573 return false; 574 } 575 576 return type === "array" || length === 0 || 577 typeof length === "number" && length > 0 && ( length - 1 ) in obj; 578} 579var Sizzle = 580/*! 581 * Sizzle CSS Selector Engine v2.2.1 582 * http://sizzlejs.com/ 583 * 584 * Copyright jQuery Foundation and other contributors 585 * Released under the MIT license 586 * http://jquery.org/license 587 * 588 * Date: 2015-10-17 589 */ 590(function( window ) { 591 592var i, 593 support, 594 Expr, 595 getText, 596 isXML, 597 tokenize, 598 compile, 599 select, 600 outermostContext, 601 sortInput, 602 hasDuplicate, 603 604 // Local document vars 605 setDocument, 606 document, 607 docElem, 608 documentIsHTML, 609 rbuggyQSA, 610 rbuggyMatches, 611 matches, 612 contains, 613 614 // Instance-specific data 615 expando = "sizzle" + 1 * new Date(), 616 preferredDoc = window.document, 617 dirruns = 0, 618 done = 0, 619 classCache = createCache(), 620 tokenCache = createCache(), 621 compilerCache = createCache(), 622 sortOrder = function( a, b ) { 623 if ( a === b ) { 624 hasDuplicate = true; 625 } 626 return 0; 627 }, 628 629 // General-purpose constants 630 MAX_NEGATIVE = 1 << 31, 631 632 // Instance methods 633 hasOwn = ({}).hasOwnProperty, 634 arr = [], 635 pop = arr.pop, 636 push_native = arr.push, 637 push = arr.push, 638 slice = arr.slice, 639 // Use a stripped-down indexOf as it's faster than native 640 // http://jsperf.com/thor-indexof-vs-for/5 641 indexOf = function( list, elem ) { 642 var i = 0, 643 len = list.length; 644 for ( ; i < len; i++ ) { 645 if ( list[i] === elem ) { 646 return i; 647 } 648 } 649 return -1; 650 }, 651 652 booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", 653 654 // Regular expressions 655 656 // http://www.w3.org/TR/css3-selectors/#whitespace 657 whitespace = "[\\x20\\t\\r\\n\\f]", 658 659 // http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier 660 identifier = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+", 661 662 // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors 663 attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + 664 // Operator (capture 2) 665 "*([*^$|!~]?=)" + whitespace + 666 // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]" 667 "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace + 668 "*\\]", 669 670 pseudos = ":(" + identifier + ")(?:\\((" + 671 // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: 672 // 1. quoted (capture 3; capture 4 or capture 5) 673 "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + 674 // 2. simple (capture 6) 675 "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + 676 // 3. anything else (capture 2) 677 ".*" + 678 ")\\)|)", 679 680 // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter 681 rwhitespace = new RegExp( whitespace + "+", "g" ), 682 rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), 683 684 rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), 685 rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ), 686 687 rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ), 688 689 rpseudo = new RegExp( pseudos ), 690 ridentifier = new RegExp( "^" + identifier + "$" ), 691 692 matchExpr = { 693 "ID": new RegExp( "^#(" + identifier + ")" ), 694 "CLASS": new RegExp( "^\\.(" + identifier + ")" ), 695 "TAG": new RegExp( "^(" + identifier + "|[*])" ), 696 "ATTR": new RegExp( "^" + attributes ), 697 "PSEUDO": new RegExp( "^" + pseudos ), 698 "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + 699 "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + 700 "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), 701 "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), 702 // For use in libraries implementing .is() 703 // We use this for POS matching in `select` 704 "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + 705 whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) 706 }, 707 708 rinputs = /^(?:input|select|textarea|button)$/i, 709 rheader = /^h\d$/i, 710 711 rnative = /^[^{]+\{\s*\[native \w/, 712 713 // Easily-parseable/retrievable ID or TAG or CLASS selectors 714 rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, 715 716 rsibling = /[+~]/, 717 rescape = /'|\\/g, 718 719 // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters 720 runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ), 721 funescape = function( _, escaped, escapedWhitespace ) { 722 var high = "0x" + escaped - 0x10000; 723 // NaN means non-codepoint 724 // Support: Firefox<24 725 // Workaround erroneous numeric interpretation of +"0x" 726 return high !== high || escapedWhitespace ? 727 escaped : 728 high < 0 ? 729 // BMP codepoint 730 String.fromCharCode( high + 0x10000 ) : 731 // Supplemental Plane codepoint (surrogate pair) 732 String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); 733 }, 734 735 // Used for iframes 736 // See setDocument() 737 // Removing the function wrapper causes a "Permission Denied" 738 // error in IE 739 unloadHandler = function() { 740 setDocument(); 741 }; 742 743// Optimize for push.apply( _, NodeList ) 744try { 745 push.apply( 746 (arr = slice.call( preferredDoc.childNodes )), 747 preferredDoc.childNodes 748 ); 749 // Support: Android<4.0 750 // Detect silently failing push.apply 751 arr[ preferredDoc.childNodes.length ].nodeType; 752} catch ( e ) { 753 push = { apply: arr.length ? 754 755 // Leverage slice if possible 756 function( target, els ) { 757 push_native.apply( target, slice.call(els) ); 758 } : 759 760 // Support: IE<9 761 // Otherwise append directly 762 function( target, els ) { 763 var j = target.length, 764 i = 0; 765 // Can't trust NodeList.length 766 while ( (target[j++] = els[i++]) ) {} 767 target.length = j - 1; 768 } 769 }; 770} 771 772function Sizzle( selector, context, results, seed ) { 773 var m, i, elem, nid, nidselect, match, groups, newSelector, 774 newContext = context && context.ownerDocument, 775 776 // nodeType defaults to 9, since context defaults to document 777 nodeType = context ? context.nodeType : 9; 778 779 results = results || []; 780 781 // Return early from calls with invalid selector or context 782 if ( typeof selector !== "string" || !selector || 783 nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { 784 785 return results; 786 } 787 788 // Try to shortcut find operations (as opposed to filters) in HTML documents 789 if ( !seed ) { 790 791 if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { 792 setDocument( context ); 793 } 794 context = context || document; 795 796 if ( documentIsHTML ) { 797 798 // If the selector is sufficiently simple, try using a "get*By*" DOM method 799 // (excepting DocumentFragment context, where the methods don't exist) 800 if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) { 801 802 // ID selector 803 if ( (m = match[1]) ) { 804 805 // Document context 806 if ( nodeType === 9 ) { 807 if ( (elem = context.getElementById( m )) ) { 808 809 // Support: IE, Opera, Webkit 810 // TODO: identify versions 811 // getElementById can match elements by name instead of ID 812 if ( elem.id === m ) { 813 results.push( elem ); 814 return results; 815 } 816 } else { 817 return results; 818 } 819 820 // Element context 821 } else { 822 823 // Support: IE, Opera, Webkit 824 // TODO: identify versions 825 // getElementById can match elements by name instead of ID 826 if ( newContext && (elem = newContext.getElementById( m )) && 827 contains( context, elem ) && 828 elem.id === m ) { 829 830 results.push( elem ); 831 return results; 832 } 833 } 834 835 // Type selector 836 } else if ( match[2] ) { 837 push.apply( results, context.getElementsByTagName( selector ) ); 838 return results; 839 840 // Class selector 841 } else if ( (m = match[3]) && support.getElementsByClassName && 842 context.getElementsByClassName ) { 843 844 push.apply( results, context.getElementsByClassName( m ) ); 845 return results; 846 } 847 } 848 849 // Take advantage of querySelectorAll 850 if ( support.qsa && 851 !compilerCache[ selector + " " ] && 852 (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { 853 854 if ( nodeType !== 1 ) { 855 newContext = context; 856 newSelector = selector; 857 858 // qSA looks outside Element context, which is not what we want 859 // Thanks to Andrew Dupont for this workaround technique 860 // Support: IE <=8 861 // Exclude object elements 862 } else if ( context.nodeName.toLowerCase() !== "object" ) { 863 864 // Capture the context ID, setting it first if necessary 865 if ( (nid = context.getAttribute( "id" )) ) { 866 nid = nid.replace( rescape, "\\$&" ); 867 } else { 868 context.setAttribute( "id", (nid = expando) ); 869 } 870 871 // Prefix every selector in the list 872 groups = tokenize( selector ); 873 i = groups.length; 874 nidselect = ridentifier.test( nid ) ? "#" + nid : "[id='" + nid + "']"; 875 while ( i-- ) { 876 groups[i] = nidselect + " " + toSelector( groups[i] ); 877 } 878 newSelector = groups.join( "," ); 879 880 // Expand context for sibling selectors 881 newContext = rsibling.test( selector ) && testContext( context.parentNode ) || 882 context; 883 } 884 885 if ( newSelector ) { 886 try { 887 push.apply( results, 888 newContext.querySelectorAll( newSelector ) 889 ); 890 return results; 891 } catch ( qsaError ) { 892 } finally { 893 if ( nid === expando ) { 894 context.removeAttribute( "id" ); 895 } 896 } 897 } 898 } 899 } 900 } 901 902 // All others 903 return select( selector.replace( rtrim, "$1" ), context, results, seed ); 904} 905 906/** 907 * Create key-value caches of limited size 908 * @returns {function(string, object)} Returns the Object data after storing it on itself with 909 * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) 910 * deleting the oldest entry 911 */ 912function createCache() { 913 var keys = []; 914 915 function cache( key, value ) { 916 // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) 917 if ( keys.push( key + " " ) > Expr.cacheLength ) { 918 // Only keep the most recent entries 919 delete cache[ keys.shift() ]; 920 } 921 return (cache[ key + " " ] = value); 922 } 923 return cache; 924} 925 926/** 927 * Mark a function for special use by Sizzle 928 * @param {Function} fn The function to mark 929 */ 930function markFunction( fn ) { 931 fn[ expando ] = true; 932 return fn; 933} 934 935/** 936 * Support testing using an element 937 * @param {Function} fn Passed the created div and expects a boolean result 938 */ 939function assert( fn ) { 940 var div = document.createElement("div"); 941 942 try { 943 return !!fn( div ); 944 } catch (e) { 945 return false; 946 } finally { 947 // Remove from its parent by default 948 if ( div.parentNode ) { 949 div.parentNode.removeChild( div ); 950 } 951 // release memory in IE 952 div = null; 953 } 954} 955 956/** 957 * Adds the same handler for all of the specified attrs 958 * @param {String} attrs Pipe-separated list of attributes 959 * @param {Function} handler The method that will be applied 960 */ 961function addHandle( attrs, handler ) { 962 var arr = attrs.split("|"), 963 i = arr.length; 964 965 while ( i-- ) { 966 Expr.attrHandle[ arr[i] ] = handler; 967 } 968} 969 970/** 971 * Checks document order of two siblings 972 * @param {Element} a 973 * @param {Element} b 974 * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b 975 */ 976function siblingCheck( a, b ) { 977 var cur = b && a, 978 diff = cur && a.nodeType === 1 && b.nodeType === 1 && 979 ( ~b.sourceIndex || MAX_NEGATIVE ) - 980 ( ~a.sourceIndex || MAX_NEGATIVE ); 981 982 // Use IE sourceIndex if available on both nodes 983 if ( diff ) { 984 return diff; 985 } 986 987 // Check if b follows a 988 if ( cur ) { 989 while ( (cur = cur.nextSibling) ) { 990 if ( cur === b ) { 991 return -1; 992 } 993 } 994 } 995 996 return a ? 1 : -1; 997} 998 999/** 1000 * Returns a function to use in pseudos for input types 1001 * @param {String} type 1002 */ 1003function createInputPseudo( type ) { 1004 return function( elem ) { 1005 var name = elem.nodeName.toLowerCase(); 1006 return name === "input" && elem.type === type; 1007 }; 1008} 1009 1010/** 1011 * Returns a function to use in pseudos for buttons 1012 * @param {String} type 1013 */ 1014function createButtonPseudo( type ) { 1015 return function( elem ) { 1016 var name = elem.nodeName.toLowerCase(); 1017 return (name === "input" || name === "button") && elem.type === type; 1018 }; 1019} 1020 1021/** 1022 * Returns a function to use in pseudos for positionals 1023 * @param {Function} fn 1024 */ 1025function createPositionalPseudo( fn ) { 1026 return markFunction(function( argument ) { 1027 argument = +argument; 1028 return markFunction(function( seed, matches ) { 1029 var j, 1030 matchIndexes = fn( [], seed.length, argument ), 1031 i = matchIndexes.length; 1032 1033 // Match elements found at the specified indexes 1034 while ( i-- ) { 1035 if ( seed[ (j = matchIndexes[i]) ] ) { 1036 seed[j] = !(matches[j] = seed[j]); 1037 } 1038 } 1039 }); 1040 }); 1041} 1042 1043/** 1044 * Checks a node for validity as a Sizzle context 1045 * @param {Element|Object=} context 1046 * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value 1047 */ 1048function testContext( context ) { 1049 return context && typeof context.getElementsByTagName !== "undefined" && context; 1050} 1051 1052// Expose support vars for convenience 1053support = Sizzle.support = {}; 1054 1055/** 1056 * Detects XML nodes 1057 * @param {Element|Object} elem An element or a document 1058 * @returns {Boolean} True iff elem is a non-HTML XML node 1059 */ 1060isXML = Sizzle.isXML = function( elem ) { 1061 // documentElement is verified for cases where it doesn't yet exist 1062 // (such as loading iframes in IE - #4833) 1063 var documentElement = elem && (elem.ownerDocument || elem).documentElement; 1064 return documentElement ? documentElement.nodeName !== "HTML" : false; 1065}; 1066 1067/** 1068 * Sets document-related variables once based on the current document 1069 * @param {Element|Object} [doc] An element or document object to use to set the document 1070 * @returns {Object} Returns the current document 1071 */ 1072setDocument = Sizzle.setDocument = function( node ) { 1073 var hasCompare, parent, 1074 doc = node ? node.ownerDocument || node : preferredDoc; 1075 1076 // Return early if doc is invalid or already selected 1077 if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { 1078 return document; 1079 } 1080 1081 // Update global variables 1082 document = doc; 1083 docElem = document.documentElement; 1084 documentIsHTML = !isXML( document ); 1085 1086 // Support: IE 9-11, Edge 1087 // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) 1088 if ( (parent = document.defaultView) && parent.top !== parent ) { 1089 // Support: IE 11 1090 if ( parent.addEventListener ) { 1091 parent.addEventListener( "unload", unloadHandler, false ); 1092 1093 // Support: IE 9 - 10 only 1094 } else if ( parent.attachEvent ) { 1095 parent.attachEvent( "onunload", unloadHandler ); 1096 } 1097 } 1098 1099 /* Attributes 1100 ---------------------------------------------------------------------- */ 1101 1102 // Support: IE<8 1103 // Verify that getAttribute really returns attributes and not properties 1104 // (excepting IE8 booleans) 1105 support.attributes = assert(function( div ) { 1106 div.className = "i"; 1107 return !div.getAttribute("className"); 1108 }); 1109 1110 /* getElement(s)By* 1111 ---------------------------------------------------------------------- */ 1112 1113 // Check if getElementsByTagName("*") returns only elements 1114 support.getElementsByTagName = assert(function( div ) { 1115 div.appendChild( document.createComment("") ); 1116 return !div.getElementsByTagName("*").length; 1117 }); 1118 1119 // Support: IE<9 1120 support.getElementsByClassName = rnative.test( document.getElementsByClassName ); 1121 1122 // Support: IE<10 1123 // Check if getElementById returns elements by name 1124 // The broken getElementById methods don't pick up programatically-set names, 1125 // so use a roundabout getElementsByName test 1126 support.getById = assert(function( div ) { 1127 docElem.appendChild( div ).id = expando; 1128 return !document.getElementsByName || !document.getElementsByName( expando ).length; 1129 }); 1130 1131 // ID find and filter 1132 if ( support.getById ) { 1133 Expr.find["ID"] = function( id, context ) { 1134 if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { 1135 var m = context.getElementById( id ); 1136 return m ? [ m ] : []; 1137 } 1138 }; 1139 Expr.filter["ID"] = function( id ) { 1140 var attrId = id.replace( runescape, funescape ); 1141 return function( elem ) { 1142 return elem.getAttribute("id") === attrId; 1143 }; 1144 }; 1145 } else { 1146 // Support: IE6/7 1147 // getElementById is not reliable as a find shortcut 1148 delete Expr.find["ID"]; 1149 1150 Expr.filter["ID"] = function( id ) { 1151 var attrId = id.replace( runescape, funescape ); 1152 return function( elem ) { 1153 var node = typeof elem.getAttributeNode !== "undefined" && 1154 elem.getAttributeNode("id"); 1155 return node && node.value === attrId; 1156 }; 1157 }; 1158 } 1159 1160 // Tag 1161 Expr.find["TAG"] = support.getElementsByTagName ? 1162 function( tag, context ) { 1163 if ( typeof context.getElementsByTagName !== "undefined" ) { 1164 return context.getElementsByTagName( tag ); 1165 1166 // DocumentFragment nodes don't have gEBTN 1167 } else if ( support.qsa ) { 1168 return context.querySelectorAll( tag ); 1169 } 1170 } : 1171 1172 function( tag, context ) { 1173 var elem, 1174 tmp = [], 1175 i = 0, 1176 // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too 1177 results = context.getElementsByTagName( tag ); 1178 1179 // Filter out possible comments 1180 if ( tag === "*" ) { 1181 while ( (elem = results[i++]) ) { 1182 if ( elem.nodeType === 1 ) { 1183 tmp.push( elem ); 1184 } 1185 } 1186 1187 return tmp; 1188 } 1189 return results; 1190 }; 1191 1192 // Class 1193 Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) { 1194 if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { 1195 return context.getElementsByClassName( className ); 1196 } 1197 }; 1198 1199 /* QSA/matchesSelector 1200 ---------------------------------------------------------------------- */ 1201 1202 // QSA and matchesSelector support 1203 1204 // matchesSelector(:active) reports false when true (IE9/Opera 11.5) 1205 rbuggyMatches = []; 1206 1207 // qSa(:focus) reports false when true (Chrome 21) 1208 // We allow this because of a bug in IE8/9 that throws an error 1209 // whenever `document.activeElement` is accessed on an iframe 1210 // So, we allow :focus to pass through QSA all the time to avoid the IE error 1211 // See http://bugs.jquery.com/ticket/13378 1212 rbuggyQSA = []; 1213 1214 if ( (support.qsa = rnative.test( document.querySelectorAll )) ) { 1215 // Build QSA regex 1216 // Regex strategy adopted from Diego Perini 1217 assert(function( div ) { 1218 // Select is set to empty string on purpose 1219 // This is to test IE's treatment of not explicitly 1220 // setting a boolean content attribute, 1221 // since its presence should be enough 1222 // http://bugs.jquery.com/ticket/12359 1223 docElem.appendChild( div ).innerHTML = "<a id='" + expando + "'></a>" + 1224 "<select id='" + expando + "-\r\\' msallowcapture=''>" + 1225 "<option selected=''></option></select>"; 1226 1227 // Support: IE8, Opera 11-12.16 1228 // Nothing should be selected when empty strings follow ^= or $= or *= 1229 // The test attribute must be unknown in Opera but "safe" for WinRT 1230 // http://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section 1231 if ( div.querySelectorAll("[msallowcapture^='']").length ) { 1232 rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); 1233 } 1234 1235 // Support: IE8 1236 // Boolean attributes and "value" are not treated correctly 1237 if ( !div.querySelectorAll("[selected]").length ) { 1238 rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); 1239 } 1240 1241 // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ 1242 if ( !div.querySelectorAll( "[id~=" + expando + "-]" ).length ) { 1243 rbuggyQSA.push("~="); 1244 } 1245 1246 // Webkit/Opera - :checked should return selected option elements 1247 // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked 1248 // IE8 throws error here and will not see later tests 1249 if ( !div.querySelectorAll(":checked").length ) { 1250 rbuggyQSA.push(":checked"); 1251 } 1252 1253 // Support: Safari 8+, iOS 8+ 1254 // https://bugs.webkit.org/show_bug.cgi?id=136851 1255 // In-page `selector#id sibing-combinator selector` fails 1256 if ( !div.querySelectorAll( "a#" + expando + "+*" ).length ) { 1257 rbuggyQSA.push(".#.+[+~]"); 1258 } 1259 }); 1260 1261 assert(function( div ) { 1262 // Support: Windows 8 Native Apps 1263 // The type and name attributes are restricted during .innerHTML assignment 1264 var input = document.createElement("input"); 1265 input.setAttribute( "type", "hidden" ); 1266 div.appendChild( input ).setAttribute( "name", "D" ); 1267 1268 // Support: IE8 1269 // Enforce case-sensitivity of name attribute 1270 if ( div.querySelectorAll("[name=d]").length ) { 1271 rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); 1272 } 1273 1274 // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) 1275 // IE8 throws error here and will not see later tests 1276 if ( !div.querySelectorAll(":enabled").length ) { 1277 rbuggyQSA.push( ":enabled", ":disabled" ); 1278 } 1279 1280 // Opera 10-11 does not throw on post-comma invalid pseudos 1281 div.querySelectorAll("*,:x"); 1282 rbuggyQSA.push(",.*:"); 1283 }); 1284 } 1285 1286 if ( (support.matchesSelector = rnative.test( (matches = docElem.matches || 1287 docElem.webkitMatchesSelector || 1288 docElem.mozMatchesSelector || 1289 docElem.oMatchesSelector || 1290 docElem.msMatchesSelector) )) ) { 1291 1292 assert(function( div ) { 1293 // Check to see if it's possible to do matchesSelector 1294 // on a disconnected node (IE 9) 1295 support.disconnectedMatch = matches.call( div, "div" ); 1296 1297 // This should fail with an exception 1298 // Gecko does not error, returns false instead 1299 matches.call( div, "[s!='']:x" ); 1300 rbuggyMatches.push( "!=", pseudos ); 1301 }); 1302 } 1303 1304 rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") ); 1305 rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") ); 1306 1307 /* Contains 1308 ---------------------------------------------------------------------- */ 1309 hasCompare = rnative.test( docElem.compareDocumentPosition ); 1310 1311 // Element contains another 1312 // Purposefully self-exclusive 1313 // As in, an element does not contain itself 1314 contains = hasCompare || rnative.test( docElem.contains ) ? 1315 function( a, b ) { 1316 var adown = a.nodeType === 9 ? a.documentElement : a, 1317 bup = b && b.parentNode; 1318 return a === bup || !!( bup && bup.nodeType === 1 && ( 1319 adown.contains ? 1320 adown.contains( bup ) : 1321 a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 1322 )); 1323 } : 1324 function( a, b ) { 1325 if ( b ) { 1326 while ( (b = b.parentNode) ) { 1327 if ( b === a ) { 1328 return true; 1329 } 1330 } 1331 } 1332 return false; 1333 }; 1334 1335 /* Sorting 1336 ---------------------------------------------------------------------- */ 1337 1338 // Document order sorting 1339 sortOrder = hasCompare ? 1340 function( a, b ) { 1341 1342 // Flag for duplicate removal 1343 if ( a === b ) { 1344 hasDuplicate = true; 1345 return 0; 1346 } 1347 1348 // Sort on method existence if only one input has compareDocumentPosition 1349 var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; 1350 if ( compare ) { 1351 return compare; 1352 } 1353 1354 // Calculate position if both inputs belong to the same document 1355 compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ? 1356 a.compareDocumentPosition( b ) : 1357 1358 // Otherwise we know they are disconnected 1359 1; 1360 1361 // Disconnected nodes 1362 if ( compare & 1 || 1363 (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) { 1364 1365 // Choose the first element that is related to our preferred document 1366 if ( a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) { 1367 return -1; 1368 } 1369 if ( b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) { 1370 return 1; 1371 } 1372 1373 // Maintain original order 1374 return sortInput ? 1375 ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : 1376 0; 1377 } 1378 1379 return compare & 4 ? -1 : 1; 1380 } : 1381 function( a, b ) { 1382 // Exit early if the nodes are identical 1383 if ( a === b ) { 1384 hasDuplicate = true; 1385 return 0; 1386 } 1387 1388 var cur, 1389 i = 0, 1390 aup = a.parentNode, 1391 bup = b.parentNode, 1392 ap = [ a ], 1393 bp = [ b ]; 1394 1395 // Parentless nodes are either documents or disconnected 1396 if ( !aup || !bup ) { 1397 return a === document ? -1 : 1398 b === document ? 1 : 1399 aup ? -1 : 1400 bup ? 1 : 1401 sortInput ? 1402 ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : 1403 0; 1404 1405 // If the nodes are siblings, we can do a quick check 1406 } else if ( aup === bup ) { 1407 return siblingCheck( a, b ); 1408 } 1409 1410 // Otherwise we need full lists of their ancestors for comparison 1411 cur = a; 1412 while ( (cur = cur.parentNode) ) { 1413 ap.unshift( cur ); 1414 } 1415 cur = b; 1416 while ( (cur = cur.parentNode) ) { 1417 bp.unshift( cur ); 1418 } 1419 1420 // Walk down the tree looking for a discrepancy 1421 while ( ap[i] === bp[i] ) { 1422 i++; 1423 } 1424 1425 return i ? 1426 // Do a sibling check if the nodes have a common ancestor 1427 siblingCheck( ap[i], bp[i] ) : 1428 1429 // Otherwise nodes in our document sort first 1430 ap[i] === preferredDoc ? -1 : 1431 bp[i] === preferredDoc ? 1 : 1432 0; 1433 }; 1434 1435 return document; 1436}; 1437 1438Sizzle.matches = function( expr, elements ) { 1439 return Sizzle( expr, null, null, elements ); 1440}; 1441 1442Sizzle.matchesSelector = function( elem, expr ) { 1443 // Set document vars if needed 1444 if ( ( elem.ownerDocument || elem ) !== document ) { 1445 setDocument( elem ); 1446 } 1447 1448 // Make sure that attribute selectors are quoted 1449 expr = expr.replace( rattributeQuotes, "='$1']" ); 1450 1451 if ( support.matchesSelector && documentIsHTML && 1452 !compilerCache[ expr + " " ] && 1453 ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && 1454 ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { 1455 1456 try { 1457 var ret = matches.call( elem, expr ); 1458 1459 // IE 9's matchesSelector returns false on disconnected nodes 1460 if ( ret || support.disconnectedMatch || 1461 // As well, disconnected nodes are said to be in a document 1462 // fragment in IE 9 1463 elem.document && elem.document.nodeType !== 11 ) { 1464 return ret; 1465 } 1466 } catch (e) {} 1467 } 1468 1469 return Sizzle( expr, document, null, [ elem ] ).length > 0; 1470}; 1471 1472Sizzle.contains = function( context, elem ) { 1473 // Set document vars if needed 1474 if ( ( context.ownerDocument || context ) !== document ) { 1475 setDocument( context ); 1476 } 1477 return contains( context, elem ); 1478}; 1479 1480Sizzle.attr = function( elem, name ) { 1481 // Set document vars if needed 1482 if ( ( elem.ownerDocument || elem ) !== document ) { 1483 setDocument( elem ); 1484 } 1485 1486 var fn = Expr.attrHandle[ name.toLowerCase() ], 1487 // Don't get fooled by Object.prototype properties (jQuery #13807) 1488 val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? 1489 fn( elem, name, !documentIsHTML ) : 1490 undefined; 1491 1492 return val !== undefined ? 1493 val : 1494 support.attributes || !documentIsHTML ? 1495 elem.getAttribute( name ) : 1496 (val = elem.getAttributeNode(name)) && val.specified ? 1497 val.value : 1498 null; 1499}; 1500 1501Sizzle.error = function( msg ) { 1502 throw new Error( "Syntax error, unrecognized expression: " + msg ); 1503}; 1504 1505/** 1506 * Document sorting and removing duplicates 1507 * @param {ArrayLike} results 1508 */ 1509Sizzle.uniqueSort = function( results ) { 1510 var elem, 1511 duplicates = [], 1512 j = 0, 1513 i = 0; 1514 1515 // Unless we *know* we can detect duplicates, assume their presence 1516 hasDuplicate = !support.detectDuplicates; 1517 sortInput = !support.sortStable && results.slice( 0 ); 1518 results.sort( sortOrder ); 1519 1520 if ( hasDuplicate ) { 1521 while ( (elem = results[i++]) ) { 1522 if ( elem === results[ i ] ) { 1523 j = duplicates.push( i ); 1524 } 1525 } 1526 while ( j-- ) { 1527 results.splice( duplicates[ j ], 1 ); 1528 } 1529 } 1530 1531 // Clear input after sorting to release objects 1532 // See https://github.com/jquery/sizzle/pull/225 1533 sortInput = null; 1534 1535 return results; 1536}; 1537 1538/** 1539 * Utility function for retrieving the text value of an array of DOM nodes 1540 * @param {Array|Element} elem 1541 */ 1542getText = Sizzle.getText = function( elem ) { 1543 var node, 1544 ret = "", 1545 i = 0, 1546 nodeType = elem.nodeType; 1547 1548 if ( !nodeType ) { 1549 // If no nodeType, this is expected to be an array 1550 while ( (node = elem[i++]) ) { 1551 // Do not traverse comment nodes 1552 ret += getText( node ); 1553 } 1554 } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { 1555 // Use textContent for elements 1556 // innerText usage removed for consistency of new lines (jQuery #11153) 1557 if ( typeof elem.textContent === "string" ) { 1558 return elem.textContent; 1559 } else { 1560 // Traverse its children 1561 for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { 1562 ret += getText( elem ); 1563 } 1564 } 1565 } else if ( nodeType === 3 || nodeType === 4 ) { 1566 return elem.nodeValue; 1567 } 1568 // Do not include comment or processing instruction nodes 1569 1570 return ret; 1571}; 1572 1573Expr = Sizzle.selectors = { 1574 1575 // Can be adjusted by the user 1576 cacheLength: 50, 1577 1578 createPseudo: markFunction, 1579 1580 match: matchExpr, 1581 1582 attrHandle: {}, 1583 1584 find: {}, 1585 1586 relative: { 1587 ">": { dir: "parentNode", first: true }, 1588 " ": { dir: "parentNode" }, 1589 "+": { dir: "previousSibling", first: true }, 1590 "~": { dir: "previousSibling" } 1591 }, 1592 1593 preFilter: { 1594 "ATTR": function( match ) { 1595 match[1] = match[1].replace( runescape, funescape ); 1596 1597 // Move the given value to match[3] whether quoted or unquoted 1598 match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape ); 1599 1600 if ( match[2] === "~=" ) { 1601 match[3] = " " + match[3] + " "; 1602 } 1603 1604 return match.slice( 0, 4 ); 1605 }, 1606 1607 "CHILD": function( match ) { 1608 /* matches from matchExpr["CHILD"] 1609 1 type (only|nth|...) 1610 2 what (child|of-type) 1611 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) 1612 4 xn-component of xn+y argument ([+-]?\d*n|) 1613 5 sign of xn-component 1614 6 x of xn-component 1615 7 sign of y-component 1616 8 y of y-component 1617 */ 1618 match[1] = match[1].toLowerCase(); 1619 1620 if ( match[1].slice( 0, 3 ) === "nth" ) { 1621 // nth-* requires argument 1622 if ( !match[3] ) { 1623 Sizzle.error( match[0] ); 1624 } 1625 1626 // numeric x and y parameters for Expr.filter.CHILD 1627 // remember that false/true cast respectively to 0/1 1628 match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) ); 1629 match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" ); 1630 1631 // other types prohibit arguments 1632 } else if ( match[3] ) { 1633 Sizzle.error( match[0] ); 1634 } 1635 1636 return match; 1637 }, 1638 1639 "PSEUDO": function( match ) { 1640 var excess, 1641 unquoted = !match[6] && match[2]; 1642 1643 if ( matchExpr["CHILD"].test( match[0] ) ) { 1644 return null; 1645 } 1646 1647 // Accept quoted arguments as-is 1648 if ( match[3] ) { 1649 match[2] = match[4] || match[5] || ""; 1650 1651 // Strip excess characters from unquoted arguments 1652 } else if ( unquoted && rpseudo.test( unquoted ) && 1653 // Get excess from tokenize (recursively) 1654 (excess = tokenize( unquoted, true )) && 1655 // advance to the next closing parenthesis 1656 (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { 1657 1658 // excess is a negative index 1659 match[0] = match[0].slice( 0, excess ); 1660 match[2] = unquoted.slice( 0, excess ); 1661 } 1662 1663 // Return only captures needed by the pseudo filter method (type and argument) 1664 return match.slice( 0, 3 ); 1665 } 1666 }, 1667 1668 filter: { 1669 1670 "TAG": function( nodeNameSelector ) { 1671 var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); 1672 return nodeNameSelector === "*" ? 1673 function() { return true; } : 1674 function( elem ) { 1675 return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; 1676 }; 1677 }, 1678 1679 "CLASS": function( className ) { 1680 var pattern = classCache[ className + " " ]; 1681 1682 return pattern || 1683 (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && 1684 classCache( className, function( elem ) { 1685 return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "" ); 1686 }); 1687 }, 1688 1689 "ATTR": function( name, operator, check ) { 1690 return function( elem ) { 1691 var result = Sizzle.attr( elem, name ); 1692 1693 if ( result == null ) { 1694 return operator === "!="; 1695 } 1696 if ( !operator ) { 1697 return true; 1698 } 1699 1700 result += ""; 1701 1702 return operator === "=" ? result === check : 1703 operator === "!=" ? result !== check : 1704 operator === "^=" ? check && result.indexOf( check ) === 0 : 1705 operator === "*=" ? check && result.indexOf( check ) > -1 : 1706 operator === "$=" ? check && result.slice( -check.length ) === check : 1707 operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : 1708 operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : 1709 false; 1710 }; 1711 }, 1712 1713 "CHILD": function( type, what, argument, first, last ) { 1714 var simple = type.slice( 0, 3 ) !== "nth", 1715 forward = type.slice( -4 ) !== "last", 1716 ofType = what === "of-type"; 1717 1718 return first === 1 && last === 0 ? 1719 1720 // Shortcut for :nth-*(n) 1721 function( elem ) { 1722 return !!elem.parentNode; 1723 } : 1724 1725 function( elem, context, xml ) { 1726 var cache, uniqueCache, outerCache, node, nodeIndex, start, 1727 dir = simple !== forward ? "nextSibling" : "previousSibling", 1728 parent = elem.parentNode, 1729 name = ofType && elem.nodeName.toLowerCase(), 1730 useCache = !xml && !ofType, 1731 diff = false; 1732 1733 if ( parent ) { 1734 1735 // :(first|last|only)-(child|of-type) 1736 if ( simple ) { 1737 while ( dir ) { 1738 node = elem; 1739 while ( (node = node[ dir ]) ) { 1740 if ( ofType ? 1741 node.nodeName.toLowerCase() === name : 1742 node.nodeType === 1 ) { 1743 1744 return false; 1745 } 1746 } 1747 // Reverse direction for :only-* (if we haven't yet done so) 1748 start = dir = type === "only" && !start && "nextSibling"; 1749 } 1750 return true; 1751 } 1752 1753 start = [ forward ? parent.firstChild : parent.lastChild ]; 1754 1755 // non-xml :nth-child(...) stores cache data on `parent` 1756 if ( forward && useCache ) { 1757 1758 // Seek `elem` from a previously-cached index 1759 1760 // ...in a gzip-friendly way 1761 node = parent; 1762 outerCache = node[ expando ] || (node[ expando ] = {}); 1763 1764 // Support: IE <9 only 1765 // Defend against cloned attroperties (jQuery gh-1709) 1766 uniqueCache = outerCache[ node.uniqueID ] || 1767 (outerCache[ node.uniqueID ] = {}); 1768 1769 cache = uniqueCache[ type ] || []; 1770 nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; 1771 diff = nodeIndex && cache[ 2 ]; 1772 node = nodeIndex && parent.childNodes[ nodeIndex ]; 1773 1774 while ( (node = ++nodeIndex && node && node[ dir ] || 1775 1776 // Fallback to seeking `elem` from the start 1777 (diff = nodeIndex = 0) || start.pop()) ) { 1778 1779 // When found, cache indexes on `parent` and break 1780 if ( node.nodeType === 1 && ++diff && node === elem ) { 1781 uniqueCache[ type ] = [ dirruns, nodeIndex, diff ]; 1782 break; 1783 } 1784 } 1785 1786 } else { 1787 // Use previously-cached element index if available 1788 if ( useCache ) { 1789 // ...in a gzip-friendly way 1790 node = elem; 1791 outerCache = node[ expando ] || (node[ expando ] = {}); 1792 1793 // Support: IE <9 only 1794 // Defend against cloned attroperties (jQuery gh-1709) 1795 uniqueCache = outerCache[ node.uniqueID ] || 1796 (outerCache[ node.uniqueID ] = {}); 1797 1798 cache = uniqueCache[ type ] || []; 1799 nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; 1800 diff = nodeIndex; 1801 } 1802 1803 // xml :nth-child(...) 1804 // or :nth-last-child(...) or :nth(-last)?-of-type(...) 1805 if ( diff === false ) { 1806 // Use the same loop as above to seek `elem` from the start 1807 while ( (node = ++nodeIndex && node && node[ dir ] || 1808 (diff = nodeIndex = 0) || start.pop()) ) { 1809 1810 if ( ( ofType ? 1811 node.nodeName.toLowerCase() === name : 1812 node.nodeType === 1 ) && 1813 ++diff ) { 1814 1815 // Cache the index of each encountered element 1816 if ( useCache ) { 1817 outerCache = node[ expando ] || (node[ expando ] = {}); 1818 1819 // Support: IE <9 only 1820 // Defend against cloned attroperties (jQuery gh-1709) 1821 uniqueCache = outerCache[ node.uniqueID ] || 1822 (outerCache[ node.uniqueID ] = {}); 1823 1824 uniqueCache[ type ] = [ dirruns, diff ]; 1825 } 1826 1827 if ( node === elem ) { 1828 break; 1829 } 1830 } 1831 } 1832 } 1833 } 1834 1835 // Incorporate the offset, then check against cycle size 1836 diff -= last; 1837 return diff === first || ( diff % first === 0 && diff / first >= 0 ); 1838 } 1839 }; 1840 }, 1841 1842 "PSEUDO": function( pseudo, argument ) { 1843 // pseudo-class names are case-insensitive 1844 // http://www.w3.org/TR/selectors/#pseudo-classes 1845 // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters 1846 // Remember that setFilters inherits from pseudos 1847 var args, 1848 fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || 1849 Sizzle.error( "unsupported pseudo: " + pseudo ); 1850 1851 // The user may use createPseudo to indicate that 1852 // arguments are needed to create the filter function 1853 // just as Sizzle does 1854 if ( fn[ expando ] ) { 1855 return fn( argument ); 1856 } 1857 1858 // But maintain support for old signatures 1859 if ( fn.length > 1 ) { 1860 args = [ pseudo, pseudo, "", argument ]; 1861 return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? 1862 markFunction(function( seed, matches ) { 1863 var idx, 1864 matched = fn( seed, argument ), 1865 i = matched.length; 1866 while ( i-- ) { 1867 idx = indexOf( seed, matched[i] ); 1868 seed[ idx ] = !( matches[ idx ] = matched[i] ); 1869 } 1870 }) : 1871 function( elem ) { 1872 return fn( elem, 0, args ); 1873 }; 1874 } 1875 1876 return fn; 1877 } 1878 }, 1879 1880 pseudos: { 1881 // Potentially complex pseudos 1882 "not": markFunction(function( selector ) { 1883 // Trim the selector passed to compile 1884 // to avoid treating leading and trailing 1885 // spaces as combinators 1886 var input = [], 1887 results = [], 1888 matcher = compile( selector.replace( rtrim, "$1" ) ); 1889 1890 return matcher[ expando ] ? 1891 markFunction(function( seed, matches, context, xml ) { 1892 var elem, 1893 unmatched = matcher( seed, null, xml, [] ), 1894 i = seed.length; 1895 1896 // Match elements unmatched by `matcher` 1897 while ( i-- ) { 1898 if ( (elem = unmatched[i]) ) { 1899 seed[i] = !(matches[i] = elem); 1900 } 1901 } 1902 }) : 1903 function( elem, context, xml ) { 1904 input[0] = elem; 1905 matcher( input, null, xml, results ); 1906 // Don't keep the element (issue #299) 1907 input[0] = null; 1908 return !results.pop(); 1909 }; 1910 }), 1911 1912 "has": markFunction(function( selector ) { 1913 return function( elem ) { 1914 return Sizzle( selector, elem ).length > 0; 1915 }; 1916 }), 1917 1918 "contains": markFunction(function( text ) { 1919 text = text.replace( runescape, funescape ); 1920 return function( elem ) { 1921 return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; 1922 }; 1923 }), 1924 1925 // "Whether an element is represented by a :lang() selector 1926 // is based solely on the element's language value 1927 // being equal to the identifier C, 1928 // or beginning with the identifier C immediately followed by "-". 1929 // The matching of C against the element's language value is performed case-insensitively. 1930 // The identifier C does not have to be a valid language name." 1931 // http://www.w3.org/TR/selectors/#lang-pseudo 1932 "lang": markFunction( function( lang ) { 1933 // lang value must be a valid identifier 1934 if ( !ridentifier.test(lang || "") ) { 1935 Sizzle.error( "unsupported lang: " + lang ); 1936 } 1937 lang = lang.replace( runescape, funescape ).toLowerCase(); 1938 return function( elem ) { 1939 var elemLang; 1940 do { 1941 if ( (elemLang = documentIsHTML ? 1942 elem.lang : 1943 elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) { 1944 1945 elemLang = elemLang.toLowerCase(); 1946 return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; 1947 } 1948 } while ( (elem = elem.parentNode) && elem.nodeType === 1 ); 1949 return false; 1950 }; 1951 }), 1952 1953 // Miscellaneous 1954 "target": function( elem ) { 1955 var hash = window.location && window.location.hash; 1956 return hash && hash.slice( 1 ) === elem.id; 1957 }, 1958 1959 "root": function( elem ) { 1960 return elem === docElem; 1961 }, 1962 1963 "focus": function( elem ) { 1964 return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); 1965 }, 1966 1967 // Boolean properties 1968 "enabled": function( elem ) { 1969 return elem.disabled === false; 1970 }, 1971 1972 "disabled": function( elem ) { 1973 return elem.disabled === true; 1974 }, 1975 1976 "checked": function( elem ) { 1977 // In CSS3, :checked should return both checked and selected elements 1978 // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked 1979 var nodeName = elem.nodeName.toLowerCase(); 1980 return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); 1981 }, 1982 1983 "selected": function( elem ) { 1984 // Accessing this property makes selected-by-default 1985 // options in Safari work properly 1986 if ( elem.parentNode ) { 1987 elem.parentNode.selectedIndex; 1988 } 1989 1990 return elem.selected === true; 1991 }, 1992 1993 // Contents 1994 "empty": function( elem ) { 1995 // http://www.w3.org/TR/selectors/#empty-pseudo 1996 // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), 1997 // but not by others (comment: 8; processing instruction: 7; etc.) 1998 // nodeType < 6 works because attributes (2) do not appear as children 1999 for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { 2000 if ( elem.nodeType < 6 ) { 2001 return false; 2002 } 2003 } 2004 return true; 2005 }, 2006 2007 "parent": function( elem ) { 2008 return !Expr.pseudos["empty"]( elem ); 2009 }, 2010 2011 // Element/input types 2012 "header": function( elem ) { 2013 return rheader.test( elem.nodeName ); 2014 }, 2015 2016 "input": function( elem ) { 2017 return rinputs.test( elem.nodeName ); 2018 }, 2019 2020 "button": function( elem ) { 2021 var name = elem.nodeName.toLowerCase(); 2022 return name === "input" && elem.type === "button" || name === "button"; 2023 }, 2024 2025 "text": function( elem ) { 2026 var attr; 2027 return elem.nodeName.toLowerCase() === "input" && 2028 elem.type === "text" && 2029 2030 // Support: IE<8 2031 // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" 2032 ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" ); 2033 }, 2034 2035 // Position-in-collection 2036 "first": createPositionalPseudo(function() { 2037 return [ 0 ]; 2038 }), 2039 2040 "last": createPositionalPseudo(function( matchIndexes, length ) { 2041 return [ length - 1 ]; 2042 }), 2043 2044 "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { 2045 return [ argument < 0 ? argument + length : argument ]; 2046 }), 2047 2048 "even": createPositionalPseudo(function( matchIndexes, length ) { 2049 var i = 0; 2050 for ( ; i < length; i += 2 ) { 2051 matchIndexes.push( i ); 2052 } 2053 return matchIndexes; 2054 }), 2055 2056 "odd": createPositionalPseudo(function( matchIndexes, length ) { 2057 var i = 1; 2058 for ( ; i < length; i += 2 ) { 2059 matchIndexes.push( i ); 2060 } 2061 return matchIndexes; 2062 }), 2063 2064 "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { 2065 var i = argument < 0 ? argument + length : argument; 2066 for ( ; --i >= 0; ) { 2067 matchIndexes.push( i ); 2068 } 2069 return matchIndexes; 2070 }), 2071 2072 "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { 2073 var i = argument < 0 ? argument + length : argument; 2074 for ( ; ++i < length; ) { 2075 matchIndexes.push( i ); 2076 } 2077 return matchIndexes; 2078 }) 2079 } 2080}; 2081 2082Expr.pseudos["nth"] = Expr.pseudos["eq"]; 2083 2084// Add button/input type pseudos 2085for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { 2086 Expr.pseudos[ i ] = createInputPseudo( i ); 2087} 2088for ( i in { submit: true, reset: true } ) { 2089 Expr.pseudos[ i ] = createButtonPseudo( i ); 2090} 2091 2092// Easy API for creating new setFilters 2093function setFilters() {} 2094setFilters.prototype = Expr.filters = Expr.pseudos; 2095Expr.setFilters = new setFilters(); 2096 2097tokenize = Sizzle.tokenize = function( selector, parseOnly ) { 2098 var matched, match, tokens, type, 2099 soFar, groups, preFilters, 2100 cached = tokenCache[ selector + " " ]; 2101 2102 if ( cached ) { 2103 return parseOnly ? 0 : cached.slice( 0 ); 2104 } 2105 2106 soFar = selector; 2107 groups = []; 2108 preFilters = Expr.preFilter; 2109 2110 while ( soFar ) { 2111 2112 // Comma and first run 2113 if ( !matched || (match = rcomma.exec( soFar )) ) { 2114 if ( match ) { 2115 // Don't consume trailing commas as valid 2116 soFar = soFar.slice( match[0].length ) || soFar; 2117 } 2118 groups.push( (tokens = []) ); 2119 } 2120 2121 matched = false; 2122 2123 // Combinators 2124 if ( (match = rcombinators.exec( soFar )) ) { 2125 matched = match.shift(); 2126 tokens.push({ 2127 value: matched, 2128 // Cast descendant combinators to space 2129 type: match[0].replace( rtrim, " " ) 2130 }); 2131 soFar = soFar.slice( matched.length ); 2132 } 2133 2134 // Filters 2135 for ( type in Expr.filter ) { 2136 if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || 2137 (match = preFilters[ type ]( match ))) ) { 2138 matched = match.shift(); 2139 tokens.push({ 2140 value: matched, 2141 type: type, 2142 matches: match 2143 }); 2144 soFar = soFar.slice( matched.length ); 2145 } 2146 } 2147 2148 if ( !matched ) { 2149 break; 2150 } 2151 } 2152 2153 // Return the length of the invalid excess 2154 // if we're just parsing 2155 // Otherwise, throw an error or return tokens 2156 return parseOnly ? 2157 soFar.length : 2158 soFar ? 2159 Sizzle.error( selector ) : 2160 // Cache the tokens 2161 tokenCache( selector, groups ).slice( 0 ); 2162}; 2163 2164function toSelector( tokens ) { 2165 var i = 0, 2166 len = tokens.length, 2167 selector = ""; 2168 for ( ; i < len; i++ ) { 2169 selector += tokens[i].value; 2170 } 2171 return selector; 2172} 2173 2174function addCombinator( matcher, combinator, base ) { 2175 var dir = combinator.dir, 2176 checkNonElements = base && dir === "parentNode", 2177 doneName = done++; 2178 2179 return combinator.first ? 2180 // Check against closest ancestor/preceding element 2181 function( elem, context, xml ) { 2182 while ( (elem = elem[ dir ]) ) { 2183 if ( elem.nodeType === 1 || checkNonElements ) { 2184 return matcher( elem, context, xml ); 2185 } 2186 } 2187 } : 2188 2189 // Check against all ancestor/preceding elements 2190 function( elem, context, xml ) { 2191 var oldCache, uniqueCache, outerCache, 2192 newCache = [ dirruns, doneName ]; 2193 2194 // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching 2195 if ( xml ) { 2196 while ( (elem = elem[ dir ]) ) { 2197 if ( elem.nodeType === 1 || checkNonElements ) { 2198 if ( matcher( elem, context, xml ) ) { 2199 return true; 2200 } 2201 } 2202 } 2203 } else { 2204 while ( (elem = elem[ dir ]) ) { 2205 if ( elem.nodeType === 1 || checkNonElements ) { 2206 outerCache = elem[ expando ] || (elem[ expando ] = {}); 2207 2208 // Support: IE <9 only 2209 // Defend against cloned attroperties (jQuery gh-1709) 2210 uniqueCache = outerCache[ elem.uniqueID ] || (outerCache[ elem.uniqueID ] = {}); 2211 2212 if ( (oldCache = uniqueCache[ dir ]) && 2213 oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { 2214 2215 // Assign to newCache so results back-propagate to previous elements 2216 return (newCache[ 2 ] = oldCache[ 2 ]); 2217 } else { 2218 // Reuse newcache so results back-propagate to previous elements 2219 uniqueCache[ dir ] = newCache; 2220 2221 // A match means we're done; a fail means we have to keep checking 2222 if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) { 2223 return true; 2224 } 2225 } 2226 } 2227 } 2228 } 2229 }; 2230} 2231 2232function elementMatcher( matchers ) { 2233 return matchers.length > 1 ? 2234 function( elem, context, xml ) { 2235 var i = matchers.length; 2236 while ( i-- ) { 2237 if ( !matchers[i]( elem, context, xml ) ) { 2238 return false; 2239 } 2240 } 2241 return true; 2242 } : 2243 matchers[0]; 2244} 2245 2246function multipleContexts( selector, contexts, results ) { 2247 var i = 0, 2248 len = contexts.length; 2249 for ( ; i < len; i++ ) { 2250 Sizzle( selector, contexts[i], results ); 2251 } 2252 return results; 2253} 2254 2255function condense( unmatched, map, filter, context, xml ) { 2256 var elem, 2257 newUnmatched = [], 2258 i = 0, 2259 len = unmatched.length, 2260 mapped = map != null; 2261 2262 for ( ; i < len; i++ ) { 2263 if ( (elem = unmatched[i]) ) { 2264 if ( !filter || filter( elem, context, xml ) ) { 2265 newUnmatched.push( elem ); 2266 if ( mapped ) { 2267 map.push( i ); 2268 } 2269 } 2270 } 2271 } 2272 2273 return newUnmatched; 2274} 2275 2276function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { 2277 if ( postFilter && !postFilter[ expando ] ) { 2278 postFilter = setMatcher( postFilter ); 2279 } 2280 if ( postFinder && !postFinder[ expando ] ) { 2281 postFinder = setMatcher( postFinder, postSelector ); 2282 } 2283 return markFunction(function( seed, results, context, xml ) { 2284 var temp, i, elem, 2285 preMap = [], 2286 postMap = [], 2287 preexisting = results.length, 2288 2289 // Get initial elements from seed or context 2290 elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), 2291 2292 // Prefilter to get matcher input, preserving a map for seed-results synchronization 2293 matcherIn = preFilter && ( seed || !selector ) ? 2294 condense( elems, preMap, preFilter, context, xml ) : 2295 elems, 2296 2297 matcherOut = matcher ? 2298 // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, 2299 postFinder || ( seed ? preFilter : preexisting || postFilter ) ? 2300 2301 // ...intermediate processing is necessary 2302 [] : 2303 2304 // ...otherwise use results directly 2305 results : 2306 matcherIn; 2307 2308 // Find primary matches 2309 if ( matcher ) { 2310 matcher( matcherIn, matcherOut, context, xml ); 2311 } 2312 2313 // Apply postFilter 2314 if ( postFilter ) { 2315 temp = condense( matcherOut, postMap ); 2316 postFilter( temp, [], context, xml ); 2317 2318 // Un-match failing elements by moving them back to matcherIn 2319 i = temp.length; 2320 while ( i-- ) { 2321 if ( (elem = temp[i]) ) { 2322 matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); 2323 } 2324 } 2325 } 2326 2327 if ( seed ) { 2328 if ( postFinder || preFilter ) { 2329 if ( postFinder ) { 2330 // Get the final matcherOut by condensing this intermediate into postFinder contexts 2331 temp = []; 2332 i = matcherOut.length; 2333 while ( i-- ) { 2334 if ( (elem = matcherOut[i]) ) { 2335 // Restore matcherIn since elem is not yet a final match 2336 temp.push( (matcherIn[i] = elem) ); 2337 } 2338 } 2339 postFinder( null, (matcherOut = []), temp, xml ); 2340 } 2341 2342 // Move matched elements from seed to results to keep them synchronized 2343 i = matcherOut.length; 2344 while ( i-- ) { 2345 if ( (elem = matcherOut[i]) && 2346 (temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) { 2347 2348 seed[temp] = !(results[temp] = elem); 2349 } 2350 } 2351 } 2352 2353 // Add elements to results, through postFinder if defined 2354 } else { 2355 matcherOut = condense( 2356 matcherOut === results ? 2357 matcherOut.splice( preexisting, matcherOut.length ) : 2358 matcherOut 2359 ); 2360 if ( postFinder ) { 2361 postFinder( null, results, matcherOut, xml ); 2362 } else { 2363 push.apply( results, matcherOut ); 2364 } 2365 } 2366 }); 2367} 2368 2369function matcherFromTokens( tokens ) { 2370 var checkContext, matcher, j, 2371 len = tokens.length, 2372 leadingRelative = Expr.relative[ tokens[0].type ], 2373 implicitRelative = leadingRelative || Expr.relative[" "], 2374 i = leadingRelative ? 1 : 0, 2375 2376 // The foundational matcher ensures that elements are reachable from top-level context(s) 2377 matchContext = addCombinator( function( elem ) { 2378 return elem === checkContext; 2379 }, implicitRelative, true ), 2380 matchAnyContext = addCombinator( function( elem ) { 2381 return indexOf( checkContext, elem ) > -1; 2382 }, implicitRelative, true ), 2383 matchers = [ function( elem, context, xml ) { 2384 var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( 2385 (checkContext = context).nodeType ? 2386 matchContext( elem, context, xml ) : 2387 matchAnyContext( elem, context, xml ) ); 2388 // Avoid hanging onto element (issue #299) 2389 checkContext = null; 2390 return ret; 2391 } ]; 2392 2393 for ( ; i < len; i++ ) { 2394 if ( (matcher = Expr.relative[ tokens[i].type ]) ) { 2395 matchers = [ addCombinator(elementMatcher( matchers ), matcher) ]; 2396 } else { 2397 matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); 2398 2399 // Return special upon seeing a positional matcher 2400 if ( matcher[ expando ] ) { 2401 // Find the next relative operator (if any) for proper handling 2402 j = ++i; 2403 for ( ; j < len; j++ ) { 2404 if ( Expr.relative[ tokens[j].type ] ) { 2405 break; 2406 } 2407 } 2408 return setMatcher( 2409 i > 1 && elementMatcher( matchers ), 2410 i > 1 && toSelector( 2411 // If the preceding token was a descendant combinator, insert an implicit any-element `*` 2412 tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" }) 2413 ).replace( rtrim, "$1" ), 2414 matcher, 2415 i < j && matcherFromTokens( tokens.slice( i, j ) ), 2416 j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), 2417 j < len && toSelector( tokens ) 2418 ); 2419 } 2420 matchers.push( matcher ); 2421 } 2422 } 2423 2424 return elementMatcher( matchers ); 2425} 2426 2427function matcherFromGroupMatchers( elementMatchers, setMatchers ) { 2428 var bySet = setMatchers.length > 0, 2429 byElement = elementMatchers.length > 0, 2430 superMatcher = function( seed, context, xml, results, outermost ) { 2431 var elem, j, matcher, 2432 matchedCount = 0, 2433 i = "0", 2434 unmatched = seed && [], 2435 setMatched = [], 2436 contextBackup = outermostContext, 2437 // We must always have either seed elements or outermost context 2438 elems = seed || byElement && Expr.find["TAG"]( "*", outermost ), 2439 // Use integer dirruns iff this is the outermost matcher 2440 dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1), 2441 len = elems.length; 2442 2443 if ( outermost ) { 2444 outermostContext = context === document || context || outermost; 2445 } 2446 2447 // Add elements passing elementMatchers directly to results 2448 // Support: IE<9, Safari 2449 // Tolerate NodeList properties (IE: "length"; Safari: <number>) matching elements by id 2450 for ( ; i !== len && (elem = elems[i]) != null; i++ ) { 2451 if ( byElement && elem ) { 2452 j = 0; 2453 if ( !context && elem.ownerDocument !== document ) { 2454 setDocument( elem ); 2455 xml = !documentIsHTML; 2456 } 2457 while ( (matcher = elementMatchers[j++]) ) { 2458 if ( matcher( elem, context || document, xml) ) { 2459 results.push( elem ); 2460 break; 2461 } 2462 } 2463 if ( outermost ) { 2464 dirruns = dirrunsUnique; 2465 } 2466 } 2467 2468 // Track unmatched elements for set filters 2469 if ( bySet ) { 2470 // They will have gone through all possible matchers 2471 if ( (elem = !matcher && elem) ) { 2472 matchedCount--; 2473 } 2474 2475 // Lengthen the array for every element, matched or not 2476 if ( seed ) { 2477 unmatched.push( elem ); 2478 } 2479 } 2480 } 2481 2482 // `i` is now the count of elements visited above, and adding it to `matchedCount` 2483 // makes the latter nonnegative. 2484 matchedCount += i; 2485 2486 // Apply set filters to unmatched elements 2487 // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` 2488 // equals `i`), unless we didn't visit _any_ elements in the above loop because we have 2489 // no element matchers and no seed. 2490 // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that 2491 // case, which will result in a "00" `matchedCount` that differs from `i` but is also 2492 // numerically zero. 2493 if ( bySet && i !== matchedCount ) { 2494 j = 0; 2495 while ( (matcher = setMatchers[j++]) ) { 2496 matcher( unmatched, setMatched, context, xml ); 2497 } 2498 2499 if ( seed ) { 2500 // Reintegrate element matches to eliminate the need for sorting 2501 if ( matchedCount > 0 ) { 2502 while ( i-- ) { 2503 if ( !(unmatched[i] || setMatched[i]) ) { 2504 setMatched[i] = pop.call( results ); 2505 } 2506 } 2507 } 2508 2509 // Discard index placeholder values to get only actual matches 2510 setMatched = condense( setMatched ); 2511 } 2512 2513 // Add matches to results 2514 push.apply( results, setMatched ); 2515 2516 // Seedless set matches succeeding multiple successful matchers stipulate sorting 2517 if ( outermost && !seed && setMatched.length > 0 && 2518 ( matchedCount + setMatchers.length ) > 1 ) { 2519 2520 Sizzle.uniqueSort( results ); 2521 } 2522 } 2523 2524 // Override manipulation of globals by nested matchers 2525 if ( outermost ) { 2526 dirruns = dirrunsUnique; 2527 outermostContext = contextBackup; 2528 } 2529 2530 return unmatched; 2531 }; 2532 2533 return bySet ? 2534 markFunction( superMatcher ) : 2535 superMatcher; 2536} 2537 2538compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { 2539 var i, 2540 setMatchers = [], 2541 elementMatchers = [], 2542 cached = compilerCache[ selector + " " ]; 2543 2544 if ( !cached ) { 2545 // Generate a function of recursive functions that can be used to check each element 2546 if ( !match ) { 2547 match = tokenize( selector ); 2548 } 2549 i = match.length; 2550 while ( i-- ) { 2551 cached = matcherFromTokens( match[i] ); 2552 if ( cached[ expando ] ) { 2553 setMatchers.push( cached ); 2554 } else { 2555 elementMatchers.push( cached ); 2556 } 2557 } 2558 2559 // Cache the compiled function 2560 cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); 2561 2562 // Save selector and tokenization 2563 cached.selector = selector; 2564 } 2565 return cached; 2566}; 2567 2568/** 2569 * A low-level selection function that works with Sizzle's compiled 2570 * selector functions 2571 * @param {String|Function} selector A selector or a pre-compiled 2572 * selector function built with Sizzle.compile 2573 * @param {Element} context 2574 * @param {Array} [results] 2575 * @param {Array} [seed] A set of elements to match against 2576 */ 2577select = Sizzle.select = function( selector, context, results, seed ) { 2578 var i, tokens, token, type, find, 2579 compiled = typeof selector === "function" && selector, 2580 match = !seed && tokenize( (selector = compiled.selector || selector) ); 2581 2582 results = results || []; 2583 2584 // Try to minimize operations if there is only one selector in the list and no seed 2585 // (the latter of which guarantees us context) 2586 if ( match.length === 1 ) { 2587 2588 // Reduce context if the leading compound selector is an ID 2589 tokens = match[0] = match[0].slice( 0 ); 2590 if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && 2591 support.getById && context.nodeType === 9 && documentIsHTML && 2592 Expr.relative[ tokens[1].type ] ) { 2593 2594 context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0]; 2595 if ( !context ) { 2596 return results; 2597 2598 // Precompiled matchers will still verify ancestry, so step up a level 2599 } else if ( compiled ) { 2600 context = context.parentNode; 2601 } 2602 2603 selector = selector.slice( tokens.shift().value.length ); 2604 } 2605 2606 // Fetch a seed set for right-to-left matching 2607 i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length; 2608 while ( i-- ) { 2609 token = tokens[i]; 2610 2611 // Abort if we hit a combinator 2612 if ( Expr.relative[ (type = token.type) ] ) { 2613 break; 2614 } 2615 if ( (find = Expr.find[ type ]) ) { 2616 // Search, expanding context for leading sibling combinators 2617 if ( (seed = find( 2618 token.matches[0].replace( runescape, funescape ), 2619 rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context 2620 )) ) { 2621 2622 // If seed is empty or no tokens remain, we can return early 2623 tokens.splice( i, 1 ); 2624 selector = seed.length && toSelector( tokens ); 2625 if ( !selector ) { 2626 push.apply( results, seed ); 2627 return results; 2628 } 2629 2630 break; 2631 } 2632 } 2633 } 2634 } 2635 2636 // Compile and execute a filtering function if one is not provided 2637 // Provide `match` to avoid retokenization if we modified the selector above 2638 ( compiled || compile( selector, match ) )( 2639 seed, 2640 context, 2641 !documentIsHTML, 2642 results, 2643 !context || rsibling.test( selector ) && testContext( context.parentNode ) || context 2644 ); 2645 return results; 2646}; 2647 2648// One-time assignments 2649 2650// Sort stability 2651support.sortStable = expando.split("").sort( sortOrder ).join("") === expando; 2652 2653// Support: Chrome 14-35+ 2654// Always assume duplicates if they aren't passed to the comparison function 2655support.detectDuplicates = !!hasDuplicate; 2656 2657// Initialize against the default document 2658setDocument(); 2659 2660// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) 2661// Detached nodes confoundingly follow *each other* 2662support.sortDetached = assert(function( div1 ) { 2663 // Should return 1, but returns 4 (following) 2664 return div1.compareDocumentPosition( document.createElement("div") ) & 1; 2665}); 2666 2667// Support: IE<8 2668// Prevent attribute/property "interpolation" 2669// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx 2670if ( !assert(function( div ) { 2671 div.innerHTML = "<a href='#'></a>"; 2672 return div.firstChild.getAttribute("href") === "#" ; 2673}) ) { 2674 addHandle( "type|href|height|width", function( elem, name, isXML ) { 2675 if ( !isXML ) { 2676 return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); 2677 } 2678 }); 2679} 2680 2681// Support: IE<9 2682// Use defaultValue in place of getAttribute("value") 2683if ( !support.attributes || !assert(function( div ) { 2684 div.innerHTML = "<input/>"; 2685 div.firstChild.setAttribute( "value", "" ); 2686 return div.firstChild.getAttribute( "value" ) === ""; 2687}) ) { 2688 addHandle( "value", function( elem, name, isXML ) { 2689 if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { 2690 return elem.defaultValue; 2691 } 2692 }); 2693} 2694 2695// Support: IE<9 2696// Use getAttributeNode to fetch booleans when getAttribute lies 2697if ( !assert(function( div ) { 2698 return div.getAttribute("disabled") == null; 2699}) ) { 2700 addHandle( booleans, function( elem, name, isXML ) { 2701 var val; 2702 if ( !isXML ) { 2703 return elem[ name ] === true ? name.toLowerCase() : 2704 (val = elem.getAttributeNode( name )) && val.specified ? 2705 val.value : 2706 null; 2707 } 2708 }); 2709} 2710 2711return Sizzle; 2712 2713})( window ); 2714 2715 2716 2717jQuery.find = Sizzle; 2718jQuery.expr = Sizzle.selectors; 2719jQuery.expr[ ":" ] = jQuery.expr.pseudos; 2720jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort; 2721jQuery.text = Sizzle.getText; 2722jQuery.isXMLDoc = Sizzle.isXML; 2723jQuery.contains = Sizzle.contains; 2724 2725 2726 2727var dir = function( elem, dir, until ) { 2728 var matched = [], 2729 truncate = until !== undefined; 2730 2731 while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) { 2732 if ( elem.nodeType === 1 ) { 2733 if ( truncate && jQuery( elem ).is( until ) ) { 2734 break; 2735 } 2736 matched.push( elem ); 2737 } 2738 } 2739 return matched; 2740}; 2741 2742 2743var siblings = function( n, elem ) { 2744 var matched = []; 2745 2746 for ( ; n; n = n.nextSibling ) { 2747 if ( n.nodeType === 1 && n !== elem ) { 2748 matched.push( n ); 2749 } 2750 } 2751 2752 return matched; 2753}; 2754 2755 2756var rneedsContext = jQuery.expr.match.needsContext; 2757 2758var rsingleTag = ( /^<([\w-]+)\s*\/?>(?:<\/\1>|)$/ ); 2759 2760 2761 2762var risSimple = /^.[^:#\[\.,]*$/; 2763 2764// Implement the identical functionality for filter and not 2765function winnow( elements, qualifier, not ) { 2766 if ( jQuery.isFunction( qualifier ) ) { 2767 return jQuery.grep( elements, function( elem, i ) { 2768 /* jshint -W018 */ 2769 return !!qualifier.call( elem, i, elem ) !== not; 2770 } ); 2771 2772 } 2773 2774 if ( qualifier.nodeType ) { 2775 return jQuery.grep( elements, function( elem ) { 2776 return ( elem === qualifier ) !== not; 2777 } ); 2778 2779 } 2780 2781 if ( typeof qualifier === "string" ) { 2782 if ( risSimple.test( qualifier ) ) { 2783 return jQuery.filter( qualifier, elements, not ); 2784 } 2785 2786 qualifier = jQuery.filter( qualifier, elements ); 2787 } 2788 2789 return jQuery.grep( elements, function( elem ) { 2790 return (
2790jQuery.inArray( elem, qualifier ) > -1 ) !== not; 2791 } ); 2792} 2793 2794jQuery.filter = function( expr, elems, not ) { 2795 var elem = elems[ 0 ]; 2796 2797 if ( not ) { 2798 expr = ":not(" + expr + ")"; 2799 } 2800 2801 return elems.length === 1 && elem.nodeType === 1 ? 2802 jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] : 2803 jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { 2804 return elem.nodeType === 1; 2805 } ) ); 2806}; 2807 2808jQuery.fn.extend( { 2809 find: function( selector ) { 2810 var i, 2811 ret = [], 2812 self = this, 2813 len = self.length; 2814 2815 if ( typeof selector !== "string" ) {
vendor: 5,394 bytes, lines 2816-3018
2816 return this.pushStack( jQuery( selector ).filter( function() { 2817 for ( i = 0; i < len; i++ ) { 2818 if ( jQuery.contains( self[ i ], this ) ) { 2819 return true; 2820 } 2821 } 2822 } ) ); 2823 } 2824 2825 for ( i = 0; i < len; i++ ) { 2826 jQuery.find( selector, self[ i ], ret ); 2827 } 2828 2829 // Needed because $( selector, context ) becomes $( context ).find( selector ) 2830 ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret ); 2831 ret.selector = this.selector ? this.selector + " " + selector : selector; 2832 return ret; 2833 }, 2834 filter: function( selector ) { 2835 return this.pushStack( winnow( this, selector || [], false ) ); 2836 }, 2837 not: function( selector ) { 2838 return this.pushStack( winnow( this, selector || [], true ) ); 2839 }, 2840 is: function( selector ) { 2841 return !!winnow( 2842 this, 2843 2844 // If this is a positional/relative selector, check membership in the returned set 2845 // so $("p:first").is("p:last") won't return true for a doc with two "p". 2846 typeof selector === "string" && rneedsContext.test( selector ) ? 2847 jQuery( selector ) : 2848 selector || [], 2849 false 2850 ).length; 2851 } 2852} ); 2853 2854 2855// Initialize a jQuery object 2856 2857 2858// A central reference to the root jQuery(document) 2859var rootjQuery, 2860 2861 // A simple way to check for HTML strings 2862 // Prioritize #id over <tag> to avoid XSS via location.hash (#9521) 2863 // Strict HTML recognition (#11290: must start with <) 2864 rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/, 2865 2866 init = jQuery.fn.init = function( selector, context, root ) { 2867 var match, elem; 2868 2869 // HANDLE: $(""), $(null), $(undefined), $(false) 2870 if ( !selector ) { 2871 return this; 2872 } 2873 2874 // init accepts an alternate rootjQuery 2875 // so migrate can support jQuery.sub (gh-2101) 2876 root = root || rootjQuery; 2877 2878 // Handle HTML strings 2879 if ( typeof selector === "string" ) { 2880 if ( selector.charAt( 0 ) === "<" && 2881 selector.charAt( selector.length - 1 ) === ">" && 2882 selector.length >= 3 ) { 2883 2884 // Assume that strings that start and end with <> are HTML and skip the regex check 2885 match = [ null, selector, null ]; 2886 2887 } else { 2888 match = rquickExpr.exec( selector ); 2889 } 2890 2891 // Match html or make sure no context is specified for #id 2892 if ( match && ( match[ 1 ] || !context ) ) { 2893 2894 // HANDLE: $(html) -> $(array) 2895 if ( match[ 1 ] ) { 2896 context = context instanceof jQuery ? context[ 0 ] : context; 2897 2898 // scripts is true for back-compat 2899 // Intentionally let the error be thrown if parseHTML is not present 2900 jQuery.merge( this, jQuery.parseHTML( 2901 match[ 1 ], 2902 context && context.nodeType ? context.ownerDocument || context : document, 2903 true 2904 ) ); 2905 2906 // HANDLE: $(html, props) 2907 if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) { 2908 for ( match in context ) { 2909 2910 // Properties of context are called as methods if possible 2911 if ( jQuery.isFunction( this[ match ] ) ) { 2912 this[ match ]( context[ match ] ); 2913 2914 // ...and otherwise set as attributes 2915 } else { 2916 this.attr( match, context[ match ] ); 2917 } 2918 } 2919 } 2920 2921 return this; 2922 2923 // HANDLE: $(#id) 2924 } else { 2925 elem = document.getElementById( match[ 2 ] ); 2926 2927 // Check parentNode to catch when Blackberry 4.6 returns 2928 // nodes that are no longer in the document #6963 2929 if ( elem && elem.parentNode ) { 2930 2931 // Handle the case where IE and Opera return items 2932 // by name instead of ID 2933 if ( elem.id !== match[ 2 ] ) { 2934 return rootjQuery.find( selector ); 2935 } 2936 2937 // Otherwise, we inject the element directly into the jQuery object 2938 this.length = 1; 2939 this[ 0 ] = elem; 2940 } 2941 2942 this.context = document; 2943 this.selector = selector; 2944 return this; 2945 } 2946 2947 // HANDLE: $(expr, $(...)) 2948 } else if ( !context || context.jquery ) { 2949 return ( context || root ).find( selector ); 2950 2951 // HANDLE: $(expr, context) 2952 // (which is just equivalent to: $(context).find(expr) 2953 } else { 2954 return this.constructor( context ).find( selector ); 2955 } 2956 2957 // HANDLE: $(DOMElement) 2958 } else if ( selector.nodeType ) { 2959 this.context = this[ 0 ] = selector; 2960 this.length = 1; 2961 return this; 2962 2963 // HANDLE: $(function) 2964 // Shortcut for document ready 2965 } else if ( jQuery.isFunction( selector ) ) { 2966 return typeof root.ready !== "undefined" ? 2967 root.ready( selector ) : 2968 2969 // Execute immediately if ready is not present 2970 selector( jQuery ); 2971 } 2972 2973 if ( selector.selector !== undefined ) { 2974 this.selector = selector.selector; 2975 this.context = selector.context; 2976 } 2977 2978 return jQuery.makeArray( selector, this ); 2979 }; 2980 2981// Give the init function the jQuery prototype for later instantiation 2982init.prototype = jQuery.fn; 2983 2984// Initialize central reference 2985rootjQuery = jQuery( document ); 2986 2987 2988var rparentsprev = /^(?:parents|prev(?:Until|All))/, 2989 2990 // methods guaranteed to produce a unique set when starting from a unique set 2991 guaranteedUnique = { 2992 children: true, 2993 contents: true, 2994 next: true, 2995 prev: true 2996 }; 2997 2998jQuery.fn.extend( { 2999 has: function( target ) { 3000 var i, 3001 targets = jQuery( target, this ), 3002 len = targets.length; 3003 3004 return this.filter( function() { 3005 for ( i = 0; i < len; i++ ) { 3006 if ( jQuery.contains( this, targets[ i ] ) ) { 3007 return true; 3008 } 3009 } 3010 } ); 3011 }, 3012 3013 closest: function( selectors, context ) { 3014 var cur, 3015 i = 0, 3016 l = this.length, 3017 matched = [], 3018 pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ?
vendor: 12,881 bytes, lines 3019-3527
3019 jQuery( selectors, context || this.context ) : 3020 0; 3021 3022 for ( ; i < l; i++ ) { 3023 for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { 3024 3025 // Always skip document fragments 3026 if ( cur.nodeType < 11 && ( pos ? 3027 pos.index( cur ) > -1 : 3028 3029 // Don't pass non-elements to Sizzle 3030 cur.nodeType === 1 && 3031 jQuery.find.matchesSelector( cur, selectors ) ) ) { 3032 3033 matched.push( cur ); 3034 break; 3035 } 3036 } 3037 } 3038 3039 return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched ); 3040 }, 3041 3042 // Determine the position of an element within 3043 // the matched set of elements 3044 index: function( elem ) { 3045 3046 // No argument, return index in parent 3047 if ( !elem ) { 3048 return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; 3049 } 3050 3051 // index in selector 3052 if ( typeof elem === "string" ) { 3053 return jQuery.inArray( this[ 0 ], jQuery( elem ) ); 3054 } 3055 3056 // Locate the position of the desired element 3057 return jQuery.inArray( 3058 3059 // If it receives a jQuery object, the first element is used 3060 elem.jquery ? elem[ 0 ] : elem, this ); 3061 }, 3062 3063 add: function( selector, context ) { 3064 return this.pushStack( 3065 jQuery.uniqueSort( 3066 jQuery.merge( this.get(), jQuery( selector, context ) ) 3067 ) 3068 ); 3069 }, 3070 3071 addBack: function( selector ) { 3072 return this.add( selector == null ? 3073 this.prevObject : this.prevObject.filter( selector ) 3074 ); 3075 } 3076} ); 3077 3078function sibling( cur, dir ) { 3079 do { 3080 cur = cur[ dir ]; 3081 } while ( cur && cur.nodeType !== 1 ); 3082 3083 return cur; 3084} 3085 3086jQuery.each( { 3087 parent: function( elem ) { 3088 var parent = elem.parentNode; 3089 return parent && parent.nodeType !== 11 ? parent : null; 3090 }, 3091 parents: function( elem ) { 3092 return dir( elem, "parentNode" ); 3093 }, 3094 parentsUntil: function( elem, i, until ) { 3095 return dir( elem, "parentNode", until ); 3096 }, 3097 next: function( elem ) { 3098 return sibling( elem, "nextSibling" ); 3099 }, 3100 prev: function( elem ) { 3101 return sibling( elem, "previousSibling" ); 3102 }, 3103 nextAll: function( elem ) { 3104 return dir( elem, "nextSibling" ); 3105 }, 3106 prevAll: function( elem ) { 3107 return dir( elem, "previousSibling" ); 3108 }, 3109 nextUntil: function( elem, i, until ) { 3110 return dir( elem, "nextSibling", until ); 3111 }, 3112 prevUntil: function( elem, i, until ) { 3113 return dir( elem, "previousSibling", until ); 3114 }, 3115 siblings: function( elem ) { 3116 return siblings( ( elem.parentNode || {} ).firstChild, elem ); 3117 }, 3118 children: function( elem ) { 3119 return siblings( elem.firstChild ); 3120 }, 3121 contents: function( elem ) { 3122 return jQuery.nodeName( elem, "iframe" ) ? 3123 elem.contentDocument || elem.contentWindow.document : 3124 jQuery.merge( [], elem.childNodes ); 3125 } 3126}, function( name, fn ) { 3127 jQuery.fn[ name ] = function( until, selector ) { 3128 var ret = jQuery.map( this, fn, until ); 3129 3130 if ( name.slice( -5 ) !== "Until" ) { 3131 selector = until; 3132 } 3133 3134 if ( selector && typeof selector === "string" ) { 3135 ret = jQuery.filter( selector, ret ); 3136 } 3137 3138 if ( this.length > 1 ) { 3139 3140 // Remove duplicates 3141 if ( !guaranteedUnique[ name ] ) { 3142 ret = jQuery.uniqueSort( ret ); 3143 } 3144 3145 // Reverse order for parents* and prev-derivatives 3146 if ( rparentsprev.test( name ) ) { 3147 ret = ret.reverse(); 3148 } 3149 } 3150 3151 return this.pushStack( ret ); 3152 }; 3153} ); 3154var rnotwhite = ( /\S+/g ); 3155 3156 3157 3158// Convert String-formatted options into Object-formatted ones 3159function createOptions( options ) { 3160 var object = {}; 3161 jQuery.each( options.match( rnotwhite ) || [], function( _, flag ) { 3162 object[ flag ] = true; 3163 } ); 3164 return object; 3165} 3166 3167/* 3168 * Create a callback list using the following parameters: 3169 * 3170 * options: an optional list of space-separated options that will change how 3171 * the callback list behaves or a more traditional option object 3172 * 3173 * By default a callback list will act like an event callback list and can be 3174 * "fired" multiple times. 3175 * 3176 * Possible options: 3177 * 3178 * once: will ensure the callback list can only be fired once (like a Deferred) 3179 * 3180 * memory: will keep track of previous values and will call any callback added 3181 * after the list has been fired right away with the latest "memorized" 3182 * values (like a Deferred) 3183 * 3184 * unique: will ensure a callback can only be added once (no duplicate in the list) 3185 * 3186 * stopOnFalse: interrupt callings when a callback returns false 3187 * 3188 */ 3189jQuery.Callbacks = function( options ) { 3190 3191 // Convert options from String-formatted to Object-formatted if needed 3192 // (we check in cache first) 3193 options = typeof options === "string" ? 3194 createOptions( options ) : 3195 jQuery.extend( {}, options ); 3196 3197 var // Flag to know if list is currently firing 3198 firing, 3199 3200 // Last fire value for non-forgettable lists 3201 memory, 3202 3203 // Flag to know if list was already fired 3204 fired, 3205 3206 // Flag to prevent firing 3207 locked, 3208 3209 // Actual callback list 3210 list = [], 3211 3212 // Queue of execution data for repeatable lists 3213 queue = [], 3214 3215 // Index of currently firing callback (modified by add/remove as needed) 3216 firingIndex = -1, 3217 3218 // Fire callbacks 3219 fire = function() { 3220 3221 // Enforce single-firing 3222 locked = options.once; 3223 3224 // Execute callbacks for all pending executions, 3225 // respecting firingIndex overrides and runtime changes 3226 fired = firing = true; 3227 for ( ; queue.length; firingIndex = -1 ) { 3228 memory = queue.shift(); 3229 while ( ++firingIndex < list.length ) { 3230 3231 // Run callback and check for early termination 3232 if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && 3233 options.stopOnFalse ) { 3234 3235 // Jump to end and forget the data so .add doesn't re-fire 3236 firingIndex = list.length; 3237 memory = false; 3238 } 3239 } 3240 } 3241 3242 // Forget the data if we're done with it 3243 if ( !options.memory ) { 3244 memory = false; 3245 } 3246 3247 firing = false; 3248 3249 // Clean up if we're done firing for good 3250 if ( locked ) { 3251 3252 // Keep an empty list if we have data for future add calls 3253 if ( memory ) { 3254 list = []; 3255 3256 // Otherwise, this object is spent 3257 } else { 3258 list = ""; 3259 } 3260 } 3261 }, 3262 3263 // Actual Callbacks object 3264 self = { 3265 3266 // Add a callback or a collection of callbacks to the list 3267 add: function() { 3268 if ( list ) { 3269 3270 // If we have memory from a past run, we should fire after adding 3271 if ( memory && !firing ) { 3272 firingIndex = list.length - 1; 3273 queue.push( memory ); 3274 } 3275 3276 ( function add( args ) { 3277 jQuery.each( args, function( _, arg ) { 3278 if ( jQuery.isFunction( arg ) ) { 3279 if ( !options.unique || !self.has( arg ) ) { 3280 list.push( arg ); 3281 } 3282 } else if ( arg && arg.length && jQuery.type( arg ) !== "string" ) { 3283 3284 // Inspect recursively 3285 add( arg ); 3286 } 3287 } ); 3288 } )( arguments ); 3289 3290 if ( memory && !firing ) { 3291 fire(); 3292 } 3293 } 3294 return this; 3295 }, 3296 3297 // Remove a callback from the list 3298 remove: function() { 3299 jQuery.each( arguments, function( _, arg ) { 3300 var index; 3301 while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { 3302 list.splice( index, 1 ); 3303 3304 // Handle firing indexes 3305 if ( index <= firingIndex ) { 3306 firingIndex--; 3307 } 3308 } 3309 } ); 3310 return this; 3311 }, 3312 3313 // Check if a given callback is in the list. 3314 // If no argument is given, return whether or not list has callbacks attached. 3315 has: function( fn ) { 3316 return fn ? 3317 jQuery.inArray( fn, list ) > -1 : 3318 list.length > 0; 3319 }, 3320 3321 // Remove all callbacks from the list 3322 empty: function() { 3323 if ( list ) { 3324 list = []; 3325 } 3326 return this; 3327 }, 3328 3329 // Disable .fire and .add 3330 // Abort any current/pending executions 3331 // Clear all callbacks and values 3332 disable: function() { 3333 locked = queue = []; 3334 list = memory = ""; 3335 return this; 3336 }, 3337 disabled: function() { 3338 return !list; 3339 }, 3340 3341 // Disable .fire 3342 // Also disable .add unless we have memory (since it would have no effect) 3343 // Abort any pending executions 3344 lock: function() { 3345 locked = true; 3346 if ( !memory ) { 3347 self.disable(); 3348 } 3349 return this; 3350 }, 3351 locked: function() { 3352 return !!locked; 3353 }, 3354 3355 // Call all callbacks with the given context and arguments 3356 fireWith: function( context, args ) { 3357 if ( !locked ) { 3358 args = args || []; 3359 args = [ context, args.slice ? args.slice() : args ]; 3360 queue.push( args ); 3361 if ( !firing ) { 3362 fire(); 3363 } 3364 } 3365 return this; 3366 }, 3367 3368 // Call all the callbacks with the given arguments 3369 fire: function() { 3370 self.fireWith( this, arguments ); 3371 return this; 3372 }, 3373 3374 // To know if the callbacks have already been called at least once 3375 fired: function() { 3376 return !!fired; 3377 } 3378 }; 3379 3380 return self; 3381}; 3382 3383 3384jQuery.extend( { 3385 3386 Deferred: function( func ) { 3387 var tuples = [ 3388 3389 // action, add listener, listener list, final state 3390 [ "resolve", "done", jQuery.Callbacks( "once memory" ), "resolved" ], 3391 [ "reject", "fail", jQuery.Callbacks( "once memory" ), "rejected" ], 3392 [ "notify", "progress", jQuery.Callbacks( "memory" ) ] 3393 ], 3394 state = "pending", 3395 promise = { 3396 state: function() { 3397 return state; 3398 }, 3399 always: function() { 3400 deferred.done( arguments ).fail( arguments ); 3401 return this; 3402 }, 3403 then: function( /* fnDone, fnFail, fnProgress */ ) { 3404 var fns = arguments; 3405 return jQuery.Deferred( function( newDefer ) { 3406 jQuery.each( tuples, function( i, tuple ) { 3407 var fn = jQuery.isFunction( fns[ i ] ) && fns[ i ]; 3408 3409 // deferred[ done | fail | progress ] for forwarding actions to newDefer 3410 deferred[ tuple[ 1 ] ]( function() { 3411 var returned = fn && fn.apply( this, arguments ); 3412 if ( returned && jQuery.isFunction( returned.promise ) ) { 3413 returned.promise() 3414 .progress( newDefer.notify ) 3415 .done( newDefer.resolve ) 3416 .fail( newDefer.reject ); 3417 } else { 3418 newDefer[ tuple[ 0 ] + "With" ]( 3419 this === promise ? newDefer.promise() : this, 3420 fn ? [ returned ] : arguments 3421 ); 3422 } 3423 } ); 3424 } ); 3425 fns = null; 3426 } ).promise(); 3427 }, 3428 3429 // Get a promise for this deferred 3430 // If obj is provided, the promise aspect is added to the object 3431 promise: function( obj ) { 3432 return obj != null ? jQuery.extend( obj, promise ) : promise; 3433 } 3434 }, 3435 deferred = {}; 3436 3437 // Keep pipe for back-compat 3438 promise.pipe = promise.then; 3439 3440 // Add list-specific methods 3441 jQuery.each( tuples, function( i, tuple ) { 3442 var list = tuple[ 2 ], 3443 stateString = tuple[ 3 ]; 3444 3445 // promise[ done | fail | progress ] = list.add 3446 promise[ tuple[ 1 ] ] = list.add; 3447 3448 // Handle state 3449 if ( stateString ) { 3450 list.add( function() { 3451 3452 // state = [ resolved | rejected ] 3453 state = stateString; 3454 3455 // [ reject_list | resolve_list ].disable; progress_list.lock 3456 }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock ); 3457 } 3458 3459 // deferred[ resolve | reject | notify ] 3460 deferred[ tuple[ 0 ] ] = function() { 3461 deferred[ tuple[ 0 ] + "With" ]( this === deferred ? promise : this, arguments ); 3462 return this; 3463 }; 3464 deferred[ tuple[ 0 ] + "With" ] = list.fireWith; 3465 } ); 3466 3467 // Make the deferred a promise 3468 promise.promise( deferred ); 3469 3470 // Call given func if any 3471 if ( func ) { 3472 func.call( deferred, deferred ); 3473 } 3474 3475 // All done! 3476 return deferred; 3477 }, 3478 3479 // Deferred helper 3480 when: function( subordinate /* , ..., subordinateN */ ) { 3481 var i = 0, 3482 resolveValues = slice.call( arguments ), 3483 length = resolveValues.length, 3484 3485 // the count of uncompleted subordinates 3486 remaining = length !== 1 || 3487 ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0, 3488 3489 // the master Deferred. 3490 // If resolveValues consist of only a single Deferred, just use that. 3491 deferred = remaining === 1 ? subordinate : jQuery.Deferred(), 3492 3493 // Update function for both resolve and progress values 3494 updateFunc = function( i, contexts, values ) { 3495 return function( value ) { 3496 contexts[ i ] = this; 3497 values[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; 3498 if ( values === progressValues ) { 3499 deferred.notifyWith( contexts, values ); 3500 3501 } else if ( !( --remaining ) ) { 3502 deferred.resolveWith( contexts, values ); 3503 } 3504 }; 3505 }, 3506 3507 progressValues, progressContexts, resolveContexts; 3508 3509 // add listeners to Deferred subordinates; treat others as resolved 3510 if ( length > 1 ) { 3511 progressValues = new Array( length ); 3512 progressContexts = new Array( length ); 3513 resolveContexts = new Array( length ); 3514 for ( ; i < length; i++ ) { 3515 if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) { 3516 resolveValues[ i ].promise() 3517 .progress( updateFunc( i, progressContexts, progressValues ) ) 3518 .done( updateFunc( i, resolveContexts, resolveValues ) ) 3519 .fail( deferred.reject ); 3520 } else { 3521 --remaining; 3522 } 3523 } 3524 } 3525 3526 // if we're not waiting on anything, resolve the master 3527 if ( !remaining ) {
vendor: 2,149 bytes, lines 3528-3627
3528 deferred.resolveWith( resolveContexts, resolveValues ); 3529 } 3530 3531 return deferred.promise(); 3532 } 3533} ); 3534 3535 3536// The deferred used on DOM ready 3537var readyList; 3538 3539jQuery.fn.ready = function( fn ) { 3540 3541 // Add the callback 3542 jQuery.ready.promise().done( fn ); 3543 3544 return this; 3545}; 3546 3547jQuery.extend( { 3548 3549 // Is the DOM ready to be used? Set to true once it occurs. 3550 isReady: false, 3551 3552 // A counter to track how many items to wait for before 3553 // the ready event fires. See #6781 3554 readyWait: 1, 3555 3556 // Hold (or release) the ready event 3557 holdReady: function( hold ) { 3558 if ( hold ) { 3559 jQuery.readyWait++; 3560 } else { 3561 jQuery.ready( true ); 3562 } 3563 }, 3564 3565 // Handle when the DOM is ready 3566 ready: function( wait ) { 3567 3568 // Abort if there are pending holds or we're already ready 3569 if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { 3570 return; 3571 } 3572 3573 // Remember that the DOM is ready 3574 jQuery.isReady = true; 3575 3576 // If a normal DOM Ready event fired, decrement, and wait if need be 3577 if ( wait !== true && --jQuery.readyWait > 0 ) { 3578 return; 3579 } 3580 3581 // If there are functions bound, to execute 3582 readyList.resolveWith( document, [ jQuery ] ); 3583 3584 // Trigger any bound ready events 3585 if ( jQuery.fn.triggerHandler ) { 3586 jQuery( document ).triggerHandler( "ready" ); 3587 jQuery( document ).off( "ready" ); 3588 } 3589 } 3590} ); 3591 3592/** 3593 * Clean-up method for dom ready events 3594 */ 3595function detach() { 3596 if ( document.addEventListener ) { 3597 document.removeEventListener( "DOMContentLoaded", completed ); 3598 window.removeEventListener( "load", completed ); 3599 3600 } else { 3601 document.detachEvent( "onreadystatechange", completed ); 3602 window.detachEvent( "onload", completed ); 3603 } 3604} 3605 3606/** 3607 * The ready event handler and self cleanup method 3608 */ 3609function completed() { 3610 3611 // readyState === "complete" is good enough for us to call the dom ready in oldIE 3612 if ( document.addEventListener || 3613 window.event.type === "load" || 3614 document.readyState === "complete" ) { 3615 3616 detach(); 3617 jQuery.ready(); 3618 } 3619} 3620 3621jQuery.ready.promise = function( obj ) { 3622 if ( !readyList ) { 3623 3624 readyList = jQuery.Deferred(); 3625 3626 // Catch cases where $(document).ready() is called 3627 // after the browser event has already occurred.
3628 // Support: IE6-10 3629 // Older IE sometimes signals "interactive" too soon 3630 if ( document.readyState === "complete" || 3631 ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { 3632 3633 // Handle it asynchronously to allow scripts the opportunity to delay ready 3634 window.setTimeout( jQuery.ready ); 3635 3636 // Standards-based browsers support DOMContentLoaded 3637 } else if ( document.addEventListener ) { 3638 3639 // Use the handy event callback 3640 document.addEventListener( "DOMContentLoaded", completed ); 3641 3642 // A fallback to window.onload, that will always work 3643 window.addEventListener( "load", completed ); 3644 3645 // If IE event model is used 3646 } else { 3647 3648 // Ensure firing before onload, maybe late but safe also for iframes 3649 document.attachEvent( "onreadystatechange", completed ); 3650 3651 // A fallback to window.onload, that will always work 3652 window.attachEvent( "onload", completed ); 3653 3654 // If IE and not a frame 3655 // continually check to see if the document is ready 3656 var top = false; 3657 3658 try { 3659 top = window.frameElement == null && document.documentElement; 3660 } catch ( e ) {} 3661 3662 if ( top && top.doScroll ) { 3663 ( function doScrollCheck() { 3664 if ( !jQuery.isReady ) { 3665 3666 try { 3667 3668 // Use the trick by Diego Perini 3669 // http://javascript.nwbox.com/IEContentLoaded/ 3670 top.doScroll( "left" ); 3671 } catch ( e ) { 3672 return window.setTimeout( doScrollCheck, 50 ); 3673 } 3674 3675 // detach all dom ready events 3676 detach(); 3677 3678 // and execute any waiting functions 3679 jQuery.ready(); 3680 } 3681 } )(); 3682 } 3683 } 3684 } 3685 return readyList.promise( obj ); 3686}; 3687 3688// Kick off the DOM ready check even if the user does not 3689jQuery.ready.promise(); 3690 3691 3692 3693 3694// Support: IE<9 3695// Iteration over object's inherited properties before its own 3696var i; 3697for ( i in jQuery( support ) ) { 3698 break; 3699} 3700support.ownFirst = i === "0"; 3701 3702// Note: most support tests are defined in their respective modules. 3703// false until the test is run 3704support.inlineBlockNeedsLayout = false; 3705 3706// Execute ASAP in case we need to set body.style.zoom 3707jQuery( function() { 3708 3709 // Minified: var a,b,c,d 3710 var val, div, body, container; 3711 3712 body = document.getElementsByTagName( "body" )[ 0 ]; 3713 if ( !body || !body.style ) { 3714 3715 // Return for frameset docs that don't have a body 3716 return; 3717 } 3718 3719 // Setup 3720 div = document.createElement( "div" ); 3721 container = document.createElement( "div" ); 3722 container.style.cssText = "position:absolute;border:0;width:0;height:0;top:0;left:-9999px"; 3723 body.appendChild( container ).appendChild( div ); 3724 3725 if ( typeof div.style.zoom !== "undefined" ) { 3726 3727 // Support: IE<8 3728 // Check if natively block-level elements act like inline-block 3729 // elements when setting their display to 'inline' and giving 3730 // them layout 3731 div.style.cssText = "display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1"; 3732 3733 support.inlineBlockNeedsLayout = val = div.offsetWidth === 3; 3734 if ( val ) { 3735 3736 // Prevent IE 6 from affecting layout for positioned elements #11048 3737 // Prevent IE from shrinking the body in IE 7 mode #12869 3738 // Support: IE<8 3739 body.style.zoom = 1; 3740 } 3741 } 3742 3743 body.removeChild( container ); 3744} ); 3745 3746 3747( function() { 3748 var div = document.createElement( "div" ); 3749 3750 // Support: IE<9 3751 support.deleteExpando = true; 3752 try { 3753 delete div.test; 3754 } catch ( e ) { 3755 support.deleteExpando = false; 3756 } 3757 3758 // Null elements to avoid leaks in IE. 3759 div = null; 3760} )(); 3761var acceptData = function( elem ) { 3762 var noData = jQuery.noData[ ( elem.nodeName + " " ).toLowerCase() ], 3763 nodeType = +elem.nodeType || 1; 3764 3765 // Do not set data on non-element DOM nodes because it will not be cleared (#8335). 3766 return nodeType !== 1 && nodeType !== 9 ? 3767 false : 3768 3769 // Nodes accept data unless otherwise specified; rejection can be conditional 3770 !noData || noData !== true && elem.getAttribute( "classid" ) === noData; 3771}; 3772 3773 3774 3775 3776var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, 3777 rmultiDash = /([A-Z])/g; 3778 3779function dataAttr( elem, key, data ) { 3780 3781 // If nothing was found internally, try to fetch any 3782 // data from the HTML5 data-* attribute 3783 if ( data === undefined && elem.nodeType === 1 ) { 3784 3785 var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase(); 3786 3787 data = elem.getAttribute( name ); 3788 3789 if ( typeof data === "string" ) { 3790 try { 3791 data = data === "true" ? true :
vendor: 11,186 bytes, lines 3792-4256
3792 data === "false" ? false : 3793 data === "null" ? null : 3794 3795 // Only convert to a number if it doesn't change the string 3796 +data + "" === data ? +data : 3797 rbrace.test( data ) ? jQuery.parseJSON( data ) : 3798 data; 3799 } catch ( e ) {} 3800 3801 // Make sure we set the data so it isn't changed later 3802 jQuery.data( elem, key, data ); 3803 3804 } else { 3805 data = undefined; 3806 } 3807 } 3808 3809 return data; 3810} 3811 3812// checks a cache object for emptiness 3813function isEmptyDataObject( obj ) { 3814 var name; 3815 for ( name in obj ) { 3816 3817 // if the public data object is empty, the private is still empty 3818 if ( name === "data" && jQuery.isEmptyObject( obj[ name ] ) ) { 3819 continue; 3820 } 3821 if ( name !== "toJSON" ) { 3822 return false; 3823 } 3824 } 3825 3826 return true; 3827} 3828 3829function internalData( elem, name, data, pvt /* Internal Use Only */ ) { 3830 if ( !acceptData( elem ) ) { 3831 return; 3832 } 3833 3834 var ret, thisCache, 3835 internalKey = jQuery.expando, 3836 3837 // We have to handle DOM nodes and JS objects differently because IE6-7 3838 // can't GC object references properly across the DOM-JS boundary 3839 isNode = elem.nodeType, 3840 3841 // Only DOM nodes need the global jQuery cache; JS object data is 3842 // attached directly to the object so GC can occur automatically 3843 cache = isNode ? jQuery.cache : elem, 3844 3845 // Only defining an ID for JS objects if its cache already exists allows 3846 // the code to shortcut on the same path as a DOM node with no cache 3847 id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey; 3848 3849 // Avoid doing any more work than we need to when trying to get data on an 3850 // object that has no data at all 3851 if ( ( !id || !cache[ id ] || ( !pvt && !cache[ id ].data ) ) && 3852 data === undefined && typeof name === "string" ) { 3853 return; 3854 } 3855 3856 if ( !id ) { 3857 3858 // Only DOM nodes need a new unique ID for each element since their data 3859 // ends up in the global cache 3860 if ( isNode ) { 3861 id = elem[ internalKey ] = deletedIds.pop() || jQuery.guid++; 3862 } else { 3863 id = internalKey; 3864 } 3865 } 3866 3867 if ( !cache[ id ] ) { 3868 3869 // Avoid exposing jQuery metadata on plain JS objects when the object 3870 // is serialized using JSON.stringify 3871 cache[ id ] = isNode ? {} : { toJSON: jQuery.noop }; 3872 } 3873 3874 // An object can be passed to jQuery.data instead of a key/value pair; this gets 3875 // shallow copied over onto the existing cache 3876 if ( typeof name === "object" || typeof name === "function" ) { 3877 if ( pvt ) { 3878 cache[ id ] = jQuery.extend( cache[ id ], name ); 3879 } else { 3880 cache[ id ].data = jQuery.extend( cache[ id ].data, name ); 3881 } 3882 } 3883 3884 thisCache = cache[ id ]; 3885 3886 // jQuery data() is stored in a separate object inside the object's internal data 3887 // cache in order to avoid key collisions between internal data and user-defined 3888 // data. 3889 if ( !pvt ) { 3890 if ( !thisCache.data ) { 3891 thisCache.data = {}; 3892 } 3893 3894 thisCache = thisCache.data; 3895 } 3896 3897 if ( data !== undefined ) { 3898 thisCache[ jQuery.camelCase( name ) ] = data; 3899 } 3900 3901 // Check for both converted-to-camel and non-converted data property names 3902 // If a data property was specified 3903 if ( typeof name === "string" ) { 3904 3905 // First Try to find as-is property data 3906 ret = thisCache[ name ]; 3907 3908 // Test for null|undefined property data 3909 if ( ret == null ) { 3910 3911 // Try to find the camelCased property 3912 ret = thisCache[ jQuery.camelCase( name ) ]; 3913 } 3914 } else { 3915 ret = thisCache; 3916 } 3917 3918 return ret; 3919} 3920 3921function internalRemoveData( elem, name, pvt ) { 3922 if ( !acceptData( elem ) ) { 3923 return; 3924 } 3925 3926 var thisCache, i, 3927 isNode = elem.nodeType, 3928 3929 // See jQuery.data for more information 3930 cache = isNode ? jQuery.cache : elem, 3931 id = isNode ? elem[ jQuery.expando ] : jQuery.expando; 3932 3933 // If there is already no cache entry for this object, there is no 3934 // purpose in continuing 3935 if ( !cache[ id ] ) { 3936 return; 3937 } 3938 3939 if ( name ) { 3940 3941 thisCache = pvt ? cache[ id ] : cache[ id ].data; 3942 3943 if ( thisCache ) { 3944 3945 // Support array or space separated string names for data keys 3946 if ( !jQuery.isArray( name ) ) { 3947 3948 // try the string as a key before any manipulation 3949 if ( name in thisCache ) { 3950 name = [ name ]; 3951 } else { 3952 3953 // split the camel cased version by spaces unless a key with the spaces exists 3954 name = jQuery.camelCase( name ); 3955 if ( name in thisCache ) { 3956 name = [ name ]; 3957 } else { 3958 name = name.split( " " ); 3959 } 3960 } 3961 } else { 3962 3963 // If "name" is an array of keys... 3964 // When data is initially created, via ("key", "val") signature, 3965 // keys will be converted to camelCase. 3966 // Since there is no way to tell _how_ a key was added, remove 3967 // both plain key and camelCase key. #12786 3968 // This will only penalize the array argument path. 3969 name = name.concat( jQuery.map( name, jQuery.camelCase ) ); 3970 } 3971 3972 i = name.length; 3973 while ( i-- ) { 3974 delete thisCache[ name[ i ] ]; 3975 } 3976 3977 // If there is no data left in the cache, we want to continue 3978 // and let the cache object itself get destroyed 3979 if ( pvt ? !isEmptyDataObject( thisCache ) : !jQuery.isEmptyObject( thisCache ) ) { 3980 return; 3981 } 3982 } 3983 } 3984 3985 // See jQuery.data for more information 3986 if ( !pvt ) { 3987 delete cache[ id ].data; 3988 3989 // Don't destroy the parent cache unless the internal data object 3990 // had been the only thing left in it 3991 if ( !isEmptyDataObject( cache[ id ] ) ) { 3992 return; 3993 } 3994 } 3995 3996 // Destroy the cache 3997 if ( isNode ) { 3998 jQuery.cleanData( [ elem ], true ); 3999 4000 // Use delete when supported for expandos or `cache` is not a window per isWindow (#10080) 4001 /* jshint eqeqeq: false */ 4002 } else if ( support.deleteExpando || cache != cache.window ) { 4003 /* jshint eqeqeq: true */ 4004 delete cache[ id ]; 4005 4006 // When all else fails, undefined 4007 } else { 4008 cache[ id ] = undefined; 4009 } 4010} 4011 4012jQuery.extend( { 4013 cache: {}, 4014 4015 // The following elements (space-suffixed to avoid Object.prototype collisions) 4016 // throw uncatchable exceptions if you attempt to set expando properties 4017 noData: { 4018 "applet ": true, 4019 "embed ": true, 4020 4021 // ...but Flash objects (which have this classid) *can* handle expandos 4022 "object ": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" 4023 }, 4024 4025 hasData: function( elem ) { 4026 elem = elem.nodeType ? jQuery.cache[ elem[ jQuery.expando ] ] : elem[ jQuery.expando ]; 4027 return !!elem && !isEmptyDataObject( elem ); 4028 }, 4029 4030 data: function( elem, name, data ) { 4031 return internalData( elem, name, data ); 4032 }, 4033 4034 removeData: function( elem, name ) { 4035 return internalRemoveData( elem, name ); 4036 }, 4037 4038 // For internal use only. 4039 _data: function( elem, name, data ) { 4040 return internalData( elem, name, data, true ); 4041 }, 4042 4043 _removeData: function( elem, name ) { 4044 return internalRemoveData( elem, name, true ); 4045 } 4046} ); 4047 4048jQuery.fn.extend( { 4049 data: function( key, value ) { 4050 var i, name, data, 4051 elem = this[ 0 ], 4052 attrs = elem && elem.attributes; 4053 4054 // Special expections of .data basically thwart jQuery.access, 4055 // so implement the relevant behavior ourselves 4056 4057 // Gets all values 4058 if ( key === undefined ) { 4059 if ( this.length ) { 4060 data = jQuery.data( elem ); 4061 4062 if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) { 4063 i = attrs.length; 4064 while ( i-- ) { 4065 4066 // Support: IE11+ 4067 // The attrs elements can be null (#14894) 4068 if ( attrs[ i ] ) { 4069 name = attrs[ i ].name; 4070 if ( name.indexOf( "data-" ) === 0 ) { 4071 name = jQuery.camelCase( name.slice( 5 ) ); 4072 dataAttr( elem, name, data[ name ] ); 4073 } 4074 } 4075 } 4076 jQuery._data( elem, "parsedAttrs", true ); 4077 } 4078 } 4079 4080 return data; 4081 } 4082 4083 // Sets multiple values 4084 if ( typeof key === "object" ) { 4085 return this.each( function() { 4086 jQuery.data( this, key ); 4087 } ); 4088 } 4089 4090 return arguments.length > 1 ? 4091 4092 // Sets one value 4093 this.each( function() { 4094 jQuery.data( this, key, value ); 4095 } ) : 4096 4097 // Gets one value 4098 // Try to fetch any internally stored data first 4099 elem ? dataAttr( elem, key, jQuery.data( elem, key ) ) : undefined; 4100 }, 4101 4102 removeData: function( key ) { 4103 return this.each( function() { 4104 jQuery.removeData( this, key ); 4105 } ); 4106 } 4107} ); 4108 4109 4110jQuery.extend( { 4111 queue: function( elem, type, data ) { 4112 var queue; 4113 4114 if ( elem ) { 4115 type = ( type || "fx" ) + "queue"; 4116 queue = jQuery._data( elem, type ); 4117 4118 // Speed up dequeue by getting out quickly if this is just a lookup 4119 if ( data ) { 4120 if ( !queue || jQuery.isArray( data ) ) { 4121 queue = jQuery._data( elem, type, jQuery.makeArray( data ) ); 4122 } else { 4123 queue.push( data ); 4124 } 4125 } 4126 return queue || []; 4127 } 4128 }, 4129 4130 dequeue: function( elem, type ) { 4131 type = type || "fx"; 4132 4133 var queue = jQuery.queue( elem, type ), 4134 startLength = queue.length, 4135 fn = queue.shift(), 4136 hooks = jQuery._queueHooks( elem, type ), 4137 next = function() { 4138 jQuery.dequeue( elem, type ); 4139 }; 4140 4141 // If the fx queue is dequeued, always remove the progress sentinel 4142 if ( fn === "inprogress" ) { 4143 fn = queue.shift(); 4144 startLength--; 4145 } 4146 4147 if ( fn ) { 4148 4149 // Add a progress sentinel to prevent the fx queue from being 4150 // automatically dequeued 4151 if ( type === "fx" ) { 4152 queue.unshift( "inprogress" ); 4153 } 4154 4155 // clear up the last queue stop function 4156 delete hooks.stop; 4157 fn.call( elem, next, hooks ); 4158 } 4159 4160 if ( !startLength && hooks ) { 4161 hooks.empty.fire(); 4162 } 4163 }, 4164 4165 // not intended for public consumption - generates a queueHooks object, 4166 // or returns the current one 4167 _queueHooks: function( elem, type ) { 4168 var key = type + "queueHooks"; 4169 return jQuery._data( elem, key ) || jQuery._data( elem, key, { 4170 empty: jQuery.Callbacks( "once memory" ).add( function() { 4171 jQuery._removeData( elem, type + "queue" ); 4172 jQuery._removeData( elem, key ); 4173 } ) 4174 } ); 4175 } 4176} ); 4177 4178jQuery.fn.extend( { 4179 queue: function( type, data ) { 4180 var setter = 2; 4181 4182 if ( typeof type !== "string" ) { 4183 data = type; 4184 type = "fx"; 4185 setter--; 4186 } 4187 4188 if ( arguments.length < setter ) { 4189 return jQuery.queue( this[ 0 ], type ); 4190 } 4191 4192 return data === undefined ? 4193 this : 4194 this.each( function() { 4195 var queue = jQuery.queue( this, type, data ); 4196 4197 // ensure a hooks for this queue 4198 jQuery._queueHooks( this, type ); 4199 4200 if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { 4201 jQuery.dequeue( this, type ); 4202 } 4203 } ); 4204 }, 4205 dequeue: function( type ) { 4206 return this.each( function() { 4207 jQuery.dequeue( this, type ); 4208 } ); 4209 }, 4210 clearQueue: function( type ) { 4211 return this.queue( type || "fx", [] ); 4212 }, 4213 4214 // Get a promise resolved when queues of a certain type 4215 // are emptied (fx is the type by default) 4216 promise: function( type, obj ) { 4217 var tmp, 4218 count = 1, 4219 defer = jQuery.Deferred(), 4220 elements = this, 4221 i = this.length, 4222 resolve = function() { 4223 if ( !( --count ) ) { 4224 defer.resolveWith( elements, [ elements ] ); 4225 } 4226 }; 4227 4228 if ( typeof type !== "string" ) { 4229 obj = type; 4230 type = undefined; 4231 } 4232 type = type || "fx"; 4233 4234 while ( i-- ) { 4235 tmp = jQuery._data( elements[ i ], type + "queueHooks" ); 4236 if ( tmp && tmp.empty ) { 4237 count++; 4238 tmp.empty.add( resolve ); 4239 } 4240 } 4241 resolve(); 4242 return defer.promise( obj ); 4243 } 4244} ); 4245 4246 4247( function() { 4248 var shrinkWrapBlocksVal; 4249 4250 support.shrinkWrapBlocks = function() { 4251 if ( shrinkWrapBlocksVal != null ) { 4252 return shrinkWrapBlocksVal; 4253 } 4254 4255 // Will be changed later if needed. 4256 shrinkWrapBlocksVal = false;
vendor: 4,171 bytes, lines 4257-4405
4257 4258 // Minified: var b,c,d 4259 var div, body, container; 4260 4261 body = document.getElementsByTagName( "body" )[ 0 ]; 4262 if ( !body || !body.style ) { 4263 4264 // Test fired too early or in an unsupported environment, exit. 4265 return; 4266 } 4267 4268 // Setup 4269 div = document.createElement( "div" ); 4270 container = document.createElement( "div" ); 4271 container.style.cssText = "position:absolute;border:0;width:0;height:0;top:0;left:-9999px"; 4272 body.appendChild( container ).appendChild( div ); 4273 4274 // Support: IE6 4275 // Check if elements with layout shrink-wrap their children 4276 if ( typeof div.style.zoom !== "undefined" ) { 4277 4278 // Reset CSS: box-sizing; display; margin; border 4279 div.style.cssText = 4280 4281 // Support: Firefox<29, Android 2.3 4282 // Vendor-prefix box-sizing 4283 "-webkit-box-sizing:content-box;-moz-box-sizing:content-box;" + 4284 "box-sizing:content-box;display:block;margin:0;border:0;" + 4285 "padding:1px;width:1px;zoom:1"; 4286 div.appendChild( document.createElement( "div" ) ).style.width = "5px"; 4287 shrinkWrapBlocksVal = div.offsetWidth !== 3; 4288 } 4289 4290 body.removeChild( container ); 4291 4292 return shrinkWrapBlocksVal; 4293 }; 4294 4295} )(); 4296var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; 4297 4298var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); 4299 4300 4301var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; 4302 4303var isHidden = function( elem, el ) { 4304 4305 // isHidden might be called from jQuery#filter function; 4306 // in that case, element will be second argument 4307 elem = el || elem; 4308 return jQuery.css( elem, "display" ) === "none" || 4309 !jQuery.contains( elem.ownerDocument, elem ); 4310 }; 4311 4312 4313 4314function adjustCSS( elem, prop, valueParts, tween ) { 4315 var adjusted, 4316 scale = 1, 4317 maxIterations = 20, 4318 currentValue = tween ? 4319 function() { return tween.cur(); } : 4320 function() { return jQuery.css( elem, prop, "" ); }, 4321 initial = currentValue(), 4322 unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), 4323 4324 // Starting value computation is required for potential unit mismatches 4325 initialInUnit = ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && 4326 rcssNum.exec( jQuery.css( elem, prop ) ); 4327 4328 if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { 4329 4330 // Trust units reported by jQuery.css 4331 unit = unit || initialInUnit[ 3 ]; 4332 4333 // Make sure we update the tween properties later on 4334 valueParts = valueParts || []; 4335 4336 // Iteratively approximate from a nonzero starting point 4337 initialInUnit = +initial || 1; 4338 4339 do { 4340 4341 // If previous iteration zeroed out, double until we get *something*. 4342 // Use string for doubling so we don't accidentally see scale as unchanged below 4343 scale = scale || ".5"; 4344 4345 // Adjust and apply 4346 initialInUnit = initialInUnit / scale; 4347 jQuery.style( elem, prop, initialInUnit + unit ); 4348 4349 // Update scale, tolerating zero or NaN from tween.cur() 4350 // Break the loop if scale is unchanged or perfect, or if we've just had enough. 4351 } while ( 4352 scale !== ( scale = currentValue() / initial ) && scale !== 1 && --maxIterations 4353 ); 4354 } 4355 4356 if ( valueParts ) { 4357 initialInUnit = +initialInUnit || +initial || 0; 4358 4359 // Apply relative offset (+=/-=) if specified 4360 adjusted = valueParts[ 1 ] ? 4361 initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] : 4362 +valueParts[ 2 ]; 4363 if ( tween ) { 4364 tween.unit = unit; 4365 tween.start = initialInUnit; 4366 tween.end = adjusted; 4367 } 4368 } 4369 return adjusted; 4370} 4371 4372 4373// Multifunctional method to get and set values of a collection 4374// The value/s can optionally be executed if it's a function 4375var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { 4376 var i = 0, 4377 length = elems.length, 4378 bulk = key == null; 4379 4380 // Sets many values 4381 if ( jQuery.type( key ) === "object" ) { 4382 chainable = true; 4383 for ( i in key ) { 4384 access( elems, fn, i, key[ i ], true, emptyGet, raw ); 4385 } 4386 4387 // Sets one value 4388 } else if ( value !== undefined ) { 4389 chainable = true; 4390 4391 if ( !jQuery.isFunction( value ) ) { 4392 raw = true; 4393 } 4394 4395 if ( bulk ) { 4396 4397 // Bulk operations run against the entire set 4398 if ( raw ) { 4399 fn.call( elems, value ); 4400 fn = null; 4401 4402 // ...except when executing function values 4403 } else { 4404 bulk = fn; 4405 fn = function( elem, key, value ) {
4406 return bulk.call( jQuery( elem ), value ); 4407 }; 4408 } 4409 } 4410 4411 if ( fn ) { 4412 for ( ; i < length; i++ ) { 4413 fn( 4414 elems[ i ], 4415 key, 4416 raw ? value : value.call( elems[ i ], i, fn( elems[ i ], key ) ) 4417 ); 4418 } 4419 } 4420 } 4421 4422 return chainable ? 4423 elems : 4424 4425 // Gets 4426 bulk ? 4427 fn.call( elems ) : 4428 length ? fn( elems[ 0 ], key ) : emptyGet; 4429}; 4430var rcheckableType = ( /^(?:checkbox|radio)$/i ); 4431 4432var rtagName = ( /<([\w:-]+)/ ); 4433 4434var rscriptType = ( /^$|\/(?:java|ecma)script/i ); 4435 4436var rleadingWhitespace = ( /^\s+/ ); 4437 4438var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|" + 4439 "details|dialog|figcaption|figure|footer|header|hgroup|main|" + 4440 "mark|meter|nav|output|picture|progress|section|summary|template|time|video"; 4441 4442 4443 4444function createSafeFragment( document ) { 4445 var list = nodeNames.split( "|" ), 4446 safeFrag = document.createDocumentFragment(); 4447 4448 if ( safeFrag.createElement ) { 4449 while ( list.length ) { 4450 safeFrag.createElement( 4451 list.pop() 4452 ); 4453 } 4454 } 4455 return safeFrag; 4456} 4457 4458 4459( function() { 4460 var div = document.createElement( "div" ), 4461 fragment = document.createDocumentFragment(), 4462 input = document.createElement( "input" ); 4463 4464 // Setup 4465 div.innerHTML = " <link/><table></table><a href='/a'>a</a><input type='checkbox'/>"; 4466 4467 // IE strips leading whitespace when .innerHTML is used 4468 support.leadingWhitespace = div.firstChild.nodeType === 3; 4469 4470 // Make sure that tbody elements aren't automatically inserted 4471 // IE will insert them into empty tables 4472 support.tbody = !div.getElementsByTagName( "tbody" ).length; 4473 4474 // Make sure that link elements get serialized correctly by innerHTML 4475 // This requires a wrapper element in IE 4476 support.htmlSerialize = !!div.getElementsByTagName( "link" ).length; 4477 4478 // Makes sure cloning an html5 element does not cause problems 4479 // Where outerHTML is undefined, this still works 4480 support.html5Clone = 4481 document.createElement( "nav" ).cloneNode( true ).outerHTML !== "<:nav></:nav>"; 4482 4483 // Check if a disconnected checkbox will retain its checked 4484 // value of true after appended to the DOM (IE6/7) 4485 input.type = "checkbox"; 4486 input.checked = true; 4487 fragment.appendChild( input ); 4488 support.appendChecked = input.checked; 4489 4490 // Make sure textarea (and checkbox) defaultValue is properly cloned 4491 // Support: IE6-IE11+ 4492 div.innerHTML = "<textarea>x</textarea>"; 4493 support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; 4494 4495 // #11217 - WebKit loses check when the name is after the checked attribute 4496 fragment.appendChild( div ); 4497 4498 // Support: Windows Web Apps (WWA) 4499 // `name` and `type` must use .setAttribute for WWA (#14901) 4500 input = document.createElement( "input" ); 4501 input.setAttribute( "type", "radio" ); 4502 input.setAttribute( "checked", "checked" ); 4503 input.setAttribute( "name", "t" ); 4504 4505 div.appendChild( input ); 4506 4507 // Support: Safari 5.1, iOS 5.1, Android 4.x, Android 2.3 4508 // old WebKit doesn't clone checked state correctly in fragments 4509 support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; 4510 4511 // Support: IE<9 4512 // Cloned elements keep attachEvent handlers, we use addEventListener on IE9+ 4513 support.noCloneEvent = !!div.addEventListener; 4514 4515 // Support: IE<9 4516 // Since attributes and properties are the same in IE, 4517 // cleanData must set properties to undefined rather than use removeAttribute 4518 div[ jQuery.expando ] = 1; 4519 support.attributes = !div.getAttribute( jQuery.expando ); 4520} )(); 4521 4522 4523// We have to close these tags to support XHTML (#13200) 4524var wrapMap = { 4525 option: [ 1, "<select multiple='multiple'>", "</select>" ], 4526 legend: [ 1, "<fieldset>", "</fieldset>" ], 4527 area: [ 1, "<map>", "</map>" ], 4528 4529 // Support: IE8 4530 param: [ 1, "<object>", "</object>" ], 4531 thead: [ 1, "<table>", "</table>" ], 4532 tr: [ 2, "<table><tbody>", "</tbody></table>" ], 4533 col: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ], 4534 td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ], 4535 4536 // IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags, 4537 // unless wrapped in a div with non-breaking characters in front of it. 4538 _default: support.htmlSerialize ? [ 0, "", "" ] : [ 1, "X<div>", "</div>" ] 4539}; 4540 4541// Support: IE8-IE9 4542wrapMap.optgroup = wrapMap.option; 4543 4544wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; 4545wrapMap.th = wrapMap.td; 4546 4547 4548function getAll( context, tag ) { 4549 var elems, elem, 4550 i = 0, 4551 found = typeof context.getElementsByTagName !== "undefined" ? 4552 context.getElementsByTagName( tag || "*" ) : 4553 typeof context.querySelectorAll !== "undefined" ? 4554 context.querySelectorAll( tag || "*" ) : 4555 undefined; 4556 4557 if ( !found ) { 4558 for ( found = [], elems = context.childNodes || context; 4559 ( elem = elems[ i ] ) != null; 4560 i++ 4561 ) { 4562 if ( !tag || jQuery.nodeName( elem, tag ) ) { 4563 found.push( elem ); 4564 } else { 4565 jQuery.merge( found, getAll( elem, tag ) ); 4566 } 4567 } 4568 } 4569 4570 return tag === undefined || tag && jQuery.nodeName( context, tag ) ? 4571 jQuery.merge( [ context ], found ) : 4572 found; 4573} 4574 4575 4576// Mark scripts as having already been evaluated 4577function setGlobalEval( elems, refElements ) { 4578 var elem, 4579 i = 0; 4580 for ( ; ( elem = elems[ i ] ) != null; i++ ) { 4581 jQuery._data( 4582 elem, 4583 "globalEval", 4584 !refElements || jQuery._data( refElements[ i ], "globalEval" ) 4585 ); 4586 } 4587} 4588 4589
vendor: 45,546 bytes, lines 4590-6222
4590var rhtml = /<|&#?\w+;/, 4591 rtbody = /<tbody/i; 4592 4593function fixDefaultChecked( elem ) { 4594 if ( rcheckableType.test( elem.type ) ) { 4595 elem.defaultChecked = elem.checked; 4596 } 4597} 4598 4599function buildFragment( elems, context, scripts, selection, ignored ) { 4600 var j, elem, contains, 4601 tmp, tag, tbody, wrap, 4602 l = elems.length, 4603 4604 // Ensure a safe fragment 4605 safe = createSafeFragment( context ), 4606 4607 nodes = [], 4608 i = 0; 4609 4610 for ( ; i < l; i++ ) { 4611 elem = elems[ i ]; 4612 4613 if ( elem || elem === 0 ) { 4614 4615 // Add nodes directly 4616 if ( jQuery.type( elem ) === "object" ) { 4617 jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); 4618 4619 // Convert non-html into a text node 4620 } else if ( !rhtml.test( elem ) ) { 4621 nodes.push( context.createTextNode( elem ) ); 4622 4623 // Convert html into DOM nodes 4624 } else { 4625 tmp = tmp || safe.appendChild( context.createElement( "div" ) ); 4626 4627 // Deserialize a standard representation 4628 tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase(); 4629 wrap = wrapMap[ tag ] || wrapMap._default; 4630 4631 tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ]; 4632 4633 // Descend through wrappers to the right content 4634 j = wrap[ 0 ]; 4635 while ( j-- ) { 4636 tmp = tmp.lastChild; 4637 } 4638 4639 // Manually add leading whitespace removed by IE 4640 if ( !support.leadingWhitespace && rleadingWhitespace.test( elem ) ) { 4641 nodes.push( context.createTextNode( rleadingWhitespace.exec( elem )[ 0 ] ) ); 4642 } 4643 4644 // Remove IE's autoinserted <tbody> from table fragments 4645 if ( !support.tbody ) { 4646 4647 // String was a <table>, *may* have spurious <tbody> 4648 elem = tag === "table" && !rtbody.test( elem ) ? 4649 tmp.firstChild : 4650 4651 // String was a bare <thead> or <tfoot> 4652 wrap[ 1 ] === "<table>" && !rtbody.test( elem ) ? 4653 tmp : 4654 0; 4655 4656 j = elem && elem.childNodes.length; 4657 while ( j-- ) { 4658 if ( jQuery.nodeName( ( tbody = elem.childNodes[ j ] ), "tbody" ) && 4659 !tbody.childNodes.length ) { 4660 4661 elem.removeChild( tbody ); 4662 } 4663 } 4664 } 4665 4666 jQuery.merge( nodes, tmp.childNodes ); 4667 4668 // Fix #12392 for WebKit and IE > 9 4669 tmp.textContent = ""; 4670 4671 // Fix #12392 for oldIE 4672 while ( tmp.firstChild ) { 4673 tmp.removeChild( tmp.firstChild ); 4674 } 4675 4676 // Remember the top-level container for proper cleanup 4677 tmp = safe.lastChild; 4678 } 4679 } 4680 } 4681 4682 // Fix #11356: Clear elements from fragment 4683 if ( tmp ) { 4684 safe.removeChild( tmp ); 4685 } 4686 4687 // Reset defaultChecked for any radios and checkboxes 4688 // about to be appended to the DOM in IE 6/7 (#8060) 4689 if ( !support.appendChecked ) { 4690 jQuery.grep( getAll( nodes, "input" ), fixDefaultChecked ); 4691 } 4692 4693 i = 0; 4694 while ( ( elem = nodes[ i++ ] ) ) { 4695 4696 // Skip elements already in the context collection (trac-4087) 4697 if ( selection && jQuery.inArray( elem, selection ) > -1 ) { 4698 if ( ignored ) { 4699 ignored.push( elem ); 4700 } 4701 4702 continue; 4703 } 4704 4705 contains = jQuery.contains( elem.ownerDocument, elem ); 4706 4707 // Append to fragment 4708 tmp = getAll( safe.appendChild( elem ), "script" ); 4709 4710 // Preserve script evaluation history 4711 if ( contains ) { 4712 setGlobalEval( tmp ); 4713 } 4714 4715 // Capture executables 4716 if ( scripts ) { 4717 j = 0; 4718 while ( ( elem = tmp[ j++ ] ) ) { 4719 if ( rscriptType.test( elem.type || "" ) ) { 4720 scripts.push( elem ); 4721 } 4722 } 4723 } 4724 } 4725 4726 tmp = null; 4727 4728 return safe; 4729} 4730 4731 4732( function() { 4733 var i, eventName, 4734 div = document.createElement( "div" ); 4735 4736 // Support: IE<9 (lack submit/change bubble), Firefox (lack focus(in | out) events) 4737 for ( i in { submit: true, change: true, focusin: true } ) { 4738 eventName = "on" + i; 4739 4740 if ( !( support[ i ] = eventName in window ) ) { 4741 4742 // Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP) 4743 div.setAttribute( eventName, "t" ); 4744 support[ i ] = div.attributes[ eventName ].expando === false; 4745 } 4746 } 4747 4748 // Null elements to avoid leaks in IE. 4749 div = null; 4750} )(); 4751 4752 4753var rformElems = /^(?:input|select|textarea)$/i, 4754 rkeyEvent = /^key/, 4755 rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/, 4756 rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, 4757 rtypenamespace = /^([^.]*)(?:\.(.+)|)/; 4758 4759function returnTrue() { 4760 return true; 4761} 4762 4763function returnFalse() { 4764 return false; 4765} 4766 4767// Support: IE9 4768// See #13393 for more info 4769function safeActiveElement() { 4770 try { 4771 return document.activeElement; 4772 } catch ( err ) { } 4773} 4774 4775function on( elem, types, selector, data, fn, one ) { 4776 var origFn, type; 4777 4778 // Types can be a map of types/handlers 4779 if ( typeof types === "object" ) { 4780 4781 // ( types-Object, selector, data ) 4782 if ( typeof selector !== "string" ) { 4783 4784 // ( types-Object, data ) 4785 data = data || selector; 4786 selector = undefined; 4787 } 4788 for ( type in types ) { 4789 on( elem, type, selector, data, types[ type ], one ); 4790 } 4791 return elem; 4792 } 4793 4794 if ( data == null && fn == null ) { 4795 4796 // ( types, fn ) 4797 fn = selector; 4798 data = selector = undefined; 4799 } else if ( fn == null ) { 4800 if ( typeof selector === "string" ) { 4801 4802 // ( types, selector, fn ) 4803 fn = data; 4804 data = undefined; 4805 } else { 4806 4807 // ( types, data, fn ) 4808 fn = data; 4809 data = selector; 4810 selector = undefined; 4811 } 4812 } 4813 if ( fn === false ) { 4814 fn = returnFalse; 4815 } else if ( !fn ) { 4816 return elem; 4817 } 4818 4819 if ( one === 1 ) { 4820 origFn = fn; 4821 fn = function( event ) { 4822 4823 // Can use an empty set, since event contains the info 4824 jQuery().off( event ); 4825 return origFn.apply( this, arguments ); 4826 }; 4827 4828 // Use same guid so caller can remove using origFn 4829 fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); 4830 } 4831 return elem.each( function() { 4832 jQuery.event.add( this, types, fn, data, selector ); 4833 } ); 4834} 4835 4836/* 4837 * Helper functions for managing events -- not part of the public interface. 4838 * Props to Dean Edwards' addEvent library for many of the ideas. 4839 */ 4840jQuery.event = { 4841 4842 global: {}, 4843 4844 add: function( elem, types, handler, data, selector ) { 4845 var tmp, events, t, handleObjIn, 4846 special, eventHandle, handleObj, 4847 handlers, type, namespaces, origType, 4848 elemData = jQuery._data( elem ); 4849 4850 // Don't attach events to noData or text/comment nodes (but allow plain objects) 4851 if ( !elemData ) { 4852 return; 4853 } 4854 4855 // Caller can pass in an object of custom data in lieu of the handler 4856 if ( handler.handler ) { 4857 handleObjIn = handler; 4858 handler = handleObjIn.handler; 4859 selector = handleObjIn.selector; 4860 } 4861 4862 // Make sure that the handler has a unique ID, used to find/remove it later 4863 if ( !handler.guid ) { 4864 handler.guid = jQuery.guid++; 4865 } 4866 4867 // Init the element's event structure and main handler, if this is the first 4868 if ( !( events = elemData.events ) ) { 4869 events = elemData.events = {}; 4870 } 4871 if ( !( eventHandle = elemData.handle ) ) { 4872 eventHandle = elemData.handle = function( e ) { 4873 4874 // Discard the second event of a jQuery.event.trigger() and 4875 // when an event is called after a page has unloaded 4876 return typeof jQuery !== "undefined" && 4877 ( !e || jQuery.event.triggered !== e.type ) ? 4878 jQuery.event.dispatch.apply( eventHandle.elem, arguments ) : 4879 undefined; 4880 }; 4881 4882 // Add elem as a property of the handle fn to prevent a memory leak 4883 // with IE non-native events 4884 eventHandle.elem = elem; 4885 } 4886 4887 // Handle multiple events separated by a space 4888 types = ( types || "" ).match( rnotwhite ) || [ "" ]; 4889 t = types.length; 4890 while ( t-- ) { 4891 tmp = rtypenamespace.exec( types[ t ] ) || []; 4892 type = origType = tmp[ 1 ]; 4893 namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); 4894 4895 // There *must* be a type, no attaching namespace-only handlers 4896 if ( !type ) { 4897 continue; 4898 } 4899 4900 // If event changes its type, use the special event handlers for the changed type 4901 special = jQuery.event.special[ type ] || {}; 4902 4903 // If selector defined, determine special event api type, otherwise given type 4904 type = ( selector ? special.delegateType : special.bindType ) || type; 4905 4906 // Update special based on newly reset type 4907 special = jQuery.event.special[ type ] || {}; 4908 4909 // handleObj is passed to all event handlers 4910 handleObj = jQuery.extend( { 4911 type: type, 4912 origType: origType, 4913 data: data, 4914 handler: handler, 4915 guid: handler.guid, 4916 selector: selector, 4917 needsContext: selector && jQuery.expr.match.needsContext.test( selector ), 4918 namespace: namespaces.join( "." ) 4919 }, handleObjIn ); 4920 4921 // Init the event handler queue if we're the first 4922 if ( !( handlers = events[ type ] ) ) { 4923 handlers = events[ type ] = []; 4924 handlers.delegateCount = 0; 4925 4926 // Only use addEventListener/attachEvent if the special events handler returns false 4927 if ( !special.setup || 4928 special.setup.call( elem, data, namespaces, eventHandle ) === false ) { 4929 4930 // Bind the global event handler to the element 4931 if ( elem.addEventListener ) { 4932 elem.addEventListener( type, eventHandle, false ); 4933 4934 } else if ( elem.attachEvent ) { 4935 elem.attachEvent( "on" + type, eventHandle ); 4936 } 4937 } 4938 } 4939 4940 if ( special.add ) { 4941 special.add.call( elem, handleObj ); 4942 4943 if ( !handleObj.handler.guid ) { 4944 handleObj.handler.guid = handler.guid; 4945 } 4946 } 4947 4948 // Add to the element's handler list, delegates in front 4949 if ( selector ) { 4950 handlers.splice( handlers.delegateCount++, 0, handleObj ); 4951 } else { 4952 handlers.push( handleObj ); 4953 } 4954 4955 // Keep track of which events have ever been used, for event optimization 4956 jQuery.event.global[ type ] = true; 4957 } 4958 4959 // Nullify elem to prevent memory leaks in IE 4960 elem = null; 4961 }, 4962 4963 // Detach an event or set of events from an element 4964 remove: function( elem, types, handler, selector, mappedTypes ) { 4965 var j, handleObj, tmp, 4966 origCount, t, events, 4967 special, handlers, type, 4968 namespaces, origType, 4969 elemData = jQuery.hasData( elem ) && jQuery._data( elem ); 4970 4971 if ( !elemData || !( events = elemData.events ) ) { 4972 return; 4973 } 4974 4975 // Once for each type.namespace in types; type may be omitted 4976 types = ( types || "" ).match( rnotwhite ) || [ "" ]; 4977 t = types.length; 4978 while ( t-- ) { 4979 tmp = rtypenamespace.exec( types[ t ] ) || []; 4980 type = origType = tmp[ 1 ]; 4981 namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); 4982 4983 // Unbind all events (on this namespace, if provided) for the element 4984 if ( !type ) { 4985 for ( type in events ) { 4986 jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); 4987 } 4988 continue; 4989 } 4990 4991 special = jQuery.event.special[ type ] || {}; 4992 type = ( selector ? special.delegateType : special.bindType ) || type; 4993 handlers = events[ type ] || []; 4994 tmp = tmp[ 2 ] && 4995 new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ); 4996 4997 // Remove matching events 4998 origCount = j = handlers.length; 4999 while ( j-- ) { 5000 handleObj = handlers[ j ]; 5001 5002 if ( ( mappedTypes || origType === handleObj.origType ) && 5003 ( !handler || handler.guid === handleObj.guid ) && 5004 ( !tmp || tmp.test( handleObj.namespace ) ) && 5005 ( !selector || selector === handleObj.selector || 5006 selector === "**" && handleObj.selector ) ) { 5007 handlers.splice( j, 1 ); 5008 5009 if ( handleObj.selector ) { 5010 handlers.delegateCount--; 5011 } 5012 if ( special.remove ) { 5013 special.remove.call( elem, handleObj ); 5014 } 5015 } 5016 } 5017 5018 // Remove generic event handler if we removed something and no more handlers exist 5019 // (avoids potential for endless recursion during removal of special event handlers) 5020 if ( origCount && !handlers.length ) { 5021 if ( !special.teardown || 5022 special.teardown.call( elem, namespaces, elemData.handle ) === false ) { 5023 5024 jQuery.removeEvent( elem, type, elemData.handle ); 5025 } 5026 5027 delete events[ type ]; 5028 } 5029 } 5030 5031 // Remove the expando if it's no longer used 5032 if ( jQuery.isEmptyObject( events ) ) { 5033 delete elemData.handle; 5034 5035 // removeData also checks for emptiness and clears the expando if empty 5036 // so use it instead of delete 5037 jQuery._removeData( elem, "events" ); 5038 } 5039 }, 5040 5041 trigger: function( event, data, elem, onlyHandlers ) { 5042 var handle, ontype, cur, 5043 bubbleType, special, tmp, i, 5044 eventPath = [ elem || document ], 5045 type = hasOwn.call( event, "type" ) ? event.type : event, 5046 namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; 5047 5048 cur = tmp = elem = elem || document; 5049 5050 // Don't do events on text and comment nodes 5051 if ( elem.nodeType === 3 || elem.nodeType === 8 ) { 5052 return; 5053 } 5054 5055 // focus/blur morphs to focusin/out; ensure we're not firing them right now 5056 if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { 5057 return; 5058 } 5059 5060 if ( type.indexOf( "." ) > -1 ) { 5061 5062 // Namespaced trigger; create a regexp to match event type in handle() 5063 namespaces = type.split( "." ); 5064 type = namespaces.shift(); 5065 namespaces.sort(); 5066 } 5067 ontype = type.indexOf( ":" ) < 0 && "on" + type; 5068 5069 // Caller can pass in a jQuery.Event object, Object, or just an event type string 5070 event = event[ jQuery.expando ] ? 5071 event : 5072 new jQuery.Event( type, typeof event === "object" && event ); 5073 5074 // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) 5075 event.isTrigger = onlyHandlers ? 2 : 3; 5076 event.namespace = namespaces.join( "." ); 5077 event.rnamespace = event.namespace ? 5078 new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : 5079 null; 5080 5081 // Clean up the event in case it is being reused 5082 event.result = undefined; 5083 if ( !event.target ) { 5084 event.target = elem; 5085 } 5086 5087 // Clone any incoming data and prepend the event, creating the handler arg list 5088 data = data == null ? 5089 [ event ] : 5090 jQuery.makeArray( data, [ event ] ); 5091 5092 // Allow special events to draw outside the lines 5093 special = jQuery.event.special[ type ] || {}; 5094 if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { 5095 return; 5096 } 5097 5098 // Determine event propagation path in advance, per W3C events spec (#9951) 5099 // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) 5100 if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { 5101 5102 bubbleType = special.delegateType || type; 5103 if ( !rfocusMorph.test( bubbleType + type ) ) { 5104 cur = cur.parentNode; 5105 } 5106 for ( ; cur; cur = cur.parentNode ) { 5107 eventPath.push( cur ); 5108 tmp = cur; 5109 } 5110 5111 // Only add window if we got to document (e.g., not plain obj or detached DOM) 5112 if ( tmp === ( elem.ownerDocument || document ) ) { 5113 eventPath.push( tmp.defaultView || tmp.parentWindow || window ); 5114 } 5115 } 5116 5117 // Fire handlers on the event path 5118 i = 0; 5119 while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { 5120 5121 event.type = i > 1 ? 5122 bubbleType : 5123 special.bindType || type; 5124 5125 // jQuery handler 5126 handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && 5127 jQuery._data( cur, "handle" ); 5128 5129 if ( handle ) { 5130 handle.apply( cur, data ); 5131 } 5132 5133 // Native handler 5134 handle = ontype && cur[ ontype ]; 5135 if ( handle && handle.apply && acceptData( cur ) ) { 5136 event.result = handle.apply( cur, data ); 5137 if ( event.result === false ) { 5138 event.preventDefault(); 5139 } 5140 } 5141 } 5142 event.type = type; 5143 5144 // If nobody prevented the default action, do it now 5145 if ( !onlyHandlers && !event.isDefaultPrevented() ) { 5146 5147 if ( 5148 ( !special._default || 5149 special._default.apply( eventPath.pop(), data ) === false 5150 ) && acceptData( elem ) 5151 ) { 5152 5153 // Call a native DOM method on the target with the same name name as the event. 5154 // Can't use an .isFunction() check here because IE6/7 fails that test. 5155 // Don't do default actions on window, that's where global variables be (#6170) 5156 if ( ontype && elem[ type ] && !jQuery.isWindow( elem ) ) { 5157 5158 // Don't re-trigger an onFOO event when we call its FOO() method 5159 tmp = elem[ ontype ]; 5160 5161 if ( tmp ) { 5162 elem[ ontype ] = null; 5163 } 5164 5165 // Prevent re-triggering of the same event, since we already bubbled it above 5166 jQuery.event.triggered = type; 5167 try { 5168 elem[ type ](); 5169 } catch ( e ) { 5170 5171 // IE<9 dies on focus/blur to hidden element (#1486,#12518) 5172 // only reproducible on winXP IE8 native, not IE9 in IE8 mode 5173 } 5174 jQuery.event.triggered = undefined; 5175 5176 if ( tmp ) { 5177 elem[ ontype ] = tmp; 5178 } 5179 } 5180 } 5181 } 5182 5183 return event.result; 5184 }, 5185 5186 dispatch: function( event ) { 5187 5188 // Make a writable jQuery.Event from the native event object 5189 event = jQuery.event.fix( event ); 5190 5191 var i, j, ret, matched, handleObj, 5192 handlerQueue = [], 5193 args = slice.call( arguments ), 5194 handlers = ( jQuery._data( this, "events" ) || {} )[ event.type ] || [], 5195 special = jQuery.event.special[ event.type ] || {}; 5196 5197 // Use the fix-ed jQuery.Event rather than the (read-only) native event 5198 args[ 0 ] = event; 5199 event.delegateTarget = this; 5200 5201 // Call the preDispatch hook for the mapped type, and let it bail if desired 5202 if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { 5203 return; 5204 } 5205 5206 // Determine handlers 5207 handlerQueue = jQuery.event.handlers.call( this, event, handlers ); 5208 5209 // Run delegates first; they may want to stop propagation beneath us 5210 i = 0; 5211 while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { 5212 event.currentTarget = matched.elem; 5213 5214 j = 0; 5215 while ( ( handleObj = matched.handlers[ j++ ] ) && 5216 !event.isImmediatePropagationStopped() ) { 5217 5218 // Triggered event must either 1) have no namespace, or 2) have namespace(s) 5219 // a subset or equal to those in the bound event (both can have no namespace). 5220 if ( !event.rnamespace || event.rnamespace.test( handleObj.namespace ) ) { 5221 5222 event.handleObj = handleObj; 5223 event.data = handleObj.data; 5224 5225 ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle || 5226 handleObj.handler ).apply( matched.elem, args ); 5227 5228 if ( ret !== undefined ) { 5229 if ( ( event.result = ret ) === false ) { 5230 event.preventDefault(); 5231 event.stopPropagation(); 5232 } 5233 } 5234 } 5235 } 5236 } 5237 5238 // Call the postDispatch hook for the mapped type 5239 if ( special.postDispatch ) { 5240 special.postDispatch.call( this, event ); 5241 } 5242 5243 return event.result; 5244 }, 5245 5246 handlers: function( event, handlers ) { 5247 var i, matches, sel, handleObj, 5248 handlerQueue = [], 5249 delegateCount = handlers.delegateCount, 5250 cur = event.target; 5251 5252 // Support (at least): Chrome, IE9 5253 // Find delegate handlers 5254 // Black-hole SVG <use> instance trees (#13180) 5255 // 5256 // Support: Firefox<=42+ 5257 // Avoid non-left-click in FF but don't block IE radio events (#3861, gh-2343) 5258 if ( delegateCount && cur.nodeType && 5259 ( event.type !== "click" || isNaN( event.button ) || event.button < 1 ) ) { 5260 5261 /* jshint eqeqeq: false */ 5262 for ( ; cur != this; cur = cur.parentNode || this ) { 5263 /* jshint eqeqeq: true */ 5264 5265 // Don't check non-elements (#13208) 5266 // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) 5267 if ( cur.nodeType === 1 && ( cur.disabled !== true || event.type !== "click" ) ) { 5268 matches = []; 5269 for ( i = 0; i < delegateCount; i++ ) { 5270 handleObj = handlers[ i ]; 5271 5272 // Don't conflict with Object.prototype properties (#13203) 5273 sel = handleObj.selector + " "; 5274 5275 if ( matches[ sel ] === undefined ) { 5276 matches[ sel ] = handleObj.needsContext ? 5277 jQuery( sel, this ).index( cur ) > -1 : 5278 jQuery.find( sel, this, null, [ cur ] ).length; 5279 } 5280 if ( matches[ sel ] ) { 5281 matches.push( handleObj ); 5282 } 5283 } 5284 if ( matches.length ) { 5285 handlerQueue.push( { elem: cur, handlers: matches } ); 5286 } 5287 } 5288 } 5289 } 5290 5291 // Add the remaining (directly-bound) handlers 5292 if ( delegateCount < handlers.length ) { 5293 handlerQueue.push( { elem: this, handlers: handlers.slice( delegateCount ) } ); 5294 } 5295 5296 return handlerQueue; 5297 }, 5298 5299 fix: function( event ) { 5300 if ( event[ jQuery.expando ] ) { 5301 return event; 5302 } 5303 5304 // Create a writable copy of the event object and normalize some properties 5305 var i, prop, copy, 5306 type = event.type, 5307 originalEvent = event, 5308 fixHook = this.fixHooks[ type ]; 5309 5310 if ( !fixHook ) { 5311 this.fixHooks[ type ] = fixHook = 5312 rmouseEvent.test( type ) ? this.mouseHooks : 5313 rkeyEvent.test( type ) ? this.keyHooks : 5314 {}; 5315 } 5316 copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; 5317 5318 event = new jQuery.Event( originalEvent ); 5319 5320 i = copy.length; 5321 while ( i-- ) { 5322 prop = copy[ i ]; 5323 event[ prop ] = originalEvent[ prop ]; 5324 } 5325 5326 // Support: IE<9 5327 // Fix target property (#1925) 5328 if ( !event.target ) { 5329 event.target = originalEvent.srcElement || document; 5330 } 5331 5332 // Support: Safari 6-8+ 5333 // Target should not be a text node (#504, #13143) 5334 if ( event.target.nodeType === 3 ) { 5335 event.target = event.target.parentNode; 5336 } 5337 5338 // Support: IE<9 5339 // For mouse/key events, metaKey==false if it's undefined (#3368, #11328) 5340 event.metaKey = !!event.metaKey; 5341 5342 return fixHook.filter ? fixHook.filter( event, originalEvent ) : event; 5343 }, 5344 5345 // Includes some event props shared by KeyEvent and MouseEvent 5346 props: ( "altKey bubbles cancelable ctrlKey currentTarget detail eventPhase " + 5347 "metaKey relatedTarget shiftKey target timeStamp view which" ).split( " " ), 5348 5349 fixHooks: {}, 5350 5351 keyHooks: { 5352 props: "char charCode key keyCode".split( " " ), 5353 filter: function( event, original ) { 5354 5355 // Add which for key events 5356 if ( event.which == null ) { 5357 event.which = original.charCode != null ? original.charCode : original.keyCode; 5358 } 5359 5360 return event; 5361 } 5362 }, 5363 5364 mouseHooks: { 5365 props: ( "button buttons clientX clientY fromElement offsetX offsetY " + 5366 "pageX pageY screenX screenY toElement" ).split( " " ), 5367 filter: function( event, original ) { 5368 var body, eventDoc, doc, 5369 button = original.button, 5370 fromElement = original.fromElement; 5371 5372 // Calculate pageX/Y if missing and clientX/Y available 5373 if ( event.pageX == null && original.clientX != null ) { 5374 eventDoc = event.target.ownerDocument || document; 5375 doc = eventDoc.documentElement; 5376 body = eventDoc.body; 5377 5378 event.pageX = original.clientX + 5379 ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - 5380 ( doc && doc.clientLeft || body && body.clientLeft || 0 ); 5381 event.pageY = original.clientY + 5382 ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - 5383 ( doc && doc.clientTop || body && body.clientTop || 0 ); 5384 } 5385 5386 // Add relatedTarget, if necessary 5387 if ( !event.relatedTarget && fromElement ) { 5388 event.relatedTarget = fromElement === event.target ? 5389 original.toElement : 5390 fromElement; 5391 } 5392 5393 // Add which for click: 1 === left; 2 === middle; 3 === right 5394 // Note: button is not normalized, so don't use it 5395 if ( !event.which && button !== undefined ) { 5396 event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) ); 5397 } 5398 5399 return event; 5400 } 5401 }, 5402 5403 special: { 5404 load: { 5405 5406 // Prevent triggered image.load events from bubbling to window.load 5407 noBubble: true 5408 }, 5409 focus: { 5410 5411 // Fire native event if possible so blur/focus sequence is correct 5412 trigger: function() { 5413 if ( this !== safeActiveElement() && this.focus ) { 5414 try { 5415 this.focus(); 5416 return false; 5417 } catch ( e ) { 5418 5419 // Support: IE<9 5420 // If we error on focus to hidden element (#1486, #12518), 5421 // let .trigger() run the handlers 5422 } 5423 } 5424 }, 5425 delegateType: "focusin" 5426 }, 5427 blur: { 5428 trigger: function() { 5429 if ( this === safeActiveElement() && this.blur ) { 5430 this.blur(); 5431 return false; 5432 } 5433 }, 5434 delegateType: "focusout" 5435 }, 5436 click: { 5437 5438 // For checkbox, fire native event so checked state will be right 5439 trigger: function() { 5440 if ( jQuery.nodeName( this, "input" ) && this.type === "checkbox" && this.click ) { 5441 this.click(); 5442 return false; 5443 } 5444 }, 5445 5446 // For cross-browser consistency, don't fire native .click() on links 5447 _default: function( event ) { 5448 return jQuery.nodeName( event.target, "a" ); 5449 } 5450 }, 5451 5452 beforeunload: { 5453 postDispatch: function( event ) { 5454 5455 // Support: Firefox 20+ 5456 // Firefox doesn't alert if the returnValue field is not set. 5457 if ( event.result !== undefined && event.originalEvent ) { 5458 event.originalEvent.returnValue = event.result; 5459 } 5460 } 5461 } 5462 }, 5463 5464 // Piggyback on a donor event to simulate a different one 5465 simulate: function( type, elem, event ) { 5466 var e = jQuery.extend( 5467 new jQuery.Event(), 5468 event, 5469 { 5470 type: type, 5471 isSimulated: true 5472 5473 // Previously, `originalEvent: {}` was set here, so stopPropagation call 5474 // would not be triggered on donor event, since in our own 5475 // jQuery.event.stopPropagation function we had a check for existence of 5476 // originalEvent.stopPropagation method, so, consequently it would be a noop. 5477 // 5478 // Guard for simulated events was moved to jQuery.event.stopPropagation function 5479 // since `originalEvent` should point to the original event for the 5480 // constancy with other events and for more focused logic 5481 } 5482 ); 5483 5484 jQuery.event.trigger( e, null, elem ); 5485 5486 if ( e.isDefaultPrevented() ) { 5487 event.preventDefault(); 5488 } 5489 } 5490}; 5491 5492jQuery.removeEvent = document.removeEventListener ? 5493 function( elem, type, handle ) { 5494 5495 // This "if" is needed for plain objects 5496 if ( elem.removeEventListener ) { 5497 elem.removeEventListener( type, handle ); 5498 } 5499 } : 5500 function( elem, type, handle ) { 5501 var name = "on" + type; 5502 5503 if ( elem.detachEvent ) { 5504 5505 // #8545, #7054, preventing memory leaks for custom events in IE6-8 5506 // detachEvent needed property on element, by name of that event, 5507 // to properly expose it to GC 5508 if ( typeof elem[ name ] === "undefined" ) { 5509 elem[ name ] = null; 5510 } 5511 5512 elem.detachEvent( name, handle ); 5513 } 5514 }; 5515 5516jQuery.Event = function( src, props ) { 5517 5518 // Allow instantiation without the 'new' keyword 5519 if ( !( this instanceof jQuery.Event ) ) { 5520 return new jQuery.Event( src, props ); 5521 } 5522 5523 // Event object 5524 if ( src && src.type ) { 5525 this.originalEvent = src; 5526 this.type = src.type; 5527 5528 // Events bubbling up the document may have been marked as prevented 5529 // by a handler lower down the tree; reflect the correct value. 5530 this.isDefaultPrevented = src.defaultPrevented || 5531 src.defaultPrevented === undefined && 5532 5533 // Support: IE < 9, Android < 4.0 5534 src.returnValue === false ? 5535 returnTrue : 5536 returnFalse; 5537 5538 // Event type 5539 } else { 5540 this.type = src; 5541 } 5542 5543 // Put explicitly provided properties onto the event object 5544 if ( props ) { 5545 jQuery.extend( this, props ); 5546 } 5547 5548 // Create a timestamp if incoming event doesn't have one 5549 this.timeStamp = src && src.timeStamp || jQuery.now(); 5550 5551 // Mark it as fixed 5552 this[ jQuery.expando ] = true; 5553}; 5554 5555// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding 5556// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html 5557jQuery.Event.prototype = { 5558 constructor: jQuery.Event, 5559 isDefaultPrevented: returnFalse, 5560 isPropagationStopped: returnFalse, 5561 isImmediatePropagationStopped: returnFalse, 5562 5563 preventDefault: function() { 5564 var e = this.originalEvent; 5565 5566 this.isDefaultPrevented = returnTrue; 5567 if ( !e ) { 5568 return; 5569 } 5570 5571 // If preventDefault exists, run it on the original event 5572 if ( e.preventDefault ) { 5573 e.preventDefault(); 5574 5575 // Support: IE 5576 // Otherwise set the returnValue property of the original event to false 5577 } else { 5578 e.returnValue = false; 5579 } 5580 }, 5581 stopPropagation: function() { 5582 var e = this.originalEvent; 5583 5584 this.isPropagationStopped = returnTrue; 5585 5586 if ( !e || this.isSimulated ) { 5587 return; 5588 } 5589 5590 // If stopPropagation exists, run it on the original event 5591 if ( e.stopPropagation ) { 5592 e.stopPropagation(); 5593 } 5594 5595 // Support: IE 5596 // Set the cancelBubble property of the original event to true 5597 e.cancelBubble = true; 5598 }, 5599 stopImmediatePropagation: function() { 5600 var e = this.originalEvent; 5601 5602 this.isImmediatePropagationStopped = returnTrue; 5603 5604 if ( e && e.stopImmediatePropagation ) { 5605 e.stopImmediatePropagation(); 5606 } 5607 5608 this.stopPropagation(); 5609 } 5610}; 5611 5612// Create mouseenter/leave events using mouseover/out and event-time checks 5613// so that event delegation works in jQuery. 5614// Do the same for pointerenter/pointerleave and pointerover/pointerout 5615// 5616// Support: Safari 7 only 5617// Safari sends mouseenter too often; see: 5618// https://code.google.com/p/chromium/issues/detail?id=470258 5619// for the description of the bug (it existed in older Chrome versions as well). 5620jQuery.each( { 5621 mouseenter: "mouseover", 5622 mouseleave: "mouseout", 5623 pointerenter: "pointerover", 5624 pointerleave: "pointerout" 5625}, function( orig, fix ) { 5626 jQuery.event.special[ orig ] = { 5627 delegateType: fix, 5628 bindType: fix, 5629 5630 handle: function( event ) { 5631 var ret, 5632 target = this, 5633 related = event.relatedTarget, 5634 handleObj = event.handleObj; 5635 5636 // For mouseenter/leave call the handler if related is outside the target. 5637 // NB: No relatedTarget if the mouse left/entered the browser window 5638 if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) { 5639 event.type = handleObj.origType; 5640 ret = handleObj.handler.apply( this, arguments ); 5641 event.type = fix; 5642 } 5643 return ret; 5644 } 5645 }; 5646} ); 5647 5648// IE submit delegation 5649if ( !support.submit ) { 5650 5651 jQuery.event.special.submit = { 5652 setup: function() { 5653 5654 // Only need this for delegated form submit events 5655 if ( jQuery.nodeName( this, "form" ) ) { 5656 return false; 5657 } 5658 5659 // Lazy-add a submit handler when a descendant form may potentially be submitted 5660 jQuery.event.add( this, "click._submit keypress._submit", function( e ) { 5661 5662 // Node name check avoids a VML-related crash in IE (#9807) 5663 var elem = e.target, 5664 form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? 5665 5666 // Support: IE <=8 5667 // We use jQuery.prop instead of elem.form 5668 // to allow fixing the IE8 delegated submit issue (gh-2332) 5669 // by 3rd party polyfills/workarounds. 5670 jQuery.prop( elem, "form" ) : 5671 undefined; 5672 5673 if ( form && !jQuery._data( form, "submit" ) ) { 5674 jQuery.event.add( form, "submit._submit", function( event ) { 5675 event._submitBubble = true; 5676 } ); 5677 jQuery._data( form, "submit", true ); 5678 } 5679 } ); 5680 5681 // return undefined since we don't need an event listener 5682 }, 5683 5684 postDispatch: function( event ) { 5685 5686 // If form was submitted by the user, bubble the event up the tree 5687 if ( event._submitBubble ) { 5688 delete event._submitBubble; 5689 if ( this.parentNode && !event.isTrigger ) { 5690 jQuery.event.simulate( "submit", this.parentNode, event ); 5691 } 5692 } 5693 }, 5694 5695 teardown: function() { 5696 5697 // Only need this for delegated form submit events 5698 if ( jQuery.nodeName( this, "form" ) ) { 5699 return false; 5700 } 5701 5702 // Remove delegated handlers; cleanData eventually reaps submit handlers attached above 5703 jQuery.event.remove( this, "._submit" ); 5704 } 5705 }; 5706} 5707 5708// IE change delegation and checkbox/radio fix 5709if ( !support.change ) { 5710 5711 jQuery.event.special.change = { 5712 5713 setup: function() { 5714 5715 if ( rformElems.test( this.nodeName ) ) { 5716 5717 // IE doesn't fire change on a check/radio until blur; trigger it on click 5718 // after a propertychange. Eat the blur-change in special.change.handle. 5719 // This still fires onchange a second time for check/radio after blur. 5720 if ( this.type === "checkbox" || this.type === "radio" ) { 5721 jQuery.event.add( this, "propertychange._change", function( event ) { 5722 if ( event.originalEvent.propertyName === "checked" ) { 5723 this._justChanged = true; 5724 } 5725 } ); 5726 jQuery.event.add( this, "click._change", function( event ) { 5727 if ( this._justChanged && !event.isTrigger ) { 5728 this._justChanged = false; 5729 } 5730 5731 // Allow triggered, simulated change events (#11500) 5732 jQuery.event.simulate( "change", this, event ); 5733 } ); 5734 } 5735 return false; 5736 } 5737 5738 // Delegated event; lazy-add a change handler on descendant inputs 5739 jQuery.event.add( this, "beforeactivate._change", function( e ) { 5740 var elem = e.target; 5741 5742 if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "change" ) ) { 5743 jQuery.event.add( elem, "change._change", function( event ) { 5744 if ( this.parentNode && !event.isSimulated && !event.isTrigger ) { 5745 jQuery.event.simulate( "change", this.parentNode, event ); 5746 } 5747 } ); 5748 jQuery._data( elem, "change", true ); 5749 } 5750 } ); 5751 }, 5752 5753 handle: function( event ) { 5754 var elem = event.target; 5755 5756 // Swallow native change events from checkbox/radio, we already triggered them above 5757 if ( this !== elem || event.isSimulated || event.isTrigger || 5758 ( elem.type !== "radio" && elem.type !== "checkbox" ) ) { 5759 5760 return event.handleObj.handler.apply( this, arguments ); 5761 } 5762 }, 5763 5764 teardown: function() { 5765 jQuery.event.remove( this, "._change" ); 5766 5767 return !rformElems.test( this.nodeName ); 5768 } 5769 }; 5770} 5771 5772// Support: Firefox 5773// Firefox doesn't have focus(in | out) events 5774// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 5775// 5776// Support: Chrome, Safari 5777// focus(in | out) events fire after focus & blur events, 5778// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order 5779// Related ticket - https://code.google.com/p/chromium/issues/detail?id=449857 5780if ( !support.focusin ) { 5781 jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) { 5782 5783 // Attach a single capturing handler on the document while someone wants focusin/focusout 5784 var handler = function( event ) { 5785 jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) ); 5786 }; 5787 5788 jQuery.event.special[ fix ] = { 5789 setup: function() { 5790 var doc = this.ownerDocument || this, 5791 attaches = jQuery._data( doc, fix ); 5792 5793 if ( !attaches ) { 5794 doc.addEventListener( orig, handler, true ); 5795 } 5796 jQuery._data( doc, fix, ( attaches || 0 ) + 1 ); 5797 }, 5798 teardown: function() { 5799 var doc = this.ownerDocument || this, 5800 attaches = jQuery._data( doc, fix ) - 1; 5801 5802 if ( !attaches ) { 5803 doc.removeEventListener( orig, handler, true ); 5804 jQuery._removeData( doc, fix ); 5805 } else { 5806 jQuery._data( doc, fix, attaches ); 5807 } 5808 } 5809 }; 5810 } ); 5811} 5812 5813jQuery.fn.extend( { 5814 5815 on: function( types, selector, data, fn ) { 5816 return on( this, types, selector, data, fn ); 5817 }, 5818 one: function( types, selector, data, fn ) { 5819 return on( this, types, selector, data, fn, 1 ); 5820 }, 5821 off: function( types, selector, fn ) { 5822 var handleObj, type; 5823 if ( types && types.preventDefault && types.handleObj ) { 5824 5825 // ( event ) dispatched jQuery.Event 5826 handleObj = types.handleObj; 5827 jQuery( types.delegateTarget ).off( 5828 handleObj.namespace ? 5829 handleObj.origType + "." + handleObj.namespace : 5830 handleObj.origType, 5831 handleObj.selector, 5832 handleObj.handler 5833 ); 5834 return this; 5835 } 5836 if ( typeof types === "object" ) { 5837 5838 // ( types-object [, selector] ) 5839 for ( type in types ) { 5840 this.off( type, selector, types[ type ] ); 5841 } 5842 return this; 5843 } 5844 if ( selector === false || typeof selector === "function" ) { 5845 5846 // ( types [, fn] ) 5847 fn = selector; 5848 selector = undefined; 5849 } 5850 if ( fn === false ) { 5851 fn = returnFalse; 5852 } 5853 return this.each( function() { 5854 jQuery.event.remove( this, types, fn, selector ); 5855 } ); 5856 }, 5857 5858 trigger: function( type, data ) { 5859 return this.each( function() { 5860 jQuery.event.trigger( type, data, this ); 5861 } ); 5862 }, 5863 triggerHandler: function( type, data ) { 5864 var elem = this[ 0 ]; 5865 if ( elem ) { 5866 return jQuery.event.trigger( type, data, elem, true ); 5867 } 5868 } 5869} ); 5870 5871 5872var rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g, 5873 rnoshimcache = new RegExp( "<(?:" + nodeNames + ")[\\s/>]", "i" ), 5874 rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi, 5875 5876 // Support: IE 10-11, Edge 10240+ 5877 // In IE/Edge using regex groups here causes severe slowdowns. 5878 // See https://connect.microsoft.com/IE/feedback/details/1736512/ 5879 rnoInnerhtml = /<script|<style|<link/i, 5880 5881 // checked="checked" or checked 5882 rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i, 5883 rscriptTypeMasked = /^true\/(.*)/, 5884 rcleanScript = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g, 5885 safeFragment = createSafeFragment( document ), 5886 fragmentDiv = safeFragment.appendChild( document.createElement( "div" ) ); 5887 5888// Support: IE<8 5889// Manipulating tables requires a tbody 5890function manipulationTarget( elem, content ) { 5891 return jQuery.nodeName( elem, "table" ) && 5892 jQuery.nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ? 5893 5894 elem.getElementsByTagName( "tbody" )[ 0 ] || 5895 elem.appendChild( elem.ownerDocument.createElement( "tbody" ) ) : 5896 elem; 5897} 5898 5899// Replace/restore the type attribute of script elements for safe DOM manipulation 5900function disableScript( elem ) { 5901 elem.type = ( jQuery.find.attr( elem, "type" ) !== null ) + "/" + elem.type; 5902 return elem; 5903} 5904function restoreScript( elem ) { 5905 var match = rscriptTypeMasked.exec( elem.type ); 5906 if ( match ) { 5907 elem.type = match[ 1 ]; 5908 } else { 5909 elem.removeAttribute( "type" ); 5910 } 5911 return elem; 5912} 5913 5914function cloneCopyEvent( src, dest ) { 5915 if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) { 5916 return; 5917 } 5918 5919 var type, i, l, 5920 oldData = jQuery._data( src ), 5921 curData = jQuery._data( dest, oldData ), 5922 events = oldData.events; 5923 5924 if ( events ) { 5925 delete curData.handle; 5926 curData.events = {}; 5927 5928 for ( type in events ) { 5929 for ( i = 0, l = events[ type ].length; i < l; i++ ) { 5930 jQuery.event.add( dest, type, events[ type ][ i ] ); 5931 } 5932 } 5933 } 5934 5935 // make the cloned public data object a copy from the original 5936 if ( curData.data ) { 5937 curData.data = jQuery.extend( {}, curData.data ); 5938 } 5939} 5940 5941function fixCloneNodeIssues( src, dest ) { 5942 var nodeName, e, data; 5943 5944 // We do not need to do anything for non-Elements 5945 if ( dest.nodeType !== 1 ) { 5946 return; 5947 } 5948 5949 nodeName = dest.nodeName.toLowerCase(); 5950 5951 // IE6-8 copies events bound via attachEvent when using cloneNode. 5952 if ( !support.noCloneEvent && dest[ jQuery.expando ] ) { 5953 data = jQuery._data( dest ); 5954 5955 for ( e in data.events ) { 5956 jQuery.removeEvent( dest, e, data.handle ); 5957 } 5958 5959 // Event data gets referenced instead of copied if the expando gets copied too 5960 dest.removeAttribute( jQuery.expando ); 5961 } 5962 5963 // IE blanks contents when cloning scripts, and tries to evaluate newly-set text 5964 if ( nodeName === "script" && dest.text !== src.text ) { 5965 disableScript( dest ).text = src.text; 5966 restoreScript( dest ); 5967 5968 // IE6-10 improperly clones children of object elements using classid. 5969 // IE10 throws NoModificationAllowedError if parent is null, #12132. 5970 } else if ( nodeName === "object" ) { 5971 if ( dest.parentNode ) { 5972 dest.outerHTML = src.outerHTML; 5973 } 5974 5975 // This path appears unavoidable for IE9. When cloning an object 5976 // element in IE9, the outerHTML strategy above is not sufficient. 5977 // If the src has innerHTML and the destination does not, 5978 // copy the src.innerHTML into the dest.innerHTML. #10324 5979 if ( support.html5Clone && ( src.innerHTML && !jQuery.trim( dest.innerHTML ) ) ) { 5980 dest.innerHTML = src.innerHTML; 5981 } 5982 5983 } else if ( nodeName === "input" && rcheckableType.test( src.type ) ) { 5984 5985 // IE6-8 fails to persist the checked state of a cloned checkbox 5986 // or radio button. Worse, IE6-7 fail to give the cloned element 5987 // a checked appearance if the defaultChecked value isn't also set 5988 5989 dest.defaultChecked = dest.checked = src.checked; 5990 5991 // IE6-7 get confused and end up setting the value of a cloned 5992 // checkbox/radio button to an empty string instead of "on" 5993 if ( dest.value !== src.value ) { 5994 dest.value = src.value; 5995 } 5996 5997 // IE6-8 fails to return the selected option to the default selected 5998 // state when cloning options 5999 } else if ( nodeName === "option" ) { 6000 dest.defaultSelected = dest.selected = src.defaultSelected; 6001 6002 // IE6-8 fails to set the defaultValue to the correct value when 6003 // cloning other types of input fields 6004 } else if ( nodeName === "input" || nodeName === "textarea" ) { 6005 dest.defaultValue = src.defaultValue; 6006 } 6007} 6008 6009function domManip( collection, args, callback, ignored ) { 6010 6011 // Flatten any nested arrays 6012 args = concat.apply( [], args ); 6013 6014 var first, node, hasScripts, 6015 scripts, doc, fragment, 6016 i = 0, 6017 l = collection.length, 6018 iNoClone = l - 1, 6019 value = args[ 0 ], 6020 isFunction = jQuery.isFunction( value ); 6021 6022 // We can't cloneNode fragments that contain checked, in WebKit 6023 if ( isFunction || 6024 ( l > 1 && typeof value === "string" && 6025 !support.checkClone && rchecked.test( value ) ) ) { 6026 return collection.each( function( index ) { 6027 var self = collection.eq( index ); 6028 if ( isFunction ) { 6029 args[ 0 ] = value.call( this, index, self.html() ); 6030 } 6031 domManip( self, args, callback, ignored ); 6032 } ); 6033 } 6034 6035 if ( l ) { 6036 fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); 6037 first = fragment.firstChild; 6038 6039 if ( fragment.childNodes.length === 1 ) { 6040 fragment = first; 6041 } 6042 6043 // Require either new content or an interest in ignored elements to invoke the callback 6044 if ( first || ignored ) { 6045 scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); 6046 hasScripts = scripts.length; 6047 6048 // Use the original fragment for the last item 6049 // instead of the first because it can end up 6050 // being emptied incorrectly in certain situations (#8070). 6051 for ( ; i < l; i++ ) { 6052 node = fragment; 6053 6054 if ( i !== iNoClone ) { 6055 node = jQuery.clone( node, true, true ); 6056 6057 // Keep references to cloned scripts for later restoration 6058 if ( hasScripts ) { 6059 6060 // Support: Android<4.1, PhantomJS<2 6061 // push.apply(_, arraylike) throws on ancient WebKit 6062 jQuery.merge( scripts, getAll( node, "script" ) ); 6063 } 6064 } 6065 6066 callback.call( collection[ i ], node, i ); 6067 } 6068 6069 if ( hasScripts ) { 6070 doc = scripts[ scripts.length - 1 ].ownerDocument; 6071 6072 // Reenable scripts 6073 jQuery.map( scripts, restoreScript ); 6074 6075 // Evaluate executable scripts on first document insertion 6076 for ( i = 0; i < hasScripts; i++ ) { 6077 node = scripts[ i ]; 6078 if ( rscriptType.test( node.type || "" ) && 6079 !jQuery._data( node, "globalEval" ) && 6080 jQuery.contains( doc, node ) ) { 6081 6082 if ( node.src ) { 6083 6084 // Optional AJAX dependency, but won't run scripts if not present 6085 if ( jQuery._evalUrl ) { 6086 jQuery._evalUrl( node.src ); 6087 } 6088 } else { 6089 jQuery.globalEval( 6090 ( node.text || node.textContent || node.innerHTML || "" ) 6091 .replace( rcleanScript, "" ) 6092 ); 6093 } 6094 } 6095 } 6096 } 6097 6098 // Fix #11809: Avoid leaking memory 6099 fragment = first = null; 6100 } 6101 } 6102 6103 return collection; 6104} 6105 6106function remove( elem, selector, keepData ) { 6107 var node, 6108 elems = selector ? jQuery.filter( selector, elem ) : elem, 6109 i = 0; 6110 6111 for ( ; ( node = elems[ i ] ) != null; i++ ) { 6112 6113 if ( !keepData && node.nodeType === 1 ) { 6114 jQuery.cleanData( getAll( node ) ); 6115 } 6116 6117 if ( node.parentNode ) { 6118 if ( keepData && jQuery.contains( node.ownerDocument, node ) ) { 6119 setGlobalEval( getAll( node, "script" ) ); 6120 } 6121 node.parentNode.removeChild( node ); 6122 } 6123 } 6124 6125 return elem; 6126} 6127 6128jQuery.extend( { 6129 htmlPrefilter: function( html ) { 6130 return html.replace( rxhtmlTag, "<$1></$2>" ); 6131 }, 6132 6133 clone: function( elem, dataAndEvents, deepDataAndEvents ) { 6134 var destElements, node, clone, i, srcElements, 6135 inPage = jQuery.contains( elem.ownerDocument, elem ); 6136 6137 if ( support.html5Clone || jQuery.isXMLDoc( elem ) || 6138 !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) { 6139 6140 clone = elem.cloneNode( true ); 6141 6142 // IE<=8 does not properly clone detached, unknown element nodes 6143 } else { 6144 fragmentDiv.innerHTML = elem.outerHTML; 6145 fragmentDiv.removeChild( clone = fragmentDiv.firstChild ); 6146 } 6147 6148 if ( ( !support.noCloneEvent || !support.noCloneChecked ) && 6149 ( elem.nodeType === 1 || elem.nodeType === 11 ) && !jQuery.isXMLDoc( elem ) ) { 6150 6151 // We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2 6152 destElements = getAll( clone ); 6153 srcElements = getAll( elem ); 6154 6155 // Fix all IE cloning issues 6156 for ( i = 0; ( node = srcElements[ i ] ) != null; ++i ) { 6157 6158 // Ensure that the destination node is not null; Fixes #9587 6159 if ( destElements[ i ] ) { 6160 fixCloneNodeIssues( node, destElements[ i ] ); 6161 } 6162 } 6163 } 6164 6165 // Copy the events from the original to the clone 6166 if ( dataAndEvents ) { 6167 if ( deepDataAndEvents ) { 6168 srcElements = srcElements || getAll( elem ); 6169 destElements = destElements || getAll( clone ); 6170 6171 for ( i = 0; ( node = srcElements[ i ] ) != null; i++ ) { 6172 cloneCopyEvent( node, destElements[ i ] ); 6173 } 6174 } else { 6175 cloneCopyEvent( elem, clone ); 6176 } 6177 } 6178 6179 // Preserve script evaluation history 6180 destElements = getAll( clone, "script" ); 6181 if ( destElements.length > 0 ) { 6182 setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); 6183 } 6184 6185 destElements = srcElements = node = null; 6186 6187 // Return the cloned set 6188 return clone; 6189 }, 6190 6191 cleanData: function( elems, /* internal */ forceAcceptData ) { 6192 var elem, type, id, data, 6193 i = 0, 6194 internalKey = jQuery.expando, 6195 cache = jQuery.cache, 6196 attributes = support.attributes, 6197 special = jQuery.event.special; 6198 6199 for ( ; ( elem = elems[ i ] ) != null; i++ ) { 6200 if ( forceAcceptData || acceptData( elem ) ) { 6201 6202 id = elem[ internalKey ]; 6203 data = id && cache[ id ]; 6204 6205 if ( data ) { 6206 if ( data.events ) { 6207 for ( type in data.events ) { 6208 if ( special[ type ] ) { 6209 jQuery.event.remove( elem, type ); 6210 6211 // This is a shortcut to avoid jQuery.event.remove's overhead 6212 } else { 6213 jQuery.removeEvent( elem, type, data.handle ); 6214 } 6215 } 6216 } 6217 6218 // Remove cache only if it was not already removed by jQuery.event.remove 6219 if ( cache[ id ] ) { 6220 6221 delete cache[ id ]; 6222
6223 // Support: IE<9 6224 // IE does not allow us to delete expando properties from nodes 6225 // IE creates expando attributes along with the property 6226 // IE does not have a removeAttribute function on Document nodes 6227 if ( !attributes && typeof elem.removeAttribute !== "undefined" ) { 6228 elem.removeAttribute( internalKey ); 6229 6230 // Webkit & Blink performance suffers when deleting properties 6231 // from DOM nodes, so set to undefined instead 6232 // https://code.google.com/p/chromium/issues/detail?id=378607 6233 } else { 6234 elem[ internalKey ] = undefined; 6235 } 6236 6237 deletedIds.push( id ); 6238 } 6239 } 6240 } 6241 } 6242 } 6243} ); 6244 6245jQuery.fn.extend( { 6246 6247 // Keep domManip exposed until 3.0 (gh-2225) 6248 domManip: domManip, 6249 6250 detach: function( selector ) { 6251 return remove( this, selector, true ); 6252 }, 6253 6254 remove: function( selector ) { 6255 return remove( this, selector ); 6256 }, 6257 6258 text: function( value ) { 6259 return access( this, function( value ) { 6260 return value === undefined ? 6261 jQuery.text( this ) : 6262 this.empty().append( 6263 ( this[ 0 ] && this[ 0 ].ownerDocument || document ).createTextNode( value ) 6264 ); 6265 }, null, value, arguments.length ); 6266 }, 6267 6268 append: function() { 6269 return domManip( this, arguments, function( elem ) { 6270 if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { 6271 var target = manipulationTarget( this, elem ); 6272 target.appendChild( elem ); 6273 } 6274 } ); 6275 }, 6276
vendor: 4,288 bytes, lines 6277-6450
6277 prepend: function() { 6278 return domManip( this, arguments, function( elem ) { 6279 if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { 6280 var target = manipulationTarget( this, elem ); 6281 target.insertBefore( elem, target.firstChild ); 6282 } 6283 } ); 6284 }, 6285 6286 before: function() { 6287 return domManip( this, arguments, function( elem ) { 6288 if ( this.parentNode ) { 6289 this.parentNode.insertBefore( elem, this ); 6290 } 6291 } ); 6292 }, 6293 6294 after: function() { 6295 return domManip( this, arguments, function( elem ) { 6296 if ( this.parentNode ) { 6297 this.parentNode.insertBefore( elem, this.nextSibling ); 6298 } 6299 } ); 6300 }, 6301 6302 empty: function() { 6303 var elem, 6304 i = 0; 6305 6306 for ( ; ( elem = this[ i ] ) != null; i++ ) { 6307 6308 // Remove element nodes and prevent memory leaks 6309 if ( elem.nodeType === 1 ) { 6310 jQuery.cleanData( getAll( elem, false ) ); 6311 } 6312 6313 // Remove any remaining nodes 6314 while ( elem.firstChild ) { 6315 elem.removeChild( elem.firstChild ); 6316 } 6317 6318 // If this is a select, ensure that it displays empty (#12336) 6319 // Support: IE<9 6320 if ( elem.options && jQuery.nodeName( elem, "select" ) ) { 6321 elem.options.length = 0; 6322 } 6323 } 6324 6325 return this; 6326 }, 6327 6328 clone: function( dataAndEvents, deepDataAndEvents ) { 6329 dataAndEvents = dataAndEvents == null ? false : dataAndEvents; 6330 deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; 6331 6332 return this.map( function() { 6333 return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); 6334 } ); 6335 }, 6336 6337 html: function( value ) { 6338 return access( this, function( value ) { 6339 var elem = this[ 0 ] || {}, 6340 i = 0, 6341 l = this.length; 6342 6343 if ( value === undefined ) { 6344 return elem.nodeType === 1 ? 6345 elem.innerHTML.replace( rinlinejQuery, "" ) : 6346 undefined; 6347 } 6348 6349 // See if we can take a shortcut and just use innerHTML 6350 if ( typeof value === "string" && !rnoInnerhtml.test( value ) && 6351 ( support.htmlSerialize || !rnoshimcache.test( value ) ) && 6352 ( support.leadingWhitespace || !rleadingWhitespace.test( value ) ) && 6353 !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { 6354 6355 value = jQuery.htmlPrefilter( value ); 6356 6357 try { 6358 for ( ; i < l; i++ ) { 6359 6360 // Remove element nodes and prevent memory leaks 6361 elem = this[ i ] || {}; 6362 if ( elem.nodeType === 1 ) { 6363 jQuery.cleanData( getAll( elem, false ) ); 6364 elem.innerHTML = value; 6365 } 6366 } 6367 6368 elem = 0; 6369 6370 // If using innerHTML throws an exception, use the fallback method 6371 } catch ( e ) {} 6372 } 6373 6374 if ( elem ) { 6375 this.empty().append( value ); 6376 } 6377 }, null, value, arguments.length ); 6378 }, 6379 6380 replaceWith: function() { 6381 var ignored = []; 6382 6383 // Make the changes, replacing each non-ignored context element with the new content 6384 return domManip( this, arguments, function( elem ) { 6385 var parent = this.parentNode; 6386 6387 if ( jQuery.inArray( this, ignored ) < 0 ) { 6388 jQuery.cleanData( getAll( this ) ); 6389 if ( parent ) { 6390 parent.replaceChild( elem, this ); 6391 } 6392 } 6393 6394 // Force callback invocation 6395 }, ignored ); 6396 } 6397} ); 6398 6399jQuery.each( { 6400 appendTo: "append", 6401 prependTo: "prepend", 6402 insertBefore: "before", 6403 insertAfter: "after", 6404 replaceAll: "replaceWith" 6405}, function( name, original ) { 6406 jQuery.fn[ name ] = function( selector ) { 6407 var elems, 6408 i = 0, 6409 ret = [], 6410 insert = jQuery( selector ), 6411 last = insert.length - 1; 6412 6413 for ( ; i <= last; i++ ) { 6414 elems = i === last ? this : this.clone( true ); 6415 jQuery( insert[ i ] )[ original ]( elems ); 6416 6417 // Modern browsers can apply jQuery collections as arrays, but oldIE needs a .get() 6418 push.apply( ret, elems.get() ); 6419 } 6420 6421 return this.pushStack( ret ); 6422 }; 6423} ); 6424 6425 6426var iframe, 6427 elemdisplay = { 6428 6429 // Support: Firefox 6430 // We have to pre-define these values for FF (#10227) 6431 HTML: "block", 6432 BODY: "block" 6433 }; 6434 6435/** 6436 * Retrieve the actual display of a element 6437 * @param {String} name nodeName of the element 6438 * @param {Object} doc Document object 6439 */ 6440 6441// Called only from within defaultDisplay 6442function actualDisplay( name, doc ) { 6443 var elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ), 6444 6445 display = jQuery.css( elem[ 0 ], "display" ); 6446 6447 // We don't have any data stored on the element, 6448 // so use "detach" method as fast way to get rid of the element 6449 elem.detach(); 6450
6451 return display; 6452} 6453 6454/** 6455 * Try to determine the default display value of an element 6456 * @param {String} nodeName 6457 */ 6458function defaultDisplay( nodeName ) { 6459 var doc = document, 6460 display = elemdisplay[ nodeName ]; 6461 6462 if ( !display ) { 6463 display = actualDisplay( nodeName, doc ); 6464 6465 // If the simple way fails, read from inside an iframe 6466 if ( display === "none" || !display ) { 6467 6468 // Use the already-created iframe if possible 6469 iframe = ( iframe || jQuery( "<iframe frameborder='0' width='0' height='0'/>" ) ) 6470 .appendTo( doc.documentElement ); 6471 6472 // Always write a new HTML skeleton so Webkit and Firefox don't choke on reuse 6473 doc = ( iframe[ 0 ].contentWindow || iframe[ 0 ].contentDocument ).document; 6474 6475 // Support: IE 6476 doc.write(); 6477 doc.close(); 6478 6479 display = actualDisplay( nodeName, doc ); 6480 iframe.detach(); 6481 } 6482 6483 // Store the correct default display 6484 elemdisplay[ nodeName ] = display; 6485 } 6486 6487 return display; 6488} 6489var rmargin = ( /^margin/ ); 6490 6491var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); 6492 6493var swap = function( elem, options, callback, args ) { 6494 var ret, name, 6495 old = {}; 6496 6497 // Remember the old values, and insert the new ones 6498 for ( name in options ) { 6499 old[ name ] = elem.style[ name ]; 6500 elem.style[ name ] = options[ name ]; 6501 } 6502 6503 ret = callback.apply( elem, args || [] ); 6504 6505 // Revert the old values 6506 for ( name in options ) { 6507 elem.style[ name ] = old[ name ]; 6508 } 6509 6510 return ret; 6511}; 6512 6513 6514var documentElement = document.documentElement; 6515 6516 6517 6518( function() { 6519 var pixelPositionVal, pixelMarginRightVal, boxSizingReliableVal, 6520 reliableHiddenOffsetsVal, reliableMarginRightVal, reliableMarginLeftVal, 6521 container = document.createElement( "div" ), 6522 div = document.createElement( "div" ); 6523 6524 // Finish early in limited (non-browser) environments 6525 if ( !div.style ) { 6526 return; 6527 } 6528 6529 div.style.cssText = "float:left;opacity:.5"; 6530 6531 // Support: IE<9 6532 // Make sure that element opacity exists (as opposed to filter) 6533 support.opacity = div.style.opacity === "0.5"; 6534 6535 // Verify style float existence 6536 // (IE uses styleFloat instead of cssFloat) 6537 support.cssFloat = !!div.style.cssFloat; 6538 6539 div.style.backgroundClip = "content-box"; 6540 div.cloneNode( true ).style.backgroundClip = ""; 6541 support.clearCloneStyle = div.style.backgroundClip === "content-box"; 6542 6543 container = document.createElement( "div" ); 6544 container.style.cssText = "border:0;width:8px;height:0;top:0;left:-9999px;" + 6545 "padding:0;margin-top:1px;position:absolute"; 6546 div.innerHTML = ""; 6547 container.appendChild( div ); 6548 6549 // Support: Firefox<29, Android 2.3 6550 // Vendor-prefix box-sizing 6551 support.boxSizing = div.style.boxSizing === "" || div.style.MozBoxSizing === "" || 6552 div.style.WebkitBoxSizing === ""; 6553 6554 jQuery.extend( support, { 6555 reliableHiddenOffsets: function() { 6556 if ( pixelPositionVal == null ) { 6557 computeStyleTests(); 6558 } 6559 return reliableHiddenOffsetsVal; 6560 }, 6561 6562 boxSizingReliable: function() { 6563 6564 // We're checking for pixelPositionVal here instead of boxSizingReliableVal 6565 // since that compresses better and they're computed together anyway. 6566 if ( pixelPositionVal == null ) { 6567 computeStyleTests(); 6568 } 6569 return boxSizingReliableVal; 6570 }, 6571 6572 pixelMarginRight: function() { 6573 6574 // Support: Android 4.0-4.3 6575 if ( pixelPositionVal == null ) { 6576 computeStyleTests(); 6577 } 6578 return pixelMarginRightVal; 6579 }, 6580 6581 pixelPosition: function() { 6582 if ( pixelPositionVal == null ) { 6583 computeStyleTests(); 6584 } 6585 return pixelPositionVal; 6586 }, 6587 6588 reliableMarginRight: function() { 6589 6590 // Support: Android 2.3 6591 if ( pixelPositionVal == null ) { 6592 computeStyleTests(); 6593 } 6594 return reliableMarginRightVal; 6595 }, 6596 6597 reliableMarginLeft: function() { 6598 6599 // Support: IE <=8 only, Android 4.0 - 4.3 only, Firefox <=3 - 37 6600 if ( pixelPositionVal == null ) { 6601 computeStyleTests(); 6602 } 6603 return reliableMarginLeftVal; 6604 } 6605 } ); 6606 6607 function computeStyleTests() { 6608 var contents, divStyle, 6609 documentElement = document.documentElement; 6610 6611 // Setup 6612 documentElement.appendChild( container ); 6613 6614 div.style.cssText = 6615 6616 // Support: Android 2.3 6617 // Vendor-prefix box-sizing 6618 "-webkit-box-sizing:border-box;box-sizing:border-box;" + 6619 "position:relative;display:block;" + 6620 "margin:auto;border:1px;padding:1px;" + 6621 "top:1%;width:50%"; 6622
6623 // Support: IE<9 6624 // Assume reasonable values in the absence of getComputedStyle 6625 pixelPositionVal = boxSizingReliableVal = reliableMarginLeftVal = false; 6626 pixelMarginRightVal = reliableMarginRightVal = true; 6627 6628 // Check for getComputedStyle so that this code is not run in IE<9. 6629 if ( window.getComputedStyle ) { 6630 divStyle = window.getComputedStyle( div ); 6631 pixelPositionVal = ( divStyle || {} ).top !== "1%"; 6632 reliableMarginLeftVal = ( divStyle || {} ).marginLeft === "2px"; 6633 boxSizingReliableVal = ( divStyle || { width: "4px" } ).width === "4px"; 6634 6635 // Support: Android 4.0 - 4.3 only 6636 // Some styles come back with percentage values, even though they shouldn't 6637 div.style.marginRight = "50%"; 6638 pixelMarginRightVal = ( divStyle || { marginRight: "4px" } ).marginRight === "4px"; 6639 6640 // Support: Android 2.3 only 6641 // Div with explicit width and no margin-right incorrectly 6642 // gets computed margin-right based on width of container (#3333) 6643 // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right 6644 contents = div.appendChild( document.createElement( "div" ) ); 6645 6646 // Reset CSS: box-sizing; display; margin; border; padding 6647 contents.style.cssText = div.style.cssText = 6648 6649 // Support: Android 2.3 6650 // Vendor-prefix box-sizing 6651 "-webkit-box-sizing:content-box;-moz-box-sizing:content-box;" + 6652 "box-sizing:content-box;display:block;margin:0;border:0;padding:0"; 6653 contents.style.marginRight = contents.style.width = "0"; 6654 div.style.width = "1px"; 6655 6656 reliableMarginRightVal = 6657 !parseFloat( ( window.getComputedStyle( contents ) || {} ).marginRight ); 6658 6659 div.removeChild( contents ); 6660 } 6661 6662 // Support: IE6-8 6663 // First check that getClientRects works as expected 6664 // Check if table cells still have offsetWidth/Height when they are set 6665 // to display:none and there are still other visible table cells in a 6666 // table row; if so, offsetWidth/Height are not reliable for use when 6667 // determining if an element has been hidden directly using 6668 // display:none (it is still safe to use offsets if a parent element is 6669 // hidden; don safety goggles and see bug #4512 for more information). 6670 div.style.display = "none"; 6671 reliableHiddenOffsetsVal = div.getClientRects().length === 0; 6672 if ( reliableHiddenOffsetsVal ) { 6673 div.style.display = ""; 6674 div.innerHTML = "<table><tr><td></td><td>t</td></tr></table>"; 6675 div.childNodes[ 0 ].style.borderCollapse = "separate"; 6676 contents = div.getElementsByTagName( "td" ); 6677 contents[ 0 ].style.cssText = "margin:0;border:0;padding:0;display:none"; 6678 reliableHiddenOffsetsVal = contents[ 0 ].offsetHeight === 0; 6679 if ( reliableHiddenOffsetsVal ) { 6680 contents[ 0 ].style.display = ""; 6681 contents[ 1 ].style.display = "none"; 6682 reliableHiddenOffsetsVal = contents[ 0 ].offsetHeight === 0; 6683 } 6684 } 6685 6686 // Teardown 6687 documentElement.removeChild( container ); 6688 } 6689 6690} )(); 6691 6692 6693var getStyles, curCSS, 6694 rposition = /^(top|right|bottom|left)$/; 6695 6696if ( window.getComputedStyle ) { 6697 getStyles = function( elem ) { 6698 6699 // Support: IE<=11+, Firefox<=30+ (#15098, #14150) 6700 // IE throws on elements created in popups 6701 // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" 6702 var view = elem.ownerDocument.defaultView; 6703 6704 if ( !view || !view.opener ) { 6705 view = window; 6706 } 6707 6708 return view.getComputedStyle( elem ); 6709 }; 6710 6711 curCSS = function( elem, name, computed ) { 6712 var width, minWidth, maxWidth, ret, 6713 style = elem.style; 6714 6715 computed = computed || getStyles( elem ); 6716 6717 // getPropertyValue is only needed for .css('filter') in IE9, see #12537 6718 ret = computed ? computed.getPropertyValue( name ) || computed[ name ] : undefined; 6719 6720 // Support: Opera 12.1x only 6721 // Fall back to style even without computed 6722 // computed is undefined for elems on document fragments 6723 if ( ( ret === "" || ret === undefined ) && !jQuery.contains( elem.ownerDocument, elem ) ) { 6724 ret = jQuery.style( elem, name ); 6725 } 6726 6727 if ( computed ) { 6728 6729 // A tribute to the "awesome hack by Dean Edwards" 6730 // Chrome < 17 and Safari 5.0 uses "computed value" 6731 // instead of "used value" for margin-right 6732 // Safari 5.1.7 (at least) returns percentage for a larger set of values, 6733 // but width seems to be reliably pixels 6734 // this is against the CSSOM draft spec: 6735 // http://dev.w3.org/csswg/cssom/#resolved-values 6736 if ( !support.pixelMarginRight() && rnumnonpx.test( ret ) && rmargin.test( name ) ) { 6737 6738 // Remember the original values 6739 width = style.width; 6740 minWidth = style.minWidth; 6741 maxWidth = style.maxWidth; 6742 6743 // Put in the new values to get a computed value out 6744 style.minWidth = style.maxWidth = style.width = ret; 6745 ret = computed.width; 6746 6747 // Revert the changed values 6748 style.width = width; 6749 style.minWidth = minWidth; 6750 style.maxWidth = maxWidth; 6751 } 6752 } 6753
vendor: 4,152 bytes, lines 6754-6916
6754 // Support: IE 6755 // IE returns zIndex value as an integer. 6756 return ret === undefined ? 6757 ret : 6758 ret + ""; 6759 }; 6760} else if ( documentElement.currentStyle ) { 6761 getStyles = function( elem ) { 6762 return elem.currentStyle; 6763 }; 6764 6765 curCSS = function( elem, name, computed ) { 6766 var left, rs, rsLeft, ret, 6767 style = elem.style; 6768 6769 computed = computed || getStyles( elem ); 6770 ret = computed ? computed[ name ] : undefined; 6771 6772 // Avoid setting ret to empty string here 6773 // so we don't default to auto 6774 if ( ret == null && style && style[ name ] ) { 6775 ret = style[ name ]; 6776 } 6777 6778 // From the awesome hack by Dean Edwards 6779 // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291 6780 6781 // If we're not dealing with a regular pixel number 6782 // but a number that has a weird ending, we need to convert it to pixels 6783 // but not position css attributes, as those are 6784 // proportional to the parent element instead 6785 // and we can't measure the parent instead because it 6786 // might trigger a "stacking dolls" problem 6787 if ( rnumnonpx.test( ret ) && !rposition.test( name ) ) { 6788 6789 // Remember the original values 6790 left = style.left; 6791 rs = elem.runtimeStyle; 6792 rsLeft = rs && rs.left; 6793 6794 // Put in the new values to get a computed value out 6795 if ( rsLeft ) { 6796 rs.left = elem.currentStyle.left; 6797 } 6798 style.left = name === "fontSize" ? "1em" : ret; 6799 ret = style.pixelLeft + "px"; 6800 6801 // Revert the changed values 6802 style.left = left; 6803 if ( rsLeft ) { 6804 rs.left = rsLeft; 6805 } 6806 } 6807 6808 // Support: IE 6809 // IE returns zIndex value as an integer. 6810 return ret === undefined ? 6811 ret : 6812 ret + "" || "auto"; 6813 }; 6814} 6815 6816 6817 6818 6819function addGetHookIf( conditionFn, hookFn ) { 6820 6821 // Define the hook, we'll check on the first run if it's really needed. 6822 return { 6823 get: function() { 6824 if ( conditionFn() ) { 6825 6826 // Hook not needed (or it's not possible to use it due 6827 // to missing dependency), remove it. 6828 delete this.get; 6829 return; 6830 } 6831 6832 // Hook needed; redefine it so that the support test is not executed again. 6833 return ( this.get = hookFn ).apply( this, arguments ); 6834 } 6835 }; 6836} 6837 6838 6839var 6840 6841 ralpha = /alpha\([^)]*\)/i, 6842 ropacity = /opacity\s*=\s*([^)]*)/i, 6843 6844 // swappable if display is none or starts with table except 6845 // "table", "table-cell", or "table-caption" 6846 // see here for display values: 6847 // https://developer.mozilla.org/en-US/docs/CSS/display 6848 rdisplayswap = /^(none|table(?!-c[ea]).+)/, 6849 rnumsplit = new RegExp( "^(" + pnum + ")(.*)$", "i" ), 6850 6851 cssShow = { position: "absolute", visibility: "hidden", display: "block" }, 6852 cssNormalTransform = { 6853 letterSpacing: "0", 6854 fontWeight: "400" 6855 }, 6856 6857 cssPrefixes = [ "Webkit", "O", "Moz", "ms" ], 6858 emptyStyle = document.createElement( "div" ).style; 6859 6860 6861// return a css property mapped to a potentially vendor prefixed property 6862function vendorPropName( name ) { 6863 6864 // shortcut for names that are not vendor prefixed 6865 if ( name in emptyStyle ) { 6866 return name; 6867 } 6868 6869 // check for vendor prefixed names 6870 var capName = name.charAt( 0 ).toUpperCase() + name.slice( 1 ), 6871 i = cssPrefixes.length; 6872 6873 while ( i-- ) { 6874 name = cssPrefixes[ i ] + capName; 6875 if ( name in emptyStyle ) { 6876 return name; 6877 } 6878 } 6879} 6880 6881function showHide( elements, show ) { 6882 var display, elem, hidden, 6883 values = [], 6884 index = 0, 6885 length = elements.length; 6886 6887 for ( ; index < length; index++ ) { 6888 elem = elements[ index ]; 6889 if ( !elem.style ) { 6890 continue; 6891 } 6892 6893 values[ index ] = jQuery._data( elem, "olddisplay" ); 6894 display = elem.style.display; 6895 if ( show ) { 6896 6897 // Reset the inline display of this element to learn if it is 6898 // being hidden by cascaded rules or not 6899 if ( !values[ index ] && display === "none" ) { 6900 elem.style.display = ""; 6901 } 6902 6903 // Set elements which have been overridden with display: none 6904 // in a stylesheet to whatever the default browser style is 6905 // for such an element 6906 if ( elem.style.display === "" && isHidden( elem ) ) { 6907 values[ index ] = 6908 jQuery._data( elem, "olddisplay", defaultDisplay( elem.nodeName ) ); 6909 } 6910 } else { 6911 hidden = isHidden( elem ); 6912 6913 if ( display && display !== "none" || !hidden ) { 6914 jQuery._data( 6915 elem, 6916 "olddisplay",
vendor: 6,043 bytes, lines 6917-7128
6917 hidden ? display : jQuery.css( elem, "display" ) 6918 ); 6919 } 6920 } 6921 } 6922 6923 // Set the display of most of the elements in a second loop 6924 // to avoid the constant reflow 6925 for ( index = 0; index < length; index++ ) { 6926 elem = elements[ index ]; 6927 if ( !elem.style ) { 6928 continue; 6929 } 6930 if ( !show || elem.style.display === "none" || elem.style.display === "" ) { 6931 elem.style.display = show ? values[ index ] || "" : "none"; 6932 } 6933 } 6934 6935 return elements; 6936} 6937 6938function setPositiveNumber( elem, value, subtract ) { 6939 var matches = rnumsplit.exec( value ); 6940 return matches ? 6941 6942 // Guard against undefined "subtract", e.g., when used as in cssHooks 6943 Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) : 6944 value; 6945} 6946 6947function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) { 6948 var i = extra === ( isBorderBox ? "border" : "content" ) ? 6949 6950 // If we already have the right measurement, avoid augmentation 6951 4 : 6952 6953 // Otherwise initialize for horizontal or vertical properties 6954 name === "width" ? 1 : 0, 6955 6956 val = 0; 6957 6958 for ( ; i < 4; i += 2 ) { 6959 6960 // both box models exclude margin, so add it if we want it 6961 if ( extra === "margin" ) { 6962 val += jQuery.css( elem, extra + cssExpand[ i ], true, styles ); 6963 } 6964 6965 if ( isBorderBox ) { 6966 6967 // border-box includes padding, so remove it if we want content 6968 if ( extra === "content" ) { 6969 val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); 6970 } 6971 6972 // at this point, extra isn't border nor margin, so remove border 6973 if ( extra !== "margin" ) { 6974 val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); 6975 } 6976 } else { 6977 6978 // at this point, extra isn't content, so add padding 6979 val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); 6980 6981 // at this point, extra isn't content nor padding, so add border 6982 if ( extra !== "padding" ) { 6983 val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); 6984 } 6985 } 6986 } 6987 6988 return val; 6989} 6990 6991function getWidthOrHeight( elem, name, extra ) { 6992 6993 // Start with offset property, which is equivalent to the border-box value 6994 var valueIsBorderBox = true, 6995 val = name === "width" ? elem.offsetWidth : elem.offsetHeight, 6996 styles = getStyles( elem ), 6997 isBorderBox = support.boxSizing && 6998 jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; 6999 7000 // some non-html elements return undefined for offsetWidth, so check for null/undefined 7001 // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285 7002 // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668 7003 if ( val <= 0 || val == null ) { 7004 7005 // Fall back to computed then uncomputed css if necessary 7006 val = curCSS( elem, name, styles ); 7007 if ( val < 0 || val == null ) { 7008 val = elem.style[ name ]; 7009 } 7010 7011 // Computed unit is not pixels. Stop here and return. 7012 if ( rnumnonpx.test( val ) ) { 7013 return val; 7014 } 7015 7016 // we need the check for style in case a browser which returns unreliable values 7017 // for getComputedStyle silently falls back to the reliable elem.style 7018 valueIsBorderBox = isBorderBox && 7019 ( support.boxSizingReliable() || val === elem.style[ name ] ); 7020 7021 // Normalize "", auto, and prepare for extra 7022 val = parseFloat( val ) || 0; 7023 } 7024 7025 // use the active box-sizing model to add/subtract irrelevant styles 7026 return ( val + 7027 augmentWidthOrHeight( 7028 elem, 7029 name, 7030 extra || ( isBorderBox ? "border" : "content" ), 7031 valueIsBorderBox, 7032 styles 7033 ) 7034 ) + "px"; 7035} 7036 7037jQuery.extend( { 7038 7039 // Add in style property hooks for overriding the default 7040 // behavior of getting and setting a style property 7041 cssHooks: { 7042 opacity: { 7043 get: function( elem, computed ) { 7044 if ( computed ) { 7045 7046 // We should always get a number back from opacity 7047 var ret = curCSS( elem, "opacity" ); 7048 return ret === "" ? "1" : ret; 7049 } 7050 } 7051 } 7052 }, 7053 7054 // Don't automatically add "px" to these possibly-unitless properties 7055 cssNumber: { 7056 "animationIterationCount": true, 7057 "columnCount": true, 7058 "fillOpacity": true, 7059 "flexGrow": true, 7060 "flexShrink": true, 7061 "fontWeight": true, 7062 "lineHeight": true, 7063 "opacity": true, 7064 "order": true, 7065 "orphans": true, 7066 "widows": true, 7067 "zIndex": true, 7068 "zoom": true 7069 }, 7070 7071 // Add in properties whose names you wish to fix before 7072 // setting or getting the value 7073 cssProps: { 7074 7075 // normalize float css property 7076 "float": support.cssFloat ? "cssFloat" : "styleFloat" 7077 }, 7078 7079 // Get and set the style property on a DOM Node 7080 style: function( elem, name, value, extra ) { 7081 7082 // Don't set styles on text and comment nodes 7083 if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { 7084 return; 7085 } 7086 7087 // Make sure that we're working with the right name 7088 var ret, type, hooks, 7089 origName = jQuery.camelCase( name ), 7090 style = elem.style; 7091 7092 name = jQuery.cssProps[ origName ] || 7093 ( jQuery.cssProps[ origName ] = vendorPropName( origName ) || origName ); 7094 7095 // gets hook for the prefixed version 7096 // followed by the unprefixed version 7097 hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; 7098 7099 // Check if we're setting a value 7100 if ( value !== undefined ) { 7101 type = typeof value; 7102 7103 // Convert "+=" or "-=" to relative numbers (#7345) 7104 if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) { 7105 value = adjustCSS( elem, name, ret ); 7106 7107 // Fixes bug #9237 7108 type = "number"; 7109 } 7110 7111 // Make sure that null and NaN values aren't set. See: #7116 7112 if ( value == null || value !== value ) { 7113 return; 7114 } 7115 7116 // If a number was passed in, add the unit (except for certain CSS properties) 7117 if ( type === "number" ) { 7118 value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" ); 7119 } 7120 7121 // Fixes #8908, it can be done more correctly by specifing setters in cssHooks, 7122 // but it would mean to define eight 7123 // (for every problematic property) identical functions 7124 if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) { 7125 style[ name ] = "inherit"; 7126 } 7127 7128 // If a hook was provided, use that value, otherwise just set the specified value
vendor: 4,586 bytes, lines 7129-7284
7129 if ( !hooks || !( "set" in hooks ) || 7130 ( value = hooks.set( elem, value, extra ) ) !== undefined ) { 7131 7132 // Support: IE 7133 // Swallow errors from 'invalid' CSS values (#5509) 7134 try { 7135 style[ name ] = value; 7136 } catch ( e ) {} 7137 } 7138 7139 } else { 7140 7141 // If a hook was provided get the non-computed value from there 7142 if ( hooks && "get" in hooks && 7143 ( ret = hooks.get( elem, false, extra ) ) !== undefined ) { 7144 7145 return ret; 7146 } 7147 7148 // Otherwise just get the value from the style object 7149 return style[ name ]; 7150 } 7151 }, 7152 7153 css: function( elem, name, extra, styles ) { 7154 var num, val, hooks, 7155 origName = jQuery.camelCase( name ); 7156 7157 // Make sure that we're working with the right name 7158 name = jQuery.cssProps[ origName ] || 7159 ( jQuery.cssProps[ origName ] = vendorPropName( origName ) || origName ); 7160 7161 // gets hook for the prefixed version 7162 // followed by the unprefixed version 7163 hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; 7164 7165 // If a hook was provided get the computed value from there 7166 if ( hooks && "get" in hooks ) { 7167 val = hooks.get( elem, true, extra ); 7168 } 7169 7170 // Otherwise, if a way to get the computed value exists, use that 7171 if ( val === undefined ) { 7172 val = curCSS( elem, name, styles ); 7173 } 7174 7175 //convert "normal" to computed value 7176 if ( val === "normal" && name in cssNormalTransform ) { 7177 val = cssNormalTransform[ name ]; 7178 } 7179 7180 // Return, converting to number if forced or a qualifier was provided and val looks numeric 7181 if ( extra === "" || extra ) { 7182 num = parseFloat( val ); 7183 return extra === true || isFinite( num ) ? num || 0 : val; 7184 } 7185 return val; 7186 } 7187} ); 7188 7189jQuery.each( [ "height", "width" ], function( i, name ) { 7190 jQuery.cssHooks[ name ] = { 7191 get: function( elem, computed, extra ) { 7192 if ( computed ) { 7193 7194 // certain elements can have dimension info if we invisibly show them 7195 // however, it must have a current display style that would benefit from this 7196 return rdisplayswap.test( jQuery.css( elem, "display" ) ) && 7197 elem.offsetWidth === 0 ? 7198 swap( elem, cssShow, function() { 7199 return getWidthOrHeight( elem, name, extra ); 7200 } ) : 7201 getWidthOrHeight( elem, name, extra ); 7202 } 7203 }, 7204 7205 set: function( elem, value, extra ) { 7206 var styles = extra && getStyles( elem ); 7207 return setPositiveNumber( elem, value, extra ? 7208 augmentWidthOrHeight( 7209 elem, 7210 name, 7211 extra, 7212 support.boxSizing && 7213 jQuery.css( elem, "boxSizing", false, styles ) === "border-box", 7214 styles 7215 ) : 0 7216 ); 7217 } 7218 }; 7219} ); 7220 7221if ( !support.opacity ) { 7222 jQuery.cssHooks.opacity = { 7223 get: function( elem, computed ) { 7224 7225 // IE uses filters for opacity 7226 return ropacity.test( ( computed && elem.currentStyle ? 7227 elem.currentStyle.filter : 7228 elem.style.filter ) || "" ) ? 7229 ( 0.01 * parseFloat( RegExp.$1 ) ) + "" : 7230 computed ? "1" : ""; 7231 }, 7232 7233 set: function( elem, value ) { 7234 var style = elem.style, 7235 currentStyle = elem.currentStyle, 7236 opacity = jQuery.isNumeric( value ) ? "alpha(opacity=" + value * 100 + ")" : "", 7237 filter = currentStyle && currentStyle.filter || style.filter || ""; 7238 7239 // IE has trouble with opacity if it does not have layout 7240 // Force it by setting the zoom level 7241 style.zoom = 1; 7242 7243 // if setting opacity to 1, and no other filters exist - 7244 // attempt to remove filter attribute #6652 7245 // if value === "", then remove inline opacity #12685 7246 if ( ( value >= 1 || value === "" ) && 7247 jQuery.trim( filter.replace( ralpha, "" ) ) === "" && 7248 style.removeAttribute ) { 7249 7250 // Setting style.filter to null, "" & " " still leave "filter:" in the cssText 7251 // if "filter:" is present at all, clearType is disabled, we want to avoid this 7252 // style.removeAttribute is IE Only, but so apparently is this code path... 7253 style.removeAttribute( "filter" ); 7254 7255 // if there is no filter style applied in a css rule 7256 // or unset inline opacity, we are done 7257 if ( value === "" || currentStyle && !currentStyle.filter ) { 7258 return; 7259 } 7260 } 7261 7262 // otherwise, set new filter values 7263 style.filter = ralpha.test( filter ) ? 7264 filter.replace( ralpha, opacity ) : 7265 filter + " " + opacity; 7266 } 7267 }; 7268} 7269 7270jQuery.cssHooks.marginRight = addGetHookIf( support.reliableMarginRight, 7271 function( elem, computed ) { 7272 if ( computed ) { 7273 return swap( elem, { "display": "inline-block" }, 7274 curCSS, [ elem, "marginRight" ] ); 7275 } 7276 } 7277); 7278 7279jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, 7280 function( elem, computed ) { 7281 if ( computed ) { 7282 return ( 7283 parseFloat( curCSS( elem, "marginLeft" ) ) || 7284
vendor: 4,625 bytes, lines 7285-7463
7285 // Support: IE<=11+ 7286 // Running getBoundingClientRect on a disconnected node in IE throws an error 7287 // Support: IE8 only 7288 // getClientRects() errors on disconnected elems 7289 ( jQuery.contains( elem.ownerDocument, elem ) ? 7290 elem.getBoundingClientRect().left - 7291 swap( elem, { marginLeft: 0 }, function() { 7292 return elem.getBoundingClientRect().left; 7293 } ) : 7294 0 7295 ) 7296 ) + "px"; 7297 } 7298 } 7299); 7300 7301// These hooks are used by animate to expand properties 7302jQuery.each( { 7303 margin: "", 7304 padding: "", 7305 border: "Width" 7306}, function( prefix, suffix ) { 7307 jQuery.cssHooks[ prefix + suffix ] = { 7308 expand: function( value ) { 7309 var i = 0, 7310 expanded = {}, 7311 7312 // assumes a single number if not a string 7313 parts = typeof value === "string" ? value.split( " " ) : [ value ]; 7314 7315 for ( ; i < 4; i++ ) { 7316 expanded[ prefix + cssExpand[ i ] + suffix ] = 7317 parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; 7318 } 7319 7320 return expanded; 7321 } 7322 }; 7323 7324 if ( !rmargin.test( prefix ) ) { 7325 jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; 7326 } 7327} ); 7328 7329jQuery.fn.extend( { 7330 css: function( name, value ) { 7331 return access( this, function( elem, name, value ) { 7332 var styles, len, 7333 map = {}, 7334 i = 0; 7335 7336 if ( jQuery.isArray( name ) ) { 7337 styles = getStyles( elem ); 7338 len = name.length; 7339 7340 for ( ; i < len; i++ ) { 7341 map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); 7342 } 7343 7344 return map; 7345 } 7346 7347 return value !== undefined ? 7348 jQuery.style( elem, name, value ) : 7349 jQuery.css( elem, name ); 7350 }, name, value, arguments.length > 1 ); 7351 }, 7352 show: function() { 7353 return showHide( this, true ); 7354 }, 7355 hide: function() { 7356 return showHide( this ); 7357 }, 7358 toggle: function( state ) { 7359 if ( typeof state === "boolean" ) { 7360 return state ? this.show() : this.hide(); 7361 } 7362 7363 return this.each( function() { 7364 if ( isHidden( this ) ) { 7365 jQuery( this ).show(); 7366 } else { 7367 jQuery( this ).hide(); 7368 } 7369 } ); 7370 } 7371} ); 7372 7373 7374function Tween( elem, options, prop, end, easing ) { 7375 return new Tween.prototype.init( elem, options, prop, end, easing ); 7376} 7377jQuery.Tween = Tween; 7378 7379Tween.prototype = { 7380 constructor: Tween, 7381 init: function( elem, options, prop, end, easing, unit ) { 7382 this.elem = elem; 7383 this.prop = prop; 7384 this.easing = easing || jQuery.easing._default; 7385 this.options = options; 7386 this.start = this.now = this.cur(); 7387 this.end = end; 7388 this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); 7389 }, 7390 cur: function() { 7391 var hooks = Tween.propHooks[ this.prop ]; 7392 7393 return hooks && hooks.get ? 7394 hooks.get( this ) : 7395 Tween.propHooks._default.get( this ); 7396 }, 7397 run: function( percent ) { 7398 var eased, 7399 hooks = Tween.propHooks[ this.prop ]; 7400 7401 if ( this.options.duration ) { 7402 this.pos = eased = jQuery.easing[ this.easing ]( 7403 percent, this.options.duration * percent, 0, 1, this.options.duration 7404 ); 7405 } else { 7406 this.pos = eased = percent; 7407 } 7408 this.now = ( this.end - this.start ) * eased + this.start; 7409 7410 if ( this.options.step ) { 7411 this.options.step.call( this.elem, this.now, this ); 7412 } 7413 7414 if ( hooks && hooks.set ) { 7415 hooks.set( this ); 7416 } else { 7417 Tween.propHooks._default.set( this ); 7418 } 7419 return this; 7420 } 7421}; 7422 7423Tween.prototype.init.prototype = Tween.prototype; 7424 7425Tween.propHooks = { 7426 _default: { 7427 get: function( tween ) { 7428 var result; 7429 7430 // Use a property on the element directly when it is not a DOM element, 7431 // or when there is no matching style property that exists. 7432 if ( tween.elem.nodeType !== 1 || 7433 tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) { 7434 return tween.elem[ tween.prop ]; 7435 } 7436 7437 // passing an empty string as a 3rd parameter to .css will automatically 7438 // attempt a parseFloat and fallback to a string if the parse fails 7439 // so, simple values such as "10px" are parsed to Float. 7440 // complex values such as "rotate(1rad)" are returned as is. 7441 result = jQuery.css( tween.elem, tween.prop, "" ); 7442 7443 // Empty strings, null, undefined and "auto" are converted to 0. 7444 return !result || result === "auto" ? 0 : result; 7445 }, 7446 set: function( tween ) { 7447 7448 // use step hook for back compat - use cssHook if its there - use .style if its 7449 // available and use plain properties where available 7450 if ( jQuery.fx.step[ tween.prop ] ) { 7451 jQuery.fx.step[ tween.prop ]( tween ); 7452 } else if ( tween.elem.nodeType === 1 && 7453 ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || 7454 jQuery.cssHooks[ tween.prop ] ) ) { 7455 jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); 7456 } else { 7457 tween.elem[ tween.prop ] = tween.now; 7458 } 7459 } 7460 } 7461}; 7462 7463// Support: IE <=9
vendor: 5,654 bytes, lines 7464-7680
7464// Panic based approach to setting things on disconnected nodes 7465 7466Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { 7467 set: function( tween ) { 7468 if ( tween.elem.nodeType && tween.elem.parentNode ) { 7469 tween.elem[ tween.prop ] = tween.now; 7470 } 7471 } 7472}; 7473 7474jQuery.easing = { 7475 linear: function( p ) { 7476 return p; 7477 }, 7478 swing: function( p ) { 7479 return 0.5 - Math.cos( p * Math.PI ) / 2; 7480 }, 7481 _default: "swing" 7482}; 7483 7484jQuery.fx = Tween.prototype.init; 7485 7486// Back Compat <1.8 extension point 7487jQuery.fx.step = {}; 7488 7489 7490 7491 7492var 7493 fxNow, timerId, 7494 rfxtypes = /^(?:toggle|show|hide)$/, 7495 rrun = /queueHooks$/; 7496 7497// Animations created synchronously will run synchronously 7498function createFxNow() { 7499 window.setTimeout( function() { 7500 fxNow = undefined; 7501 } ); 7502 return ( fxNow = jQuery.now() ); 7503} 7504 7505// Generate parameters to create a standard animation 7506function genFx( type, includeWidth ) { 7507 var which, 7508 attrs = { height: type }, 7509 i = 0; 7510 7511 // if we include width, step value is 1 to do all cssExpand values, 7512 // if we don't include width, step value is 2 to skip over Left and Right 7513 includeWidth = includeWidth ? 1 : 0; 7514 for ( ; i < 4 ; i += 2 - includeWidth ) { 7515 which = cssExpand[ i ]; 7516 attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; 7517 } 7518 7519 if ( includeWidth ) { 7520 attrs.opacity = attrs.width = type; 7521 } 7522 7523 return attrs; 7524} 7525 7526function createTween( value, prop, animation ) { 7527 var tween, 7528 collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ), 7529 index = 0, 7530 length = collection.length; 7531 for ( ; index < length; index++ ) { 7532 if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) { 7533 7534 // we're done with this property 7535 return tween; 7536 } 7537 } 7538} 7539 7540function defaultPrefilter( elem, props, opts ) { 7541 /* jshint validthis: true */ 7542 var prop, value, toggle, tween, hooks, oldfire, display, checkDisplay, 7543 anim = this, 7544 orig = {}, 7545 style = elem.style, 7546 hidden = elem.nodeType && isHidden( elem ), 7547 dataShow = jQuery._data( elem, "fxshow" ); 7548 7549 // handle queue: false promises 7550 if ( !opts.queue ) { 7551 hooks = jQuery._queueHooks( elem, "fx" ); 7552 if ( hooks.unqueued == null ) { 7553 hooks.unqueued = 0; 7554 oldfire = hooks.empty.fire; 7555 hooks.empty.fire = function() { 7556 if ( !hooks.unqueued ) { 7557 oldfire(); 7558 } 7559 }; 7560 } 7561 hooks.unqueued++; 7562 7563 anim.always( function() { 7564 7565 // doing this makes sure that the complete handler will be called 7566 // before this completes 7567 anim.always( function() { 7568 hooks.unqueued--; 7569 if ( !jQuery.queue( elem, "fx" ).length ) { 7570 hooks.empty.fire(); 7571 } 7572 } ); 7573 } ); 7574 } 7575 7576 // height/width overflow pass 7577 if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) { 7578 7579 // Make sure that nothing sneaks out 7580 // Record all 3 overflow attributes because IE does not 7581 // change the overflow attribute when overflowX and 7582 // overflowY are set to the same value 7583 opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; 7584 7585 // Set display property to inline-block for height/width 7586 // animations on inline elements that are having width/height animated 7587 display = jQuery.css( elem, "display" ); 7588 7589 // Test default display if display is currently "none" 7590 checkDisplay = display === "none" ? 7591 jQuery._data( elem, "olddisplay" ) || defaultDisplay( elem.nodeName ) : display; 7592 7593 if ( checkDisplay === "inline" && jQuery.css( elem, "float" ) === "none" ) { 7594 7595 // inline-level elements accept inline-block; 7596 // block-level elements need to be inline with layout 7597 if ( !support.inlineBlockNeedsLayout || defaultDisplay( elem.nodeName ) === "inline" ) { 7598 style.display = "inline-block"; 7599 } else { 7600 style.zoom = 1; 7601 } 7602 } 7603 } 7604 7605 if ( opts.overflow ) { 7606 style.overflow = "hidden"; 7607 if ( !support.shrinkWrapBlocks() ) { 7608 anim.always( function() { 7609 style.overflow = opts.overflow[ 0 ]; 7610 style.overflowX = opts.overflow[ 1 ]; 7611 style.overflowY = opts.overflow[ 2 ]; 7612 } ); 7613 } 7614 } 7615 7616 // show/hide pass 7617 for ( prop in props ) { 7618 value = props[ prop ]; 7619 if ( rfxtypes.exec( value ) ) { 7620 delete props[ prop ]; 7621 toggle = toggle || value === "toggle"; 7622 if ( value === ( hidden ? "hide" : "show" ) ) { 7623 7624 // If there is dataShow left over from a stopped hide or show 7625 // and we are going to proceed with show, we should pretend to be hidden 7626 if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) { 7627 hidden = true; 7628 } else { 7629 continue; 7630 } 7631 } 7632 orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop ); 7633 7634 // Any non-fx value stops us from restoring the original display value 7635 } else { 7636 display = undefined; 7637 } 7638 } 7639 7640 if ( !jQuery.isEmptyObject( orig ) ) { 7641 if ( dataShow ) { 7642 if ( "hidden" in dataShow ) { 7643 hidden = dataShow.hidden; 7644 } 7645 } else { 7646 dataShow = jQuery._data( elem, "fxshow", {} ); 7647 } 7648 7649 // store state if its toggle - enables .stop().toggle() to "reverse" 7650 if ( toggle ) { 7651 dataShow.hidden = !hidden; 7652 } 7653 if ( hidden ) { 7654 jQuery( elem ).show(); 7655 } else { 7656 anim.done( function() { 7657 jQuery( elem ).hide(); 7658 } ); 7659 } 7660 anim.done( function() { 7661 var prop; 7662 jQuery._removeData( elem, "fxshow" ); 7663 for ( prop in orig ) { 7664 jQuery.style( elem, prop, orig[ prop ] ); 7665 } 7666 } ); 7667 for ( prop in orig ) { 7668 tween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim ); 7669 7670 if ( !( prop in dataShow ) ) { 7671 dataShow[ prop ] = tween.start; 7672 if ( hidden ) { 7673 tween.end = tween.start; 7674 tween.start = prop === "width" || prop === "height" ? 1 : 0; 7675 } 7676 } 7677 } 7678 7679 // If this is a noop like .hide().hide(), restore an overwritten display value 7680 } else if ( ( display === "none" ? defaultDisplay( elem.nodeName ) : dis
vendor: 10,851 bytes, lines 7680-8112
7680play ) === "inline" ) { 7681 style.display = display; 7682 } 7683} 7684 7685function propFilter( props, specialEasing ) { 7686 var index, name, easing, value, hooks; 7687 7688 // camelCase, specialEasing and expand cssHook pass 7689 for ( index in props ) { 7690 name = jQuery.camelCase( index ); 7691 easing = specialEasing[ name ]; 7692 value = props[ index ]; 7693 if ( jQuery.isArray( value ) ) { 7694 easing = value[ 1 ]; 7695 value = props[ index ] = value[ 0 ]; 7696 } 7697 7698 if ( index !== name ) { 7699 props[ name ] = value; 7700 delete props[ index ]; 7701 } 7702 7703 hooks = jQuery.cssHooks[ name ]; 7704 if ( hooks && "expand" in hooks ) { 7705 value = hooks.expand( value ); 7706 delete props[ name ]; 7707 7708 // not quite $.extend, this wont overwrite keys already present. 7709 // also - reusing 'index' from above because we have the correct "name" 7710 for ( index in value ) { 7711 if ( !( index in props ) ) { 7712 props[ index ] = value[ index ]; 7713 specialEasing[ index ] = easing; 7714 } 7715 } 7716 } else { 7717 specialEasing[ name ] = easing; 7718 } 7719 } 7720} 7721 7722function Animation( elem, properties, options ) { 7723 var result, 7724 stopped, 7725 index = 0, 7726 length = Animation.prefilters.length, 7727 deferred = jQuery.Deferred().always( function() { 7728 7729 // don't match elem in the :animated selector 7730 delete tick.elem; 7731 } ), 7732 tick = function() { 7733 if ( stopped ) { 7734 return false; 7735 } 7736 var currentTime = fxNow || createFxNow(), 7737 remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), 7738 7739 // Support: Android 2.3 7740 // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497) 7741 temp = remaining / animation.duration || 0, 7742 percent = 1 - temp, 7743 index = 0, 7744 length = animation.tweens.length; 7745 7746 for ( ; index < length ; index++ ) { 7747 animation.tweens[ index ].run( percent ); 7748 } 7749 7750 deferred.notifyWith( elem, [ animation, percent, remaining ] ); 7751 7752 if ( percent < 1 && length ) { 7753 return remaining; 7754 } else { 7755 deferred.resolveWith( elem, [ animation ] ); 7756 return false; 7757 } 7758 }, 7759 animation = deferred.promise( { 7760 elem: elem, 7761 props: jQuery.extend( {}, properties ), 7762 opts: jQuery.extend( true, { 7763 specialEasing: {}, 7764 easing: jQuery.easing._default 7765 }, options ), 7766 originalProperties: properties, 7767 originalOptions: options, 7768 startTime: fxNow || createFxNow(), 7769 duration: options.duration, 7770 tweens: [], 7771 createTween: function( prop, end ) { 7772 var tween = jQuery.Tween( elem, animation.opts, prop, end, 7773 animation.opts.specialEasing[ prop ] || animation.opts.easing ); 7774 animation.tweens.push( tween ); 7775 return tween; 7776 }, 7777 stop: function( gotoEnd ) { 7778 var index = 0, 7779 7780 // if we are going to the end, we want to run all the tweens 7781 // otherwise we skip this part 7782 length = gotoEnd ? animation.tweens.length : 0; 7783 if ( stopped ) { 7784 return this; 7785 } 7786 stopped = true; 7787 for ( ; index < length ; index++ ) { 7788 animation.tweens[ index ].run( 1 ); 7789 } 7790 7791 // resolve when we played the last frame 7792 // otherwise, reject 7793 if ( gotoEnd ) { 7794 deferred.notifyWith( elem, [ animation, 1, 0 ] ); 7795 deferred.resolveWith( elem, [ animation, gotoEnd ] ); 7796 } else { 7797 deferred.rejectWith( elem, [ animation, gotoEnd ] ); 7798 } 7799 return this; 7800 } 7801 } ), 7802 props = animation.props; 7803 7804 propFilter( props, animation.opts.specialEasing ); 7805 7806 for ( ; index < length ; index++ ) { 7807 result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts ); 7808 if ( result ) { 7809 if ( jQuery.isFunction( result.stop ) ) { 7810 jQuery._queueHooks( animation.elem, animation.opts.queue ).stop = 7811 jQuery.proxy( result.stop, result ); 7812 } 7813 return result; 7814 } 7815 } 7816 7817 jQuery.map( props, createTween, animation ); 7818 7819 if ( jQuery.isFunction( animation.opts.start ) ) { 7820 animation.opts.start.call( elem, animation ); 7821 } 7822 7823 jQuery.fx.timer( 7824 jQuery.extend( tick, { 7825 elem: elem, 7826 anim: animation, 7827 queue: animation.opts.queue 7828 } ) 7829 ); 7830 7831 // attach callbacks from options 7832 return animation.progress( animation.opts.progress ) 7833 .done( animation.opts.done, animation.opts.complete ) 7834 .fail( animation.opts.fail ) 7835 .always( animation.opts.always ); 7836} 7837 7838jQuery.Animation = jQuery.extend( Animation, { 7839 7840 tweeners: { 7841 "*": [ function( prop, value ) { 7842 var tween = this.createTween( prop, value ); 7843 adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween ); 7844 return tween; 7845 } ] 7846 }, 7847 7848 tweener: function( props, callback ) { 7849 if ( jQuery.isFunction( props ) ) { 7850 callback = props; 7851 props = [ "*" ]; 7852 } else { 7853 props = props.match( rnotwhite ); 7854 } 7855 7856 var prop, 7857 index = 0, 7858 length = props.length; 7859 7860 for ( ; index < length ; index++ ) { 7861 prop = props[ index ]; 7862 Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || []; 7863 Animation.tweeners[ prop ].unshift( callback ); 7864 } 7865 }, 7866 7867 prefilters: [ defaultPrefilter ], 7868 7869 prefilter: function( callback, prepend ) { 7870 if ( prepend ) { 7871 Animation.prefilters.unshift( callback ); 7872 } else { 7873 Animation.prefilters.push( callback ); 7874 } 7875 } 7876} ); 7877 7878jQuery.speed = function( speed, easing, fn ) { 7879 var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { 7880 complete: fn || !fn && easing || 7881 jQuery.isFunction( speed ) && speed, 7882 duration: speed, 7883 easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing 7884 }; 7885 7886 opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration : 7887 opt.duration in jQuery.fx.speeds ? 7888 jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default; 7889 7890 // normalize opt.queue - true/undefined/null -> "fx" 7891 if ( opt.queue == null || opt.queue === true ) { 7892 opt.queue = "fx"; 7893 } 7894 7895 // Queueing 7896 opt.old = opt.complete; 7897 7898 opt.complete = function() { 7899 if ( jQuery.isFunction( opt.old ) ) { 7900 opt.old.call( this ); 7901 } 7902 7903 if ( opt.queue ) { 7904 jQuery.dequeue( this, opt.queue ); 7905 } 7906 }; 7907 7908 return opt; 7909}; 7910 7911jQuery.fn.extend( { 7912 fadeTo: function( speed, to, easing, callback ) { 7913 7914 // show any hidden elements after setting opacity to 0 7915 return this.filter( isHidden ).css( "opacity", 0 ).show() 7916 7917 // animate to the value specified 7918 .end().animate( { opacity: to }, speed, easing, callback ); 7919 }, 7920 animate: function( prop, speed, easing, callback ) { 7921 var empty = jQuery.isEmptyObject( prop ), 7922 optall = jQuery.speed( speed, easing, callback ), 7923 doAnimation = function() { 7924 7925 // Operate on a copy of prop so per-property easing won't be lost 7926 var anim = Animation( this, jQuery.extend( {}, prop ), optall ); 7927 7928 // Empty animations, or finishing resolves immediately 7929 if ( empty || jQuery._data( this, "finish" ) ) { 7930 anim.stop( true ); 7931 } 7932 }; 7933 doAnimation.finish = doAnimation; 7934 7935 return empty || optall.queue === false ? 7936 this.each( doAnimation ) : 7937 this.queue( optall.queue, doAnimation ); 7938 }, 7939 stop: function( type, clearQueue, gotoEnd ) { 7940 var stopQueue = function( hooks ) { 7941 var stop = hooks.stop; 7942 delete hooks.stop; 7943 stop( gotoEnd ); 7944 }; 7945 7946 if ( typeof type !== "string" ) { 7947 gotoEnd = clearQueue; 7948 clearQueue = type; 7949 type = undefined; 7950 } 7951 if ( clearQueue && type !== false ) { 7952 this.queue( type || "fx", [] ); 7953 } 7954 7955 return this.each( function() { 7956 var dequeue = true, 7957 index = type != null && type + "queueHooks", 7958 timers = jQuery.timers, 7959 data = jQuery._data( this ); 7960 7961 if ( index ) { 7962 if ( data[ index ] && data[ index ].stop ) { 7963 stopQueue( data[ index ] ); 7964 } 7965 } else { 7966 for ( index in data ) { 7967 if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { 7968 stopQueue( data[ index ] ); 7969 } 7970 } 7971 } 7972 7973 for ( index = timers.length; index--; ) { 7974 if ( timers[ index ].elem === this && 7975 ( type == null || timers[ index ].queue === type ) ) { 7976 7977 timers[ index ].anim.stop( gotoEnd ); 7978 dequeue = false; 7979 timers.splice( index, 1 ); 7980 } 7981 } 7982 7983 // start the next in the queue if the last step wasn't forced 7984 // timers currently will call their complete callbacks, which will dequeue 7985 // but only if they were gotoEnd 7986 if ( dequeue || !gotoEnd ) { 7987 jQuery.dequeue( this, type ); 7988 } 7989 } ); 7990 }, 7991 finish: function( type ) { 7992 if ( type !== false ) { 7993 type = type || "fx"; 7994 } 7995 return this.each( function() { 7996 var index, 7997 data = jQuery._data( this ), 7998 queue = data[ type + "queue" ], 7999 hooks = data[ type + "queueHooks" ], 8000 timers = jQuery.timers, 8001 length = queue ? queue.length : 0; 8002 8003 // enable finishing flag on private data 8004 data.finish = true; 8005 8006 // empty the queue first 8007 jQuery.queue( this, type, [] ); 8008 8009 if ( hooks && hooks.stop ) { 8010 hooks.stop.call( this, true ); 8011 } 8012 8013 // look for any active animations, and finish them 8014 for ( index = timers.length; index--; ) { 8015 if ( timers[ index ].elem === this && timers[ index ].queue === type ) { 8016 timers[ index ].anim.stop( true ); 8017 timers.splice( index, 1 ); 8018 } 8019 } 8020 8021 // look for any animations in the old queue and finish them 8022 for ( index = 0; index < length; index++ ) { 8023 if ( queue[ index ] && queue[ index ].finish ) { 8024 queue[ index ].finish.call( this ); 8025 } 8026 } 8027 8028 // turn off finishing flag 8029 delete data.finish; 8030 } ); 8031 } 8032} ); 8033 8034jQuery.each( [ "toggle", "show", "hide" ], function( i, name ) { 8035 var cssFn = jQuery.fn[ name ]; 8036 jQuery.fn[ name ] = function( speed, easing, callback ) { 8037 return speed == null || typeof speed === "boolean" ? 8038 cssFn.apply( this, arguments ) : 8039 this.animate( genFx( name, true ), speed, easing, callback ); 8040 }; 8041} ); 8042 8043// Generate shortcuts for custom animations 8044jQuery.each( { 8045 slideDown: genFx( "show" ), 8046 slideUp: genFx( "hide" ), 8047 slideToggle: genFx( "toggle" ), 8048 fadeIn: { opacity: "show" }, 8049 fadeOut: { opacity: "hide" }, 8050 fadeToggle: { opacity: "toggle" } 8051}, function( name, props ) { 8052 jQuery.fn[ name ] = function( speed, easing, callback ) { 8053 return this.animate( props, speed, easing, callback ); 8054 }; 8055} ); 8056 8057jQuery.timers = []; 8058jQuery.fx.tick = function() { 8059 var timer, 8060 timers = jQuery.timers, 8061 i = 0; 8062 8063 fxNow = jQuery.now(); 8064 8065 for ( ; i < timers.length; i++ ) { 8066 timer = timers[ i ]; 8067 8068 // Checks the timer has not already been removed 8069 if ( !timer() && timers[ i ] === timer ) { 8070 timers.splice( i--, 1 ); 8071 } 8072 } 8073 8074 if ( !timers.length ) { 8075 jQuery.fx.stop(); 8076 } 8077 fxNow = undefined; 8078}; 8079 8080jQuery.fx.timer = function( timer ) { 8081 jQuery.timers.push( timer ); 8082 if ( timer() ) { 8083 jQuery.fx.start(); 8084 } else { 8085 jQuery.timers.pop(); 8086 } 8087}; 8088 8089jQuery.fx.interval = 13; 8090 8091jQuery.fx.start = function() { 8092 if ( !timerId ) { 8093 timerId = window.setInterval( jQuery.fx.tick, jQuery.fx.interval ); 8094 } 8095}; 8096 8097jQuery.fx.stop = function() { 8098 window.clearInterval( timerId ); 8099 timerId = null; 8100}; 8101 8102jQuery.fx.speeds = { 8103 slow: 600, 8104 fast: 200, 8105 8106 // Default speed 8107 _default: 400 8108}; 8109 8110 8111// Based off of the plugin by Clint Helfers, with permission. 8112// http://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/
8113jQuery.fn.delay = function( time, type ) { 8114 time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; 8115 type = type || "fx"; 8116 8117 return this.queue( type, function( next, hooks ) { 8118 var timeout = window.setTimeout( next, time ); 8119 hooks.stop = function() { 8120 window.clearTimeout( timeout ); 8121 }; 8122 } ); 8123}; 8124 8125 8126( function() { 8127 var a, 8128 input = document.createElement( "input" ), 8129 div = document.createElement( "div" ), 8130 select = document.createElement( "select" ), 8131 opt = select.appendChild( document.createElement( "option" ) ); 8132 8133 // Setup 8134 div = document.createElement( "div" ); 8135 div.setAttribute( "className", "t" ); 8136 div.innerHTML = " <link/><table></table><a href='/a'>a</a><input type='checkbox'/>"; 8137 a = div.getElementsByTagName( "a" )[ 0 ]; 8138 8139 // Support: Windows Web Apps (WWA) 8140 // `type` must use .setAttribute for WWA (#14901) 8141 input.setAttribute( "type", "checkbox" ); 8142 div.appendChild( input ); 8143 8144 a = div.getElementsByTagName( "a" )[ 0 ]; 8145 8146 // First batch of tests. 8147 a.style.cssText = "top:1px"; 8148 8149 // Test setAttribute on camelCase class. 8150 // If it works, we need attrFixes when doing get/setAttribute (ie6/7)
vendor: 2,696 bytes, lines 8151-8252
8151 support.getSetAttribute = div.className !== "t"; 8152 8153 // Get the style information from getAttribute 8154 // (IE uses .cssText instead) 8155 support.style = /top/.test( a.getAttribute( "style" ) ); 8156 8157 // Make sure that URLs aren't manipulated 8158 // (IE normalizes it by default) 8159 support.hrefNormalized = a.getAttribute( "href" ) === "/a"; 8160 8161 // Check the default checkbox/radio value ("" on WebKit; "on" elsewhere) 8162 support.checkOn = !!input.value; 8163 8164 // Make sure that a selected-by-default option has a working selected property. 8165 // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) 8166 support.optSelected = opt.selected; 8167 8168 // Tests for enctype support on a form (#6743) 8169 support.enctype = !!document.createElement( "form" ).enctype; 8170 8171 // Make sure that the options inside disabled selects aren't marked as disabled 8172 // (WebKit marks them as disabled) 8173 select.disabled = true; 8174 support.optDisabled = !opt.disabled; 8175 8176 // Support: IE8 only 8177 // Check if we can trust getAttribute("value") 8178 input = document.createElement( "input" ); 8179 input.setAttribute( "value", "" ); 8180 support.input = input.getAttribute( "value" ) === ""; 8181 8182 // Check if an input maintains its value after becoming a radio 8183 input.value = "t"; 8184 input.setAttribute( "type", "radio" ); 8185 support.radioValue = input.value === "t"; 8186} )(); 8187 8188 8189var rreturn = /\r/g, 8190 rspaces = /[\x20\t\r\n\f]+/g; 8191 8192jQuery.fn.extend( { 8193 val: function( value ) { 8194 var hooks, ret, isFunction, 8195 elem = this[ 0 ]; 8196 8197 if ( !arguments.length ) { 8198 if ( elem ) { 8199 hooks = jQuery.valHooks[ elem.type ] || 8200 jQuery.valHooks[ elem.nodeName.toLowerCase() ]; 8201 8202 if ( 8203 hooks && 8204 "get" in hooks && 8205 ( ret = hooks.get( elem, "value" ) ) !== undefined 8206 ) { 8207 return ret; 8208 } 8209 8210 ret = elem.value; 8211 8212 return typeof ret === "string" ? 8213 8214 // handle most common string cases 8215 ret.replace( rreturn, "" ) : 8216 8217 // handle cases where value is null/undef or number 8218 ret == null ? "" : ret; 8219 } 8220 8221 return; 8222 } 8223 8224 isFunction = jQuery.isFunction( value ); 8225 8226 return this.each( function( i ) { 8227 var val; 8228 8229 if ( this.nodeType !== 1 ) { 8230 return; 8231 } 8232 8233 if ( isFunction ) { 8234 val = value.call( this, i, jQuery( this ).val() ); 8235 } else { 8236 val = value; 8237 } 8238 8239 // Treat null/undefined as ""; convert numbers to string 8240 if ( val == null ) { 8241 val = ""; 8242 } else if ( typeof val === "number" ) { 8243 val += ""; 8244 } else if ( jQuery.isArray( val ) ) { 8245 val = jQuery.map( val, function( value ) { 8246 return value == null ? "" : value + ""; 8247 } ); 8248 } 8249 8250 hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; 8251 8252 // If set returns undefined, fall back to normal setting
vendor: 4,648 bytes, lines 8253-8443
8253 if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) { 8254 this.value = val; 8255 } 8256 } ); 8257 } 8258} ); 8259 8260jQuery.extend( { 8261 valHooks: { 8262 option: { 8263 get: function( elem ) { 8264 var val = jQuery.find.attr( elem, "value" ); 8265 return val != null ? 8266 val : 8267 8268 // Support: IE10-11+ 8269 // option.text throws exceptions (#14686, #14858) 8270 // Strip and collapse whitespace 8271 // https://html.spec.whatwg.org/#strip-and-collapse-whitespace 8272 jQuery.trim( jQuery.text( elem ) ).replace( rspaces, " " ); 8273 } 8274 }, 8275 select: { 8276 get: function( elem ) { 8277 var value, option, 8278 options = elem.options, 8279 index = elem.selectedIndex, 8280 one = elem.type === "select-one" || index < 0, 8281 values = one ? null : [], 8282 max = one ? index + 1 : options.length, 8283 i = index < 0 ? 8284 max : 8285 one ? index : 0; 8286 8287 // Loop through all the selected options 8288 for ( ; i < max; i++ ) { 8289 option = options[ i ]; 8290 8291 // oldIE doesn't update selected after form reset (#2551) 8292 if ( ( option.selected || i === index ) && 8293 8294 // Don't return options that are disabled or in a disabled optgroup 8295 ( support.optDisabled ? 8296 !option.disabled : 8297 option.getAttribute( "disabled" ) === null ) && 8298 ( !option.parentNode.disabled || 8299 !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) { 8300 8301 // Get the specific value for the option 8302 value = jQuery( option ).val(); 8303 8304 // We don't need an array for one selects 8305 if ( one ) { 8306 return value; 8307 } 8308 8309 // Multi-Selects return an array 8310 values.push( value ); 8311 } 8312 } 8313 8314 return values; 8315 }, 8316 8317 set: function( elem, value ) { 8318 var optionSet, option, 8319 options = elem.options, 8320 values = jQuery.makeArray( value ), 8321 i = options.length; 8322 8323 while ( i-- ) { 8324 option = options[ i ]; 8325 8326 if ( jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1 ) { 8327 8328 // Support: IE6 8329 // When new option element is added to select box we need to 8330 // force reflow of newly added node in order to workaround delay 8331 // of initialization properties 8332 try { 8333 option.selected = optionSet = true; 8334 8335 } catch ( _ ) { 8336 8337 // Will be executed only in IE6 8338 option.scrollHeight; 8339 } 8340 8341 } else { 8342 option.selected = false; 8343 } 8344 } 8345 8346 // Force browsers to behave consistently when non-matching value is set 8347 if ( !optionSet ) { 8348 elem.selectedIndex = -1; 8349 } 8350 8351 return options; 8352 } 8353 } 8354 } 8355} ); 8356 8357// Radios and checkboxes getter/setter 8358jQuery.each( [ "radio", "checkbox" ], function() { 8359 jQuery.valHooks[ this ] = { 8360 set: function( elem, value ) { 8361 if ( jQuery.isArray( value ) ) { 8362 return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 ); 8363 } 8364 } 8365 }; 8366 if ( !support.checkOn ) { 8367 jQuery.valHooks[ this ].get = function( elem ) { 8368 return elem.getAttribute( "value" ) === null ? "on" : elem.value; 8369 }; 8370 } 8371} ); 8372 8373 8374 8375 8376var nodeHook, boolHook, 8377 attrHandle = jQuery.expr.attrHandle, 8378 ruseDefault = /^(?:checked|selected)$/i, 8379 getSetAttribute = support.getSetAttribute, 8380 getSetInput = support.input; 8381 8382jQuery.fn.extend( { 8383 attr: function( name, value ) { 8384 return access( this, jQuery.attr, name, value, arguments.length > 1 ); 8385 }, 8386 8387 removeAttr: function( name ) { 8388 return this.each( function() { 8389 jQuery.removeAttr( this, name ); 8390 } ); 8391 } 8392} ); 8393 8394jQuery.extend( { 8395 attr: function( elem, name, value ) { 8396 var ret, hooks, 8397 nType = elem.nodeType; 8398 8399 // Don't get/set attributes on text, comment and attribute nodes 8400 if ( nType === 3 || nType === 8 || nType === 2 ) { 8401 return; 8402 } 8403 8404 // Fallback to prop when attributes are not supported 8405 if ( typeof elem.getAttribute === "undefined" ) { 8406 return jQuery.prop( elem, name, value ); 8407 } 8408 8409 // All attributes are lowercase 8410 // Grab necessary hook if one is defined 8411 if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { 8412 name = name.toLowerCase(); 8413 hooks = jQuery.attrHooks[ name ] || 8414 ( jQuery.expr.match.bool.test( name ) ? boolHook : nodeHook ); 8415 } 8416 8417 if ( value !== undefined ) { 8418 if ( value === null ) { 8419 jQuery.removeAttr( elem, name ); 8420 return; 8421 } 8422 8423 if ( hooks && "set" in hooks && 8424 ( ret = hooks.set( elem, value, name ) ) !== undefined ) { 8425 return ret; 8426 } 8427 8428 elem.setAttribute( name, value + "" ); 8429 return value; 8430 } 8431 8432 if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { 8433 return ret; 8434 } 8435 8436 ret = jQuery.find.attr( elem, name ); 8437 8438 // Non-existent attributes return null, we normalize to undefined 8439 return ret == null ? undefined : ret; 8440 }, 8441 8442 attrHooks: { 8443 type: {
vendor: 4,457 bytes, lines 8444-8610
8444 set: function( elem, value ) { 8445 if ( !support.radioValue && value === "radio" && 8446 jQuery.nodeName( elem, "input" ) ) { 8447 8448 // Setting the type on a radio button after the value resets the value in IE8-9 8449 // Reset value to default in case type is set after value during creation 8450 var val = elem.value; 8451 elem.setAttribute( "type", value ); 8452 if ( val ) { 8453 elem.value = val; 8454 } 8455 return value; 8456 } 8457 } 8458 } 8459 }, 8460 8461 removeAttr: function( elem, value ) { 8462 var name, propName, 8463 i = 0, 8464 attrNames = value && value.match( rnotwhite ); 8465 8466 if ( attrNames && elem.nodeType === 1 ) { 8467 while ( ( name = attrNames[ i++ ] ) ) { 8468 propName = jQuery.propFix[ name ] || name; 8469 8470 // Boolean attributes get special treatment (#10870) 8471 if ( jQuery.expr.match.bool.test( name ) ) { 8472 8473 // Set corresponding property to false 8474 if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) { 8475 elem[ propName ] = false; 8476 8477 // Support: IE<9 8478 // Also clear defaultChecked/defaultSelected (if appropriate) 8479 } else { 8480 elem[ jQuery.camelCase( "default-" + name ) ] = 8481 elem[ propName ] = false; 8482 } 8483 8484 // See #9699 for explanation of this approach (setting first, then removal) 8485 } else { 8486 jQuery.attr( elem, name, "" ); 8487 } 8488 8489 elem.removeAttribute( getSetAttribute ? name : propName ); 8490 } 8491 } 8492 } 8493} ); 8494 8495// Hooks for boolean attributes 8496boolHook = { 8497 set: function( elem, value, name ) { 8498 if ( value === false ) { 8499 8500 // Remove boolean attributes when set to false 8501 jQuery.removeAttr( elem, name ); 8502 } else if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) { 8503 8504 // IE<8 needs the *property* name 8505 elem.setAttribute( !getSetAttribute && jQuery.propFix[ name ] || name, name ); 8506 8507 } else { 8508 8509 // Support: IE<9 8510 // Use defaultChecked and defaultSelected for oldIE 8511 elem[ jQuery.camelCase( "default-" + name ) ] = elem[ name ] = true; 8512 } 8513 return name; 8514 } 8515}; 8516 8517jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) { 8518 var getter = attrHandle[ name ] || jQuery.find.attr; 8519 8520 if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) { 8521 attrHandle[ name ] = function( elem, name, isXML ) { 8522 var ret, handle; 8523 if ( !isXML ) { 8524 8525 // Avoid an infinite loop by temporarily removing this function from the getter 8526 handle = attrHandle[ name ]; 8527 attrHandle[ name ] = ret; 8528 ret = getter( elem, name, isXML ) != null ? 8529 name.toLowerCase() : 8530 null; 8531 attrHandle[ name ] = handle; 8532 } 8533 return ret; 8534 }; 8535 } else { 8536 attrHandle[ name ] = function( elem, name, isXML ) { 8537 if ( !isXML ) { 8538 return elem[ jQuery.camelCase( "default-" + name ) ] ? 8539 name.toLowerCase() : 8540 null; 8541 } 8542 }; 8543 } 8544} ); 8545 8546// fix oldIE attroperties 8547if ( !getSetInput || !getSetAttribute ) { 8548 jQuery.attrHooks.value = { 8549 set: function( elem, value, name ) { 8550 if ( jQuery.nodeName( elem, "input" ) ) { 8551 8552 // Does not return so that setAttribute is also used 8553 elem.defaultValue = value; 8554 } else { 8555 8556 // Use nodeHook if defined (#1954); otherwise setAttribute is fine 8557 return nodeHook && nodeHook.set( elem, value, name ); 8558 } 8559 } 8560 }; 8561} 8562 8563// IE6/7 do not support getting/setting some attributes with get/setAttribute 8564if ( !getSetAttribute ) { 8565 8566 // Use this for any attribute in IE6/7 8567 // This fixes almost every IE6/7 issue 8568 nodeHook = { 8569 set: function( elem, value, name ) { 8570 8571 // Set the existing or create a new attribute node 8572 var ret = elem.getAttributeNode( name ); 8573 if ( !ret ) { 8574 elem.setAttributeNode( 8575 ( ret = elem.ownerDocument.createAttribute( name ) ) 8576 ); 8577 } 8578 8579 ret.value = value += ""; 8580 8581 // Break association with cloned elements by also using setAttribute (#9646) 8582 if ( name === "value" || value === elem.getAttribute( name ) ) { 8583 return value; 8584 } 8585 } 8586 }; 8587 8588 // Some attributes are constructed with empty-string values when not defined 8589 attrHandle.id = attrHandle.name = attrHandle.coords = 8590 function( elem, name, isXML ) { 8591 var ret; 8592 if ( !isXML ) { 8593 return ( ret = elem.getAttributeNode( name ) ) && ret.value !== "" ? 8594 ret.value : 8595 null; 8596 } 8597 }; 8598 8599 // Fixing value retrieval on a button requires this module 8600 jQuery.valHooks.button = { 8601 get: function( elem, name ) { 8602 var ret = elem.getAttributeNode( name ); 8603 if ( ret && ret.specified ) { 8604 return ret.value; 8605 } 8606 }, 8607 set: nodeHook.set 8608 }; 8609 8610 // Set contenteditable to false on removals(#10429)
8611 // Setting to empty string throws an error as an invalid value 8612 jQuery.attrHooks.contenteditable = { 8613 set: function( elem, value, name ) { 8614 nodeHook.set( elem, value === "" ? false : value, name ); 8615 } 8616 }; 8617 8618 // Set width and height to auto instead of 0 on empty string( Bug #8150 ) 8619 // This is for removals 8620 jQuery.each( [ "width", "height" ], function( i, name ) { 8621 jQuery.attrHooks[ name ] = { 8622 set: function( elem, value ) { 8623 if ( value === "" ) { 8624 elem.setAttribute( name, "auto" ); 8625 return value; 8626 } 8627 } 8628 }; 8629 } ); 8630} 8631 8632if ( !support.style ) { 8633 jQuery.attrHooks.style = { 8634 get: function( elem ) { 8635 8636 // Return undefined in the case of empty string 8637 // Note: IE uppercases css property names, but if we were to .toLowerCase() 8638 // .cssText, that would destroy case sensitivity in URL's, like in "background" 8639 return elem.style.cssText || undefined; 8640 }, 8641 set: function( elem, value ) { 8642 return ( elem.style.cssText = value + "" ); 8643 } 8644 }; 8645} 8646 8647 8648 8649 8650var rfocusable = /^(?:input|select|textarea|button|object)$/i, 8651 rclickable = /^(?:a|area)$/i; 8652 8653jQuery.fn.extend( { 8654 prop: function( name, value ) { 8655 return access( this, jQuery.prop, name, value, arguments.length > 1 ); 8656 }, 8657 8658 removeProp: function( name ) { 8659 name = jQuery.propFix[ name ] || name; 8660 return this.each( function() { 8661 8662 // try/catch handles cases where IE balks (such as removing a property on window) 8663 try { 8664 this[ name ] = undefined; 8665 delete this[ name ]; 8666 } catch ( e ) {} 8667 } ); 8668 } 8669} ); 8670 8671jQuery.extend( { 8672 prop: function( elem, name, value ) { 8673 var ret, hooks, 8674 nType = elem.nodeType; 8675 8676 // Don't get/set properties on text, comment and attribute nodes 8677 if ( nType === 3 || nType === 8 || nType === 2 ) { 8678 return; 8679 } 8680 8681 if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { 8682 8683 // Fix name and attach hooks 8684 name = jQuery.propFix[ name ] || name; 8685 hooks = jQuery.propHooks[ name ]; 8686 } 8687 8688 if ( value !== undefined ) { 8689 if ( hooks && "set" in hooks && 8690 ( ret = hooks.set( elem, value, name ) ) !== undefined ) { 8691 return ret; 8692 } 8693 8694 return ( elem[ name ] = value ); 8695 } 8696 8697 if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { 8698 return ret; 8699 } 8700 8701 return elem[ name ]; 8702 }, 8703 8704 propHooks: { 8705 tabIndex: { 8706 get: function( elem ) { 8707 8708 // elem.tabIndex doesn't always return the 8709 // correct value when it hasn't been explicitly set 8710 // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ 8711 // Use proper attribute retrieval(#12072) 8712 var tabindex = jQuery.find.attr( elem, "tabindex" ); 8713 8714 return tabindex ? 8715 parseInt( tabindex, 10 ) : 8716 rfocusable.test( elem.nodeName ) || 8717 rclickable.test( elem.nodeName ) && elem.href ? 8718 0 : 8719 -1; 8720 } 8721 } 8722 }, 8723 8724 propFix: { 8725 "for": "htmlFor", 8726 "class": "className" 8727 } 8728} ); 8729 8730// Some attributes require a special call on IE 8731// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx 8732if ( !support.hrefNormalized ) { 8733 8734 // href/src property should get the full normalized URL (#10299/#12915) 8735 jQuery.each( [ "href", "src" ], function( i, name ) { 8736 jQuery.propHooks[ name ] = { 8737 get: function( elem ) { 8738 return elem.getAttribute( name, 4 ); 8739 } 8740 }; 8741 } ); 8742} 8743 8744// Support: Safari, IE9+ 8745// Accessing the selectedIndex property 8746// forces the browser to respect setting selected 8747// on the option 8748// The getter ensures a default option is selected 8749// when in an optgroup 8750if ( !support.optSelected ) { 8751 jQuery.propHooks.selected = { 8752 get: function( elem ) { 8753 var parent = elem.parentNode; 8754 8755 if ( parent ) { 8756 parent.selectedIndex; 8757 8758 // Make sure that it also works with optgroups, see #5701 8759 if ( parent.parentNode ) { 8760 parent.parentNode.selectedIndex; 8761 } 8762 } 8763 return null; 8764 }, 8765 set: function( elem ) { 8766 var parent = elem.parentNode; 8767 if ( parent ) { 8768 parent.selectedIndex; 8769 8770 if ( parent.parentNode ) { 8771 parent.parentNode.selectedIndex; 8772 } 8773 } 8774 } 8775 }; 8776} 8777 8778jQuery.each( [ 8779 "tabIndex", 8780 "readOnly", 8781 "maxLength", 8782 "cellSpacing", 8783 "cellPadding", 8784 "rowSpan", 8785 "colSpan", 8786 "useMap", 8787 "frameBorder", 8788 "contentEditable" 8789], function() { 8790 jQuery.propFix[ this.toLowerCase() ] = this; 8791} ); 8792 8793// IE6/7 call enctype encoding 8794if ( !support.enctype ) { 8795 jQuery.propFix.enctype = "encoding"; 8796} 8797 8798 8799 8800 8801var rclass = /[\t\r\n\f]/g; 8802 8803function getClass( elem ) { 8804 return jQuery.attr( elem, "class" ) || ""; 8805} 8806 8807jQuery.fn.extend( { 8808 addClass: function( value ) { 8809 var classes, elem, cur, curValue, clazz, j, finalValue, 8810 i = 0; 8811 8812 if ( jQuery.isFunction( value ) ) { 8813 return this.each( function( j ) { 8814 jQuery( this ).addClass( value.call( this, j, getClass( this ) ) ); 8815 } ); 8816 } 8817 8818 if ( typeof value === "string" && value ) { 8819 classes = value.match( rnotwhite ) || []; 8820 8821 while ( ( elem = this[ i++ ] ) ) { 8822 curValue = getClass( elem ); 8823 cur = elem.nodeType === 1 && 8824 ( " " + curValue + " " ).replace( rclass, " " ); 8825 8826 if ( cur ) { 8827 j = 0; 8828 while ( ( clazz = classes[ j++ ] ) ) { 8829 if ( cur.indexOf( " " + clazz + " " ) < 0 ) { 8830 cur += clazz + " "; 8831 } 8832 } 8833 8834 // only assign if different to avoid unneeded rendering. 8835 finalValue = jQuery.trim( cur ); 8836 if ( curValue !== finalValue ) { 8837 jQuery.attr( elem, "class", finalValue ); 8838 } 8839 } 8840 } 8841 } 8842 8843 return this; 8844 }, 8845 8846 removeClass: function( value ) { 8847 var classes, elem, cur, curValue, clazz, j, finalValue, 8848 i = 0; 8849 8850 if ( jQuery.isFunction( value ) ) { 8851 return this.each( function( j ) { 8852 jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) ); 8853 } ); 8854 } 8855 8856 if ( !arguments.length ) { 8857 return this.attr( "class", "" ); 8858 } 8859 8860 if ( typeof value === "string" && value ) { 8861 classes = value.match( rnotwhite ) || []; 8862 8863 while ( ( elem = this[ i++ ] ) ) { 8864 curValue = getClass( elem ); 8865 8866 // This expression is here for better compressibility (see addClass) 8867 cur = elem.nodeType === 1 && 8868 ( " " + curValue + " " ).replace( rclass, " " ); 8869 8870 if ( cur ) { 8871 j = 0; 8872 while ( ( clazz = classes[ j++ ] ) ) { 8873
8874 // Remove *all* instances 8875 while ( cur.indexOf( " " + clazz + " " ) > -1 ) { 8876 cur = cur.replace( " " + clazz + " ", " " ); 8877 } 8878 } 8879 8880 // Only assign if different to avoid unneeded rendering. 8881 finalValue = jQuery.trim( cur ); 8882 if ( curValue !== finalValue ) { 8883 jQuery.attr( elem, "class", finalValue ); 8884 } 8885 } 8886 } 8887 } 8888 8889 return this; 8890 }, 8891 8892 toggleClass: function( value, stateVal ) { 8893 var type = typeof value; 8894 8895 if ( typeof stateVal === "boolean" && type === "string" ) { 8896 return stateVal ? this.addClass( value ) : this.removeClass( value ); 8897 } 8898 8899 if ( jQuery.isFunction( value ) ) { 8900 return this.each( function( i ) { 8901 jQuery( this ).toggleClass( 8902 value.call( this, i, getClass( this ), stateVal ), 8903 stateVal 8904 ); 8905 } ); 8906 } 8907 8908 return this.each( function() { 8909 var className, i, self, classNames; 8910 8911 if ( type === "string" ) { 8912 8913 // Toggle individual class names 8914 i = 0; 8915 self = jQuery( this ); 8916 classNames = value.match( rnotwhite ) || []; 8917 8918 while ( ( className = classNames[ i++ ] ) ) { 8919 8920 // Check each className given, space separated list 8921 if ( self.hasClass( className ) ) { 8922 self.removeClass( className ); 8923 } else { 8924 self.addClass( className ); 8925 } 8926 } 8927 8928 // Toggle whole class name 8929 } else if ( value === undefined || type === "boolean" ) { 8930 className = getClass( this ); 8931 if ( className ) { 8932 8933 // store className if set 8934 jQuery._data( this, "__className__", className ); 8935 } 8936 8937 // If the element has a class name or if we're passed "false", 8938 // then remove the whole classname (if there was one, the above saved it). 8939 // Otherwise bring back whatever was previously saved (if anything), 8940 // falling back to the empty string if nothing was stored. 8941 jQuery.attr( this, "class", 8942 className || value === false ? 8943 "" : 8944 jQuery._data( this, "__className__" ) || "" 8945 ); 8946 } 8947 } ); 8948 }, 8949 8950 hasClass: function( selector ) { 8951 var className, elem, 8952 i = 0; 8953 8954 className = " " + selector + " "; 8955 while ( ( elem = this[ i++ ] ) ) { 8956 if ( elem.nodeType === 1 && 8957 ( " " + getClass( elem ) + " " ).replace( rclass, " " ) 8958 .indexOf( className ) > -1 8959 ) { 8960 return true; 8961 } 8962 } 8963 8964 return false; 8965 } 8966} ); 8967 8968 8969 8970 8971// Return jQuery for attributes-only inclusion 8972 8973 8974jQuery.each( ( "blur focus focusin focusout load resize scroll unload click dblclick " + 8975 "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + 8976 "change select submit keydown keypress keyup error contextmenu" ).split( " " ), 8977 function( i, name ) { 8978 8979 // Handle event binding 8980 jQuery.fn[ name ] = function( data, fn ) { 8981 return arguments.length > 0 ? 8982 this.on( name, null, data, fn ) : 8983 this.trigger( name ); 8984 }; 8985} ); 8986 8987jQuery.fn.extend( { 8988 hover: function( fnOver, fnOut ) { 8989 return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); 8990 } 8991} ); 8992 8993 8994var location = window.location; 8995 8996var nonce = jQuery.now(); 8997 8998var rquery = ( /\?/ ); 8999 9000 9001 9002var rvalidtokens = /(,)|(\[|{)|(}|])|"(?:[^"\\\r\n]|\\["\\\/bfnrt]|\\u[\da-fA-F]{4})*"\s*:?|true|false|null|-?(?!0\d)\d+(?:\.\d+|)(?:[eE][+-]?\d+|)/g; 9003 9004jQuery.parseJSON = function( data ) { 9005 9006 // Attempt to parse using the native JSON parser first 9007 if ( window.JSON && window.JSON.parse ) { 9008 9009 // Support: Android 2.3 9010 // Workaround failure to string-cast null input 9011 return window.JSON.parse( data + "" ); 9012 } 9013 9014 var requireNonComma, 9015 depth = null, 9016 str = jQuery.trim( data + "" ); 9017 9018 // Guard against invalid (and possibly dangerous) input by ensuring that nothing remains 9019 // after removing valid tokens 9020 return str && !jQuery.trim( str.replace( rvalidtokens, function( token, comma, open, close ) { 9021 9022 // Force termination if we see a misplaced comma 9023 if ( requireNonComma && comma ) { 9024 depth = 0; 9025 } 9026 9027 // Perform no more replacements after returning to outermost depth 9028 if ( depth === 0 ) { 9029 return token; 9030 } 9031 9032 // Commas must not follow "[", "{", or "," 9033 requireNonComma = open || comma; 9034 9035 // Determine new depth 9036 // array/object open ("[" or "{"): depth += true - false (increment) 9037 // array/object close ("]" or "}"): depth += false - true (decrement) 9038 // other cases ("," or primitive): depth += true - true (numeric cast) 9039 depth += !close - !open; 9040 9041 // Remove this token 9042 return ""; 9043 } ) ) ? 9044 ( Function( "return " + str ) )() : 9045 jQuery.error( "Invalid JSON: " + data ); 9046}; 9047 9048 9049// Cross-browser xml parsing
vendor: 10,393 bytes, lines 9050-9455
9050jQuery.parseXML = function( data ) { 9051 var xml, tmp; 9052 if ( !data || typeof data !== "string" ) { 9053 return null; 9054 } 9055 try { 9056 if ( window.DOMParser ) { // Standard 9057 tmp = new window.DOMParser(); 9058 xml = tmp.parseFromString( data, "text/xml" ); 9059 } else { // IE 9060 xml = new window.ActiveXObject( "Microsoft.XMLDOM" ); 9061 xml.async = "false"; 9062 xml.loadXML( data ); 9063 } 9064 } catch ( e ) { 9065 xml = undefined; 9066 } 9067 if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) { 9068 jQuery.error( "Invalid XML: " + data ); 9069 } 9070 return xml; 9071}; 9072 9073 9074var 9075 rhash = /#.*$/, 9076 rts = /([?&])_=[^&]*/, 9077 9078 // IE leaves an \r character at EOL 9079 rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, 9080 9081 // #7653, #8125, #8152: local protocol detection 9082 rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, 9083 rnoContent = /^(?:GET|HEAD)$/, 9084 rprotocol = /^\/\//, 9085 rurl = /^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/, 9086 9087 /* Prefilters 9088 * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) 9089 * 2) These are called: 9090 * - BEFORE asking for a transport 9091 * - AFTER param serialization (s.data is a string if s.processData is true) 9092 * 3) key is the dataType 9093 * 4) the catchall symbol "*" can be used 9094 * 5) execution will start with transport dataType and THEN continue down to "*" if needed 9095 */ 9096 prefilters = {}, 9097 9098 /* Transports bindings 9099 * 1) key is the dataType 9100 * 2) the catchall symbol "*" can be used 9101 * 3) selection will start with transport dataType and THEN go to "*" if needed 9102 */ 9103 transports = {}, 9104 9105 // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression 9106 allTypes = "*/".concat( "*" ), 9107 9108 // Document location 9109 ajaxLocation = location.href, 9110 9111 // Segment location into parts 9112 ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || []; 9113 9114// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport 9115function addToPrefiltersOrTransports( structure ) { 9116 9117 // dataTypeExpression is optional and defaults to "*" 9118 return function( dataTypeExpression, func ) { 9119 9120 if ( typeof dataTypeExpression !== "string" ) { 9121 func = dataTypeExpression; 9122 dataTypeExpression = "*"; 9123 } 9124 9125 var dataType, 9126 i = 0, 9127 dataTypes = dataTypeExpression.toLowerCase().match( rnotwhite ) || []; 9128 9129 if ( jQuery.isFunction( func ) ) { 9130 9131 // For each dataType in the dataTypeExpression 9132 while ( ( dataType = dataTypes[ i++ ] ) ) { 9133 9134 // Prepend if requested 9135 if ( dataType.charAt( 0 ) === "+" ) { 9136 dataType = dataType.slice( 1 ) || "*"; 9137 ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func ); 9138 9139 // Otherwise append 9140 } else { 9141 ( structure[ dataType ] = structure[ dataType ] || [] ).push( func ); 9142 } 9143 } 9144 } 9145 }; 9146} 9147 9148// Base inspection function for prefilters and transports 9149function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) { 9150 9151 var inspected = {}, 9152 seekingTransport = ( structure === transports ); 9153 9154 function inspect( dataType ) { 9155 var selected; 9156 inspected[ dataType ] = true; 9157 jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) { 9158 var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR ); 9159 if ( typeof dataTypeOrTransport === "string" && 9160 !seekingTransport && !inspected[ dataTypeOrTransport ] ) { 9161 9162 options.dataTypes.unshift( dataTypeOrTransport ); 9163 inspect( dataTypeOrTransport ); 9164 return false; 9165 } else if ( seekingTransport ) { 9166 return !( selected = dataTypeOrTransport ); 9167 } 9168 } ); 9169 return selected; 9170 } 9171 9172 return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" ); 9173} 9174 9175// A special extend for ajax options 9176// that takes "flat" options (not to be deep extended) 9177// Fixes #9887 9178function ajaxExtend( target, src ) { 9179 var deep, key, 9180 flatOptions = jQuery.ajaxSettings.flatOptions || {}; 9181 9182 for ( key in src ) { 9183 if ( src[ key ] !== undefined ) { 9184 ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; 9185 } 9186 } 9187 if ( deep ) { 9188 jQuery.extend( true, target, deep ); 9189 } 9190 9191 return target; 9192} 9193 9194/* Handles responses to an ajax request: 9195 * - finds the right dataType (mediates between content-type and expected dataType) 9196 * - returns the corresponding response 9197 */ 9198function ajaxHandleResponses( s, jqXHR, responses ) { 9199 var firstDataType, ct, finalDataType, type, 9200 contents = s.contents, 9201 dataTypes = s.dataTypes; 9202 9203 // Remove auto dataType and get content-type in the process 9204 while ( dataTypes[ 0 ] === "*" ) { 9205 dataTypes.shift(); 9206 if ( ct === undefined ) { 9207 ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" ); 9208 } 9209 } 9210 9211 // Check if we're dealing with a known content-type 9212 if ( ct ) { 9213 for ( type in contents ) { 9214 if ( contents[ type ] && contents[ type ].test( ct ) ) { 9215 dataTypes.unshift( type ); 9216 break; 9217 } 9218 } 9219 } 9220 9221 // Check to see if we have a response for the expected dataType 9222 if ( dataTypes[ 0 ] in responses ) { 9223 finalDataType = dataTypes[ 0 ]; 9224 } else { 9225 9226 // Try convertible dataTypes 9227 for ( type in responses ) { 9228 if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) { 9229 finalDataType = type; 9230 break; 9231 } 9232 if ( !firstDataType ) { 9233 firstDataType = type; 9234 } 9235 } 9236 9237 // Or just use first one 9238 finalDataType = finalDataType || firstDataType; 9239 } 9240 9241 // If we found a dataType 9242 // We add the dataType to the list if needed 9243 // and return the corresponding response 9244 if ( finalDataType ) { 9245 if ( finalDataType !== dataTypes[ 0 ] ) { 9246 dataTypes.unshift( finalDataType ); 9247 } 9248 return responses[ finalDataType ]; 9249 } 9250} 9251 9252/* Chain conversions given the request and the original response 9253 * Also sets the responseXXX fields on the jqXHR instance 9254 */ 9255function ajaxConvert( s, response, jqXHR, isSuccess ) { 9256 var conv2, current, conv, tmp, prev, 9257 converters = {}, 9258 9259 // Work with a copy of dataTypes in case we need to modify it for conversion 9260 dataTypes = s.dataTypes.slice(); 9261 9262 // Create converters map with lowercased keys 9263 if ( dataTypes[ 1 ] ) { 9264 for ( conv in s.converters ) { 9265 converters[ conv.toLowerCase() ] = s.converters[ conv ]; 9266 } 9267 } 9268 9269 current = dataTypes.shift(); 9270 9271 // Convert to each sequential dataType 9272 while ( current ) { 9273 9274 if ( s.responseFields[ current ] ) { 9275 jqXHR[ s.responseFields[ current ] ] = response; 9276 } 9277 9278 // Apply the dataFilter if provided 9279 if ( !prev && isSuccess && s.dataFilter ) { 9280 response = s.dataFilter( response, s.dataType ); 9281 } 9282 9283 prev = current; 9284 current = dataTypes.shift(); 9285 9286 if ( current ) { 9287 9288 // There's only work to do if current dataType is non-auto 9289 if ( current === "*" ) { 9290 9291 current = prev; 9292 9293 // Convert response if prev dataType is non-auto and differs from current 9294 } else if ( prev !== "*" && prev !== current ) { 9295 9296 // Seek a direct converter 9297 conv = converters[ prev + " " + current ] || converters[ "* " + current ]; 9298 9299 // If none found, seek a pair 9300 if ( !conv ) { 9301 for ( conv2 in converters ) { 9302 9303 // If conv2 outputs current 9304 tmp = conv2.split( " " ); 9305 if ( tmp[ 1 ] === current ) { 9306 9307 // If prev can be converted to accepted input 9308 conv = converters[ prev + " " + tmp[ 0 ] ] || 9309 converters[ "* " + tmp[ 0 ] ]; 9310 if ( conv ) { 9311 9312 // Condense equivalence converters 9313 if ( conv === true ) { 9314 conv = converters[ conv2 ]; 9315 9316 // Otherwise, insert the intermediate dataType 9317 } else if ( converters[ conv2 ] !== true ) { 9318 current = tmp[ 0 ]; 9319 dataTypes.unshift( tmp[ 1 ] ); 9320 } 9321 break; 9322 } 9323 } 9324 } 9325 } 9326 9327 // Apply converter (if not an equivalence) 9328 if ( conv !== true ) { 9329 9330 // Unless errors are allowed to bubble, catch and return them 9331 if ( conv && s[ "throws" ] ) { // jscs:ignore requireDotNotation 9332 response = conv( response ); 9333 } else { 9334 try { 9335 response = conv( response ); 9336 } catch ( e ) { 9337 return { 9338 state: "parsererror", 9339 error: conv ? e : "No conversion from " + prev + " to " + current 9340 }; 9341 } 9342 } 9343 } 9344 } 9345 } 9346 } 9347 9348 return { state: "success", data: response }; 9349} 9350 9351jQuery.extend( { 9352 9353 // Counter for holding the number of active queries 9354 active: 0, 9355 9356 // Last-Modified header cache for next request 9357 lastModified: {}, 9358 etag: {}, 9359 9360 ajaxSettings: { 9361 url: ajaxLocation, 9362 type: "GET", 9363 isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ), 9364 global: true, 9365 processData: true, 9366 async: true, 9367 contentType: "application/x-www-form-urlencoded; charset=UTF-8", 9368 /* 9369 timeout: 0, 9370 data: null, 9371 dataType: null, 9372 username: null, 9373 password: null, 9374 cache: null, 9375 throws: false, 9376 traditional: false, 9377 headers: {}, 9378 */ 9379 9380 accepts: { 9381 "*": allTypes, 9382 text: "text/plain", 9383 html: "text/html", 9384 xml: "application/xml, text/xml", 9385 json: "application/json, text/javascript" 9386 }, 9387 9388 contents: { 9389 xml: /\bxml\b/, 9390 html: /\bhtml/, 9391 json: /\bjson\b/ 9392 }, 9393 9394 responseFields: { 9395 xml: "responseXML", 9396 text: "responseText", 9397 json: "responseJSON" 9398 }, 9399 9400 // Data converters 9401 // Keys separate source (or catchall "*") and destination types with a single space 9402 converters: { 9403 9404 // Convert anything to text 9405 "* text": String, 9406 9407 // Text to html (true = no transformation) 9408 "text html": true, 9409 9410 // Evaluate text as a json expression 9411 "text json": jQuery.parseJSON, 9412 9413 // Parse text as xml 9414 "text xml": jQuery.parseXML 9415 }, 9416 9417 // For options that shouldn't be deep extended: 9418 // you can add your own custom options here if 9419 // and when you create one that shouldn't be 9420 // deep extended (see ajaxExtend) 9421 flatOptions: { 9422 url: true, 9423 context: true 9424 } 9425 }, 9426 9427 // Creates a full fledged settings object into target 9428 // with both ajaxSettings and settings fields. 9429 // If target is omitted, writes into ajaxSettings. 9430 ajaxSetup: function( target, settings ) { 9431 return settings ? 9432 9433 // Building a settings object 9434 ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) : 9435 9436 // Extending ajaxSettings 9437 ajaxExtend( jQuery.ajaxSettings, target ); 9438 }, 9439 9440 ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), 9441 ajaxTransport: addToPrefiltersOrTransports( transports ), 9442 9443 // Main method 9444 ajax: function( url, options ) { 9445 9446 // If url is an object, simulate pre-1.5 signature 9447 if ( typeof url === "object" ) { 9448 options = url; 9449 url = undefined; 9450 } 9451 9452 // Force options to be an object 9453 options = options || {}; 9454 9455 var
vendor: 5,146 bytes, lines 9456-9646
9456 9457 // Cross-domain detection vars 9458 parts, 9459 9460 // Loop variable 9461 i, 9462 9463 // URL without anti-cache param 9464 cacheURL, 9465 9466 // Response headers as string 9467 responseHeadersString, 9468 9469 // timeout handle 9470 timeoutTimer, 9471 9472 // To know if global events are to be dispatched 9473 fireGlobals, 9474 9475 transport, 9476 9477 // Response headers 9478 responseHeaders, 9479 9480 // Create the final options object 9481 s = jQuery.ajaxSetup( {}, options ), 9482 9483 // Callbacks context 9484 callbackContext = s.context || s, 9485 9486 // Context for global events is callbackContext if it is a DOM node or jQuery collection 9487 globalEventContext = s.context && 9488 ( callbackContext.nodeType || callbackContext.jquery ) ? 9489 jQuery( callbackContext ) : 9490 jQuery.event, 9491 9492 // Deferreds 9493 deferred = jQuery.Deferred(), 9494 completeDeferred = jQuery.Callbacks( "once memory" ), 9495 9496 // Status-dependent callbacks 9497 statusCode = s.statusCode || {}, 9498 9499 // Headers (they are sent all at once) 9500 requestHeaders = {}, 9501 requestHeadersNames = {}, 9502 9503 // The jqXHR state 9504 state = 0, 9505 9506 // Default abort message 9507 strAbort = "canceled", 9508 9509 // Fake xhr 9510 jqXHR = { 9511 readyState: 0, 9512 9513 // Builds headers hashtable if needed 9514 getResponseHeader: function( key ) { 9515 var match; 9516 if ( state === 2 ) { 9517 if ( !responseHeaders ) { 9518 responseHeaders = {}; 9519 while ( ( match = rheaders.exec( responseHeadersString ) ) ) { 9520 responseHeaders[ match[ 1 ].toLowerCase() ] = match[ 2 ]; 9521 } 9522 } 9523 match = responseHeaders[ key.toLowerCase() ]; 9524 } 9525 return match == null ? null : match; 9526 }, 9527 9528 // Raw string 9529 getAllResponseHeaders: function() { 9530 return state === 2 ? responseHeadersString : null; 9531 }, 9532 9533 // Caches the header 9534 setRequestHeader: function( name, value ) { 9535 var lname = name.toLowerCase(); 9536 if ( !state ) { 9537 name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name; 9538 requestHeaders[ name ] = value; 9539 } 9540 return this; 9541 }, 9542 9543 // Overrides response content-type header 9544 overrideMimeType: function( type ) { 9545 if ( !state ) { 9546 s.mimeType = type; 9547 } 9548 return this; 9549 }, 9550 9551 // Status-dependent callbacks 9552 statusCode: function( map ) { 9553 var code; 9554 if ( map ) { 9555 if ( state < 2 ) { 9556 for ( code in map ) { 9557 9558 // Lazy-add the new callback in a way that preserves old ones 9559 statusCode[ code ] = [ statusCode[ code ], map[ code ] ]; 9560 } 9561 } else { 9562 9563 // Execute the appropriate callbacks 9564 jqXHR.always( map[ jqXHR.status ] ); 9565 } 9566 } 9567 return this; 9568 }, 9569 9570 // Cancel the request 9571 abort: function( statusText ) { 9572 var finalText = statusText || strAbort; 9573 if ( transport ) { 9574 transport.abort( finalText ); 9575 } 9576 done( 0, finalText ); 9577 return this; 9578 } 9579 }; 9580 9581 // Attach deferreds 9582 deferred.promise( jqXHR ).complete = completeDeferred.add; 9583 jqXHR.success = jqXHR.done; 9584 jqXHR.error = jqXHR.fail; 9585 9586 // Remove hash character (#7531: and string promotion) 9587 // Add protocol if not provided (#5866: IE7 issue with protocol-less urls) 9588 // Handle falsy url in the settings object (#10093: consistency with old signature) 9589 // We also use the url parameter if available 9590 s.url = ( ( url || s.url || ajaxLocation ) + "" ) 9591 .replace( rhash, "" ) 9592 .replace( rprotocol, ajaxLocParts[ 1 ] + "//" ); 9593 9594 // Alias method option to type as per ticket #12004 9595 s.type = options.method || options.type || s.method || s.type; 9596 9597 // Extract dataTypes list 9598 s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().match( rnotwhite ) || [ "" ]; 9599 9600 // A cross-domain request is in order when we have a protocol:host:port mismatch 9601 if ( s.crossDomain == null ) { 9602 parts = rurl.exec( s.url.toLowerCase() ); 9603 s.crossDomain = !!( parts && 9604 ( parts[ 1 ] !== ajaxLocParts[ 1 ] || parts[ 2 ] !== ajaxLocParts[ 2 ] || 9605 ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? "80" : "443" ) ) !== 9606 ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? "80" : "443" ) ) ) 9607 ); 9608 } 9609 9610 // Convert data if not already a string 9611 if ( s.data && s.processData && typeof s.data !== "string" ) { 9612 s.data = jQuery.param( s.data, s.traditional ); 9613 } 9614 9615 // Apply prefilters 9616 inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); 9617 9618 // If request was aborted inside a prefilter, stop there 9619 if ( state === 2 ) { 9620 return jqXHR; 9621 } 9622 9623 // We can fire global events as of now if asked to 9624 // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118) 9625 fireGlobals = jQuery.event && s.global; 9626 9627 // Watch for a new set of requests 9628 if ( fireGlobals && jQuery.active++ === 0 ) { 9629 jQuery.event.trigger( "ajaxStart" ); 9630 } 9631 9632 // Uppercase the type 9633 s.type = s.type.toUpperCase(); 9634 9635 // Determine if request has content 9636 s.hasContent = !rnoContent.test( s.type ); 9637 9638 // Save the URL in case we're toying with the If-Modified-Since 9639 // and/or If-None-Match header later on 9640 cacheURL = s.url; 9641 9642 // More options handling for requests with no content 9643 if ( !s.hasContent ) { 9644 9645 // If data is available, append data to url 9646 if ( s.data ) {
vendor: 8,244 bytes, lines 9647-9986
9647 cacheURL = ( s.url += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data ); 9648 9649 // #9682: remove data so that it's not used in an eventual retry 9650 delete s.data; 9651 } 9652 9653 // Add anti-cache in url if needed 9654 if ( s.cache === false ) { 9655 s.url = rts.test( cacheURL ) ? 9656 9657 // If there is already a '_' parameter, set its value 9658 cacheURL.replace( rts, "$1_=" + nonce++ ) : 9659 9660 // Otherwise add one to the end 9661 cacheURL + ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + nonce++; 9662 } 9663 } 9664 9665 // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. 9666 if ( s.ifModified ) { 9667 if ( jQuery.lastModified[ cacheURL ] ) { 9668 jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] ); 9669 } 9670 if ( jQuery.etag[ cacheURL ] ) { 9671 jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] ); 9672 } 9673 } 9674 9675 // Set the correct header, if data is being sent 9676 if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { 9677 jqXHR.setRequestHeader( "Content-Type", s.contentType ); 9678 } 9679 9680 // Set the Accepts header for the server, depending on the dataType 9681 jqXHR.setRequestHeader( 9682 "Accept", 9683 s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ? 9684 s.accepts[ s.dataTypes[ 0 ] ] + 9685 ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : 9686 s.accepts[ "*" ] 9687 ); 9688 9689 // Check for headers option 9690 for ( i in s.headers ) { 9691 jqXHR.setRequestHeader( i, s.headers[ i ] ); 9692 } 9693 9694 // Allow custom headers/mimetypes and early abort 9695 if ( s.beforeSend && 9696 ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) { 9697 9698 // Abort if not done already and return 9699 return jqXHR.abort(); 9700 } 9701 9702 // aborting is no longer a cancellation 9703 strAbort = "abort"; 9704 9705 // Install callbacks on deferreds 9706 for ( i in { success: 1, error: 1, complete: 1 } ) { 9707 jqXHR[ i ]( s[ i ] ); 9708 } 9709 9710 // Get transport 9711 transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); 9712 9713 // If no transport, we auto-abort 9714 if ( !transport ) { 9715 done( -1, "No Transport" ); 9716 } else { 9717 jqXHR.readyState = 1; 9718 9719 // Send global event 9720 if ( fireGlobals ) { 9721 globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); 9722 } 9723 9724 // If request was aborted inside ajaxSend, stop there 9725 if ( state === 2 ) { 9726 return jqXHR; 9727 } 9728 9729 // Timeout 9730 if ( s.async && s.timeout > 0 ) { 9731 timeoutTimer = window.setTimeout( function() { 9732 jqXHR.abort( "timeout" ); 9733 }, s.timeout ); 9734 } 9735 9736 try { 9737 state = 1; 9738 transport.send( requestHeaders, done ); 9739 } catch ( e ) { 9740 9741 // Propagate exception as error if not done 9742 if ( state < 2 ) { 9743 done( -1, e ); 9744 9745 // Simply rethrow otherwise 9746 } else { 9747 throw e; 9748 } 9749 } 9750 } 9751 9752 // Callback for when everything is done 9753 function done( status, nativeStatusText, responses, headers ) { 9754 var isSuccess, success, error, response, modified, 9755 statusText = nativeStatusText; 9756 9757 // Called once 9758 if ( state === 2 ) { 9759 return; 9760 } 9761 9762 // State is "done" now 9763 state = 2; 9764 9765 // Clear timeout if it exists 9766 if ( timeoutTimer ) { 9767 window.clearTimeout( timeoutTimer ); 9768 } 9769 9770 // Dereference transport for early garbage collection 9771 // (no matter how long the jqXHR object will be used) 9772 transport = undefined; 9773 9774 // Cache response headers 9775 responseHeadersString = headers || ""; 9776 9777 // Set readyState 9778 jqXHR.readyState = status > 0 ? 4 : 0; 9779 9780 // Determine if successful 9781 isSuccess = status >= 200 && status < 300 || status === 304; 9782 9783 // Get response data 9784 if ( responses ) { 9785 response = ajaxHandleResponses( s, jqXHR, responses ); 9786 } 9787 9788 // Convert no matter what (that way responseXXX fields are always set) 9789 response = ajaxConvert( s, response, jqXHR, isSuccess ); 9790 9791 // If successful, handle type chaining 9792 if ( isSuccess ) { 9793 9794 // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. 9795 if ( s.ifModified ) { 9796 modified = jqXHR.getResponseHeader( "Last-Modified" ); 9797 if ( modified ) { 9798 jQuery.lastModified[ cacheURL ] = modified; 9799 } 9800 modified = jqXHR.getResponseHeader( "etag" ); 9801 if ( modified ) { 9802 jQuery.etag[ cacheURL ] = modified; 9803 } 9804 } 9805 9806 // if no content 9807 if ( status === 204 || s.type === "HEAD" ) { 9808 statusText = "nocontent"; 9809 9810 // if not modified 9811 } else if ( status === 304 ) { 9812 statusText = "notmodified"; 9813 9814 // If we have data, let's convert it 9815 } else { 9816 statusText = response.state; 9817 success = response.data; 9818 error = response.error; 9819 isSuccess = !error; 9820 } 9821 } else { 9822 9823 // We extract error from statusText 9824 // then normalize statusText and status for non-aborts 9825 error = statusText; 9826 if ( status || !statusText ) { 9827 statusText = "error"; 9828 if ( status < 0 ) { 9829 status = 0; 9830 } 9831 } 9832 } 9833 9834 // Set data for the fake xhr object 9835 jqXHR.status = status; 9836 jqXHR.statusText = ( nativeStatusText || statusText ) + ""; 9837 9838 // Success/Error 9839 if ( isSuccess ) { 9840 deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); 9841 } else { 9842 deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); 9843 } 9844 9845 // Status-dependent callbacks 9846 jqXHR.statusCode( statusCode ); 9847 statusCode = undefined; 9848 9849 if ( fireGlobals ) { 9850 globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError", 9851 [ jqXHR, s, isSuccess ? success : error ] ); 9852 } 9853 9854 // Complete 9855 completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); 9856 9857 if ( fireGlobals ) { 9858 globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); 9859 9860 // Handle the global AJAX counter 9861 if ( !( --jQuery.active ) ) { 9862 jQuery.event.trigger( "ajaxStop" ); 9863 } 9864 } 9865 } 9866 9867 return jqXHR; 9868 }, 9869 9870 getJSON: function( url, data, callback ) { 9871 return jQuery.get( url, data, callback, "json" ); 9872 }, 9873 9874 getScript: function( url, callback ) { 9875 return jQuery.get( url, undefined, callback, "script" ); 9876 } 9877} ); 9878 9879jQuery.each( [ "get", "post" ], function( i, method ) { 9880 jQuery[ method ] = function( url, data, callback, type ) { 9881 9882 // shift arguments if data argument was omitted 9883 if ( jQuery.isFunction( data ) ) { 9884 type = type || callback; 9885 callback = data; 9886 data = undefined; 9887 } 9888 9889 // The url can be an options object (which then must have .url) 9890 return jQuery.ajax( jQuery.extend( { 9891 url: url, 9892 type: method, 9893 dataType: type, 9894 data: data, 9895 success: callback 9896 }, jQuery.isPlainObject( url ) && url ) ); 9897 }; 9898} ); 9899 9900 9901jQuery._evalUrl = function( url ) { 9902 return jQuery.ajax( { 9903 url: url, 9904 9905 // Make this explicit, since user can override this through ajaxSetup (#11264) 9906 type: "GET", 9907 dataType: "script", 9908 cache: true, 9909 async: false, 9910 global: false, 9911 "throws": true 9912 } ); 9913}; 9914 9915 9916jQuery.fn.extend( { 9917 wrapAll: function( html ) { 9918 if ( jQuery.isFunction( html ) ) { 9919 return this.each( function( i ) { 9920 jQuery( this ).wrapAll( html.call( this, i ) ); 9921 } ); 9922 } 9923 9924 if ( this[ 0 ] ) { 9925 9926 // The elements to wrap the target around 9927 var wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true ); 9928 9929 if ( this[ 0 ].parentNode ) { 9930 wrap.insertBefore( this[ 0 ] ); 9931 } 9932 9933 wrap.map( function() { 9934 var elem = this; 9935 9936 while ( elem.firstChild && elem.firstChild.nodeType === 1 ) { 9937 elem = elem.firstChild; 9938 } 9939 9940 return elem; 9941 } ).append( this ); 9942 } 9943 9944 return this; 9945 }, 9946 9947 wrapInner: function( html ) { 9948 if ( jQuery.isFunction( html ) ) { 9949 return this.each( function( i ) { 9950 jQuery( this ).wrapInner( html.call( this, i ) ); 9951 } ); 9952 } 9953 9954 return this.each( function() { 9955 var self = jQuery( this ), 9956 contents = self.contents(); 9957 9958 if ( contents.length ) { 9959 contents.wrapAll( html ); 9960 9961 } else { 9962 self.append( html ); 9963 } 9964 } ); 9965 }, 9966 9967 wrap: function( html ) { 9968 var isFunction = jQuery.isFunction( html ); 9969 9970 return this.each( function( i ) { 9971 jQuery( this ).wrapAll( isFunction ? html.call( this, i ) : html ); 9972 } ); 9973 }, 9974 9975 unwrap: function() { 9976 return this.parent().each( function() { 9977 if ( !jQuery.nodeName( this, "body" ) ) { 9978 jQuery( this ).replaceWith( this.childNodes ); 9979 } 9980 } ).end(); 9981 } 9982} ); 9983 9984 9985function getDisplay( elem ) { 9986 return elem.style && elem.style.display || jQuery.css( elem, "dis
9986play" ); 9987} 9988 9989function filterHidden( elem ) { 9990 9991 // Disconnected elements are considered hidden 9992 if ( !jQuery.contains( elem.ownerDocument || document, elem ) ) { 9993 return true; 9994 } 9995 while ( elem && elem.nodeType === 1 ) { 9996 if ( getDisplay( elem ) === "none" || elem.type === "hidden" ) { 9997 return true; 9998 } 9999 elem = elem.parentNode; 10000 } 10001 return false; 10002} 10003 10004jQuery.expr.filters.hidden = function( elem ) { 10005 10006 // Support: Opera <= 12.12 10007 // Opera reports offsetWidths and offsetHeights less than zero on some elements 10008 return support.reliableHiddenOffsets() ? 10009 ( elem.offsetWidth <= 0 && elem.offsetHeight <= 0 && 10010 !elem.getClientRects().length ) : 10011 filterHidden( elem ); 10012}; 10013 10014jQuery.expr.filters.visible = function( elem ) { 10015 return !jQuery.expr.filters.hidden( elem ); 10016}; 10017 10018 10019 10020 10021var r20 = /%20/g, 10022 rbracket = /\[\]$/, 10023 rCRLF = /\r?\n/g, 10024 rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, 10025 rsubmittable = /^(?:input|select|textarea|keygen)/i; 10026 10027function buildParams( prefix, obj, traditional, add ) { 10028 var name; 10029 10030 if ( jQuery.isArray( obj ) ) { 10031 10032 // Serialize array item. 10033 jQuery.each( obj, function( i, v ) { 10034 if ( traditional || rbracket.test( prefix ) ) { 10035 10036 // Treat each array item as a scalar. 10037 add( prefix, v ); 10038 10039 } else { 10040 10041 // Item is non-scalar (array or object), encode its numeric index. 10042 buildParams( 10043 prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]", 10044 v, 10045 traditional, 10046 add 10047 ); 10048 } 10049 } ); 10050 10051 } else if ( !traditional && jQuery.type( obj ) === "object" ) { 10052 10053 // Serialize object item. 10054 for ( name in obj ) { 10055 buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); 10056 } 10057 10058 } else { 10059 10060 // Serialize scalar item. 10061 add( prefix, obj ); 10062 } 10063} 10064 10065// Serialize an array of form elements or a set of 10066// key/values into a query string 10067jQuery.param = function( a, traditional ) { 10068 var prefix, 10069 s = [], 10070 add = function( key, value ) { 10071 10072 // If value is a function, invoke it and return its value 10073 value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value ); 10074 s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value ); 10075 }; 10076 10077 // Set traditional to true for jQuery <= 1.3.2 behavior. 10078 if ( traditional === undefined ) { 10079 traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional; 10080 } 10081 10082 // If an array was passed in, assume that it is an array of form elements. 10083 if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { 10084 10085 // Serialize the form elements 10086 jQuery.each( a, function() { 10087 add( this.name, this.value ); 10088 } ); 10089 10090 } else { 10091 10092 // If traditional, encode the "old" way (the way 1.3.2 or older 10093 // did it), otherwise encode params recursively. 10094 for ( prefix in a ) { 10095 buildParams( prefix, a[ prefix ], traditional, add ); 10096 } 10097 } 10098 10099 // Return the resulting serialization 10100 return s.join( "&" ).replace( r20, "+" ); 10101}; 10102 10103jQuery.fn.extend( { 10104 serialize: function() { 10105 return jQuery.param( this.serializeArray() ); 10106 }, 10107 serializeArray: function() { 10108 return this.map( function() { 10109 10110 // Can add propHook for "elements" to filter or add form elements 10111 var elements = jQuery.prop( this, "elements" ); 10112 return elements ? jQuery.makeArray( elements ) : this; 10113 } ) 10114 .filter( function() { 10115 var type = this.type; 10116 10117 // Use .is(":disabled") so that fieldset[disabled] works 10118 return this.name && !jQuery( this ).is( ":disabled" ) && 10119 rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && 10120 ( this.checked || !rcheckableType.test( type ) ); 10121 } ) 10122 .map( function( i, elem ) { 10123 var val = jQuery( this ).val(); 10124 10125 return val == null ? 10126 null : 10127 jQuery.isArray( val ) ? 10128 jQuery.map( val, function( val ) { 10129 return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; 10130 } ) : 10131 { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; 10132 } ).get(); 10133 } 10134} ); 10135 10136 10137// Create the request object 10138// (This is still attached to ajaxSettings for backward compatibility) 10139jQuery.ajaxSettings.xhr = window.ActiveXObject !== undefined ? 10140 10141 // Support: IE6-IE8 10142 function() { 10143 10144 // XHR cannot access local files, always use ActiveX for that case 10145 if ( this.isLocal ) { 10146 return createActiveXHR(); 10147 } 10148
vendor: 22,565 bytes, lines 10149-10969
10149 // Support: IE 9-11 10150 // IE seems to error on cross-domain PATCH requests when ActiveX XHR 10151 // is used. In IE 9+ always use the native XHR. 10152 // Note: this condition won't catch Edge as it doesn't define 10153 // document.documentMode but it also doesn't support ActiveX so it won't 10154 // reach this code. 10155 if ( document.documentMode > 8 ) { 10156 return createStandardXHR(); 10157 } 10158 10159 // Support: IE<9 10160 // oldIE XHR does not support non-RFC2616 methods (#13240) 10161 // See http://msdn.microsoft.com/en-us/library/ie/ms536648(v=vs.85).aspx 10162 // and http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9 10163 // Although this check for six methods instead of eight 10164 // since IE also does not support "trace" and "connect" 10165 return /^(get|post|head|put|delete|options)$/i.test( this.type ) && 10166 createStandardXHR() || createActiveXHR(); 10167 } : 10168 10169 // For all other browsers, use the standard XMLHttpRequest object 10170 createStandardXHR; 10171 10172var xhrId = 0, 10173 xhrCallbacks = {}, 10174 xhrSupported = jQuery.ajaxSettings.xhr(); 10175 10176// Support: IE<10 10177// Open requests must be manually aborted on unload (#5280) 10178// See https://support.microsoft.com/kb/2856746 for more info 10179if ( window.attachEvent ) { 10180 window.attachEvent( "onunload", function() { 10181 for ( var key in xhrCallbacks ) { 10182 xhrCallbacks[ key ]( undefined, true ); 10183 } 10184 } ); 10185} 10186 10187// Determine support properties 10188support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported ); 10189xhrSupported = support.ajax = !!xhrSupported; 10190 10191// Create transport if the browser can provide an xhr 10192if ( xhrSupported ) { 10193 10194 jQuery.ajaxTransport( function( options ) { 10195 10196 // Cross domain only allowed if supported through XMLHttpRequest 10197 if ( !options.crossDomain || support.cors ) { 10198 10199 var callback; 10200 10201 return { 10202 send: function( headers, complete ) { 10203 var i, 10204 xhr = options.xhr(), 10205 id = ++xhrId; 10206 10207 // Open the socket 10208 xhr.open( 10209 options.type, 10210 options.url, 10211 options.async, 10212 options.username, 10213 options.password 10214 ); 10215 10216 // Apply custom fields if provided 10217 if ( options.xhrFields ) { 10218 for ( i in options.xhrFields ) { 10219 xhr[ i ] = options.xhrFields[ i ]; 10220 } 10221 } 10222 10223 // Override mime type if needed 10224 if ( options.mimeType && xhr.overrideMimeType ) { 10225 xhr.overrideMimeType( options.mimeType ); 10226 } 10227 10228 // X-Requested-With header 10229 // For cross-domain requests, seeing as conditions for a preflight are 10230 // akin to a jigsaw puzzle, we simply never set it to be sure. 10231 // (it can always be set on a per-request basis or even using ajaxSetup) 10232 // For same-domain requests, won't change header if already provided. 10233 if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) { 10234 headers[ "X-Requested-With" ] = "XMLHttpRequest"; 10235 } 10236 10237 // Set headers 10238 for ( i in headers ) { 10239 10240 // Support: IE<9 10241 // IE's ActiveXObject throws a 'Type Mismatch' exception when setting 10242 // request header to a null-value. 10243 // 10244 // To keep consistent with other XHR implementations, cast the value 10245 // to string and ignore `undefined`. 10246 if ( headers[ i ] !== undefined ) { 10247 xhr.setRequestHeader( i, headers[ i ] + "" ); 10248 } 10249 } 10250 10251 // Do send the request 10252 // This may raise an exception which is actually 10253 // handled in jQuery.ajax (so no try/catch here) 10254 xhr.send( ( options.hasContent && options.data ) || null ); 10255 10256 // Listener 10257 callback = function( _, isAbort ) { 10258 var status, statusText, responses; 10259 10260 // Was never called and is aborted or complete 10261 if ( callback && ( isAbort || xhr.readyState === 4 ) ) { 10262 10263 // Clean up 10264 delete xhrCallbacks[ id ]; 10265 callback = undefined; 10266 xhr.onreadystatechange = jQuery.noop; 10267 10268 // Abort manually if needed 10269 if ( isAbort ) { 10270 if ( xhr.readyState !== 4 ) { 10271 xhr.abort(); 10272 } 10273 } else { 10274 responses = {}; 10275 status = xhr.status; 10276 10277 // Support: IE<10 10278 // Accessing binary-data responseText throws an exception 10279 // (#11426) 10280 if ( typeof xhr.responseText === "string" ) { 10281 responses.text = xhr.responseText; 10282 } 10283 10284 // Firefox throws an exception when accessing 10285 // statusText for faulty cross-domain requests 10286 try { 10287 statusText = xhr.statusText; 10288 } catch ( e ) { 10289 10290 // We normalize with Webkit giving an empty statusText 10291 statusText = ""; 10292 } 10293 10294 // Filter status for non standard behaviors 10295 10296 // If the request is local and we have data: assume a success 10297 // (success with no data won't get notified, that's the best we 10298 // can do given current implementations) 10299 if ( !status && options.isLocal && !options.crossDomain ) { 10300 status = responses.text ? 200 : 404; 10301 10302 // IE - #1450: sometimes returns 1223 when it should be 204 10303 } else if ( status === 1223 ) { 10304 status = 204; 10305 } 10306 } 10307 } 10308 10309 // Call complete if needed 10310 if ( responses ) { 10311 complete( status, statusText, responses, xhr.getAllResponseHeaders() ); 10312 } 10313 }; 10314 10315 // Do send the request 10316 // `xhr.send` may raise an exception, but it will be 10317 // handled in jQuery.ajax (so no try/catch here) 10318 if ( !options.async ) { 10319 10320 // If we're in sync mode we fire the callback 10321 callback(); 10322 } else if ( xhr.readyState === 4 ) { 10323 10324 // (IE6 & IE7) if it's in cache and has been 10325 // retrieved directly we need to fire the callback 10326 window.setTimeout( callback ); 10327 } else { 10328 10329 // Register the callback, but delay it in case `xhr.send` throws 10330 // Add to the list of active xhr callbacks 10331 xhr.onreadystatechange = xhrCallbacks[ id ] = callback; 10332 } 10333 }, 10334 10335 abort: function() { 10336 if ( callback ) { 10337 callback( undefined, true ); 10338 } 10339 } 10340 }; 10341 } 10342 } ); 10343} 10344 10345// Functions to create xhrs 10346function createStandardXHR() { 10347 try { 10348 return new window.XMLHttpRequest(); 10349 } catch ( e ) {} 10350} 10351 10352function createActiveXHR() { 10353 try { 10354 return new window.ActiveXObject( "Microsoft.XMLHTTP" ); 10355 } catch ( e ) {} 10356} 10357 10358 10359 10360 10361// Install script dataType 10362jQuery.ajaxSetup( { 10363 accepts: { 10364 script: "text/javascript, application/javascript, " + 10365 "application/ecmascript, application/x-ecmascript" 10366 }, 10367 contents: { 10368 script: /\b(?:java|ecma)script\b/ 10369 }, 10370 converters: { 10371 "text script": function( text ) { 10372 jQuery.globalEval( text ); 10373 return text; 10374 } 10375 } 10376} ); 10377 10378// Handle cache's special case and global 10379jQuery.ajaxPrefilter( "script", function( s ) { 10380 if ( s.cache === undefined ) { 10381 s.cache = false; 10382 } 10383 if ( s.crossDomain ) { 10384 s.type = "GET"; 10385 s.global = false; 10386 } 10387} ); 10388 10389// Bind script tag hack transport 10390jQuery.ajaxTransport( "script", function( s ) { 10391 10392 // This transport only deals with cross domain requests 10393 if ( s.crossDomain ) { 10394 10395 var script, 10396 head = document.head || jQuery( "head" )[ 0 ] || document.documentElement; 10397 10398 return { 10399 10400 send: function( _, callback ) { 10401 10402 script = document.createElement( "script" ); 10403 10404 script.async = true; 10405 10406 if ( s.scriptCharset ) { 10407 script.charset = s.scriptCharset; 10408 } 10409 10410 script.src = s.url; 10411 10412 // Attach handlers for all browsers 10413 script.onload = script.onreadystatechange = function( _, isAbort ) { 10414 10415 if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) { 10416 10417 // Handle memory leak in IE 10418 script.onload = script.onreadystatechange = null; 10419 10420 // Remove the script 10421 if ( script.parentNode ) { 10422 script.parentNode.removeChild( script ); 10423 } 10424 10425 // Dereference the script 10426 script = null; 10427 10428 // Callback if not abort 10429 if ( !isAbort ) { 10430 callback( 200, "success" ); 10431 } 10432 } 10433 }; 10434 10435 // Circumvent IE6 bugs with base elements (#2709 and #4378) by prepending 10436 // Use native DOM manipulation to avoid our domManip AJAX trickery 10437 head.insertBefore( script, head.firstChild ); 10438 }, 10439 10440 abort: function() { 10441 if ( script ) { 10442 script.onload( undefined, true ); 10443 } 10444 } 10445 }; 10446 } 10447} ); 10448 10449 10450 10451 10452var oldCallbacks = [], 10453 rjsonp = /(=)\?(?=&|$)|\?\?/; 10454 10455// Default jsonp settings 10456jQuery.ajaxSetup( { 10457 jsonp: "callback", 10458 jsonpCallback: function() { 10459 var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce++ ) ); 10460 this[ callback ] = true; 10461 return callback; 10462 } 10463} ); 10464 10465// Detect, normalize options and install callbacks for jsonp requests 10466jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) { 10467 10468 var callbackName, overwritten, responseContainer, 10469 jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ? 10470 "url" : 10471 typeof s.data === "string" && 10472 ( s.contentType || "" ) 10473 .indexOf( "application/x-www-form-urlencoded" ) === 0 && 10474 rjsonp.test( s.data ) && "data" 10475 ); 10476 10477 // Handle iff the expected data type is "jsonp" or we have a parameter to set 10478 if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) { 10479 10480 // Get callback name, remembering preexisting value associated with it 10481 callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ? 10482 s.jsonpCallback() : 10483 s.jsonpCallback; 10484 10485 // Insert callback into url or form data 10486 if ( jsonProp ) { 10487 s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + callbackName ); 10488 } else if ( s.jsonp !== false ) { 10489 s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName; 10490 } 10491 10492 // Use data converter to retrieve json after script execution 10493 s.converters[ "script json" ] = function() { 10494 if ( !responseContainer ) { 10495 jQuery.error( callbackName + " was not called" ); 10496 } 10497 return responseContainer[ 0 ]; 10498 }; 10499 10500 // force json dataType 10501 s.dataTypes[ 0 ] = "json"; 10502 10503 // Install callback 10504 overwritten = window[ callbackName ]; 10505 window[ callbackName ] = function() { 10506 responseContainer = arguments; 10507 }; 10508 10509 // Clean-up function (fires after converters) 10510 jqXHR.always( function() { 10511 10512 // If previous value didn't exist - remove it 10513 if ( overwritten === undefined ) { 10514 jQuery( window ).removeProp( callbackName ); 10515 10516 // Otherwise restore preexisting value 10517 } else { 10518 window[ callbackName ] = overwritten; 10519 } 10520 10521 // Save back as free 10522 if ( s[ callbackName ] ) { 10523 10524 // make sure that re-using the options doesn't screw things around 10525 s.jsonpCallback = originalSettings.jsonpCallback; 10526 10527 // save the callback name for future use 10528 oldCallbacks.push( callbackName ); 10529 } 10530 10531 // Call if it was a function and we have a response 10532 if ( responseContainer && jQuery.isFunction( overwritten ) ) { 10533 overwritten( responseContainer[ 0 ] ); 10534 } 10535 10536 responseContainer = overwritten = undefined; 10537 } ); 10538 10539 // Delegate to script 10540 return "script"; 10541 } 10542} ); 10543 10544 10545 10546 10547// data: string of html 10548// context (optional): If specified, the fragment will be created in this context, 10549// defaults to document 10550// keepScripts (optional): If true, will include scripts passed in the html string 10551jQuery.parseHTML = function( data, context, keepScripts ) { 10552 if ( !data || typeof data !== "string" ) { 10553 return null; 10554 } 10555 if ( typeof context === "boolean" ) { 10556 keepScripts = context; 10557 context = false; 10558 } 10559 context = context || document; 10560 10561 var parsed = rsingleTag.exec( data ), 10562 scripts = !keepScripts && []; 10563 10564 // Single tag 10565 if ( parsed ) { 10566 return [ context.createElement( parsed[ 1 ] ) ]; 10567 } 10568 10569 parsed = buildFragment( [ data ], context, scripts ); 10570 10571 if ( scripts && scripts.length ) { 10572 jQuery( scripts ).remove(); 10573 } 10574 10575 return jQuery.merge( [], parsed.childNodes ); 10576}; 10577 10578 10579// Keep a copy of the old load method 10580var _load = jQuery.fn.load; 10581 10582/** 10583 * Load a url into a page 10584 */ 10585jQuery.fn.load = function( url, params, callback ) { 10586 if ( typeof url !== "string" && _load ) { 10587 return _load.apply( this, arguments ); 10588 } 10589 10590 var selector, type, response, 10591 self = this, 10592 off = url.indexOf( " " ); 10593 10594 if ( off > -1 ) { 10595 selector = jQuery.trim( url.slice( off, url.length ) ); 10596 url = url.slice( 0, off ); 10597 } 10598 10599 // If it's a function 10600 if ( jQuery.isFunction( params ) ) { 10601 10602 // We assume that it's the callback 10603 callback = params; 10604 params = undefined; 10605 10606 // Otherwise, build a param string 10607 } else if ( params && typeof params === "object" ) { 10608 type = "POST"; 10609 } 10610 10611 // If we have elements to modify, make the request 10612 if ( self.length > 0 ) { 10613 jQuery.ajax( { 10614 url: url, 10615 10616 // If "type" variable is undefined, then "GET" method will be used. 10617 // Make value of this field explicit since 10618 // user can override it through ajaxSetup method 10619 type: type || "GET", 10620 dataType: "html", 10621 data: params 10622 } ).done( function( responseText ) { 10623 10624 // Save response for use in complete callback 10625 response = arguments; 10626 10627 self.html( selector ? 10628 10629 // If a selector was specified, locate the right elements in a dummy div 10630 // Exclude scripts to avoid IE 'Permission Denied' errors 10631 jQuery( "<div>" ).append( jQuery.parseHTML( responseText ) ).find( selector ) : 10632 10633 // Otherwise use the full result 10634 responseText ); 10635 10636 // If the request succeeds, this function gets "data", "status", "jqXHR" 10637 // but they are ignored because response was set above. 10638 // If it fails, this function gets "jqXHR", "status", "error" 10639 } ).always( callback && function( jqXHR, status ) { 10640 self.each( function() { 10641 callback.apply( this, response || [ jqXHR.responseText, status, jqXHR ] ); 10642 } ); 10643 } ); 10644 } 10645 10646 return this; 10647}; 10648 10649 10650 10651 10652// Attach a bunch of functions for handling common AJAX events 10653jQuery.each( [ 10654 "ajaxStart", 10655 "ajaxStop", 10656 "ajaxComplete", 10657 "ajaxError", 10658 "ajaxSuccess", 10659 "ajaxSend" 10660], function( i, type ) { 10661 jQuery.fn[ type ] = function( fn ) { 10662 return this.on( type, fn ); 10663 }; 10664} ); 10665 10666 10667 10668 10669jQuery.expr.filters.animated = function( elem ) { 10670 return jQuery.grep( jQuery.timers, function( fn ) { 10671 return elem === fn.elem; 10672 } ).length; 10673}; 10674 10675 10676 10677 10678 10679/** 10680 * Gets a window from an element 10681 */ 10682function getWindow( elem ) { 10683 return jQuery.isWindow( elem ) ? 10684 elem : 10685 elem.nodeType === 9 ? 10686 elem.defaultView || elem.parentWindow : 10687 false; 10688} 10689 10690jQuery.offset = { 10691 setOffset: function( elem, options, i ) { 10692 var curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition, 10693 position = jQuery.css( elem, "position" ), 10694 curElem = jQuery( elem ), 10695 props = {}; 10696 10697 // set position first, in-case top/left are set even on static elem 10698 if ( position === "static" ) { 10699 elem.style.position = "relative"; 10700 } 10701 10702 curOffset = curElem.offset(); 10703 curCSSTop = jQuery.css( elem, "top" ); 10704 curCSSLeft = jQuery.css( elem, "left" ); 10705 calculatePosition = ( position === "absolute" || position === "fixed" ) && 10706 jQuery.inArray( "auto", [ curCSSTop, curCSSLeft ] ) > -1; 10707 10708 // need to be able to calculate position if either top or left 10709 // is auto and position is either absolute or fixed 10710 if ( calculatePosition ) { 10711 curPosition = curElem.position(); 10712 curTop = curPosition.top; 10713 curLeft = curPosition.left; 10714 } else { 10715 curTop = parseFloat( curCSSTop ) || 0; 10716 curLeft = parseFloat( curCSSLeft ) || 0; 10717 } 10718 10719 if ( jQuery.isFunction( options ) ) { 10720 10721 // Use jQuery.extend here to allow modification of coordinates argument (gh-1848) 10722 options = options.call( elem, i, jQuery.extend( {}, curOffset ) ); 10723 } 10724 10725 if ( options.top != null ) { 10726 props.top = ( options.top - curOffset.top ) + curTop; 10727 } 10728 if ( options.left != null ) { 10729 props.left = ( options.left - curOffset.left ) + curLeft; 10730 } 10731 10732 if ( "using" in options ) { 10733 options.using.call( elem, props ); 10734 } else { 10735 curElem.css( props ); 10736 } 10737 } 10738}; 10739 10740jQuery.fn.extend( { 10741 offset: function( options ) { 10742 if ( arguments.length ) { 10743 return options === undefined ? 10744 this : 10745 this.each( function( i ) { 10746 jQuery.offset.setOffset( this, options, i ); 10747 } ); 10748 } 10749 10750 var docElem, win, 10751 box = { top: 0, left: 0 }, 10752 elem = this[ 0 ], 10753 doc = elem && elem.ownerDocument; 10754 10755 if ( !doc ) { 10756 return; 10757 } 10758 10759 docElem = doc.documentElement; 10760 10761 // Make sure it's not a disconnected DOM node 10762 if ( !jQuery.contains( docElem, elem ) ) { 10763 return box; 10764 } 10765 10766 // If we don't have gBCR, just use 0,0 rather than error 10767 // BlackBerry 5, iOS 3 (original iPhone) 10768 if ( typeof elem.getBoundingClientRect !== "undefined" ) { 10769 box = elem.getBoundingClientRect(); 10770 } 10771 win = getWindow( doc ); 10772 return { 10773 top: box.top + ( win.pageYOffset || docElem.scrollTop ) - ( docElem.clientTop || 0 ), 10774 left: box.left + ( win.pageXOffset || docElem.scrollLeft ) - ( docElem.clientLeft || 0 ) 10775 }; 10776 }, 10777 10778 position: function() { 10779 if ( !this[ 0 ] ) { 10780 return; 10781 } 10782 10783 var offsetParent, offset, 10784 parentOffset = { top: 0, left: 0 }, 10785 elem = this[ 0 ]; 10786 10787 // Fixed elements are offset from window (parentOffset = {top:0, left: 0}, 10788 // because it is its only offset parent 10789 if ( jQuery.css( elem, "position" ) === "fixed" ) { 10790 10791 // we assume that getBoundingClientRect is available when computed position is fixed 10792 offset = elem.getBoundingClientRect(); 10793 } else { 10794 10795 // Get *real* offsetParent 10796 offsetParent = this.offsetParent(); 10797 10798 // Get correct offsets 10799 offset = this.offset(); 10800 if ( !jQuery.nodeName( offsetParent[ 0 ], "html" ) ) { 10801 parentOffset = offsetParent.offset(); 10802 } 10803 10804 // Add offsetParent borders 10805 parentOffset.top += jQuery.css( offsetParent[ 0 ], "borderTopWidth", true ); 10806 parentOffset.left += jQuery.css( offsetParent[ 0 ], "borderLeftWidth", true ); 10807 } 10808 10809 // Subtract parent offsets and element margins 10810 // note: when an element has margin: auto the offsetLeft and marginLeft 10811 // are the same in Safari causing offset.left to incorrectly be 0 10812 return { 10813 top: offset.top - parentOffset.top - jQuery.css( elem, "marginTop", true ), 10814 left: offset.left - parentOffset.left - jQuery.css( elem, "marginLeft", true ) 10815 }; 10816 }, 10817 10818 offsetParent: function() { 10819 return this.map( function() { 10820 var offsetParent = this.offsetParent; 10821 10822 while ( offsetParent && ( !jQuery.nodeName( offsetParent, "html" ) && 10823 jQuery.css( offsetParent, "position" ) === "static" ) ) { 10824 offsetParent = offsetParent.offsetParent; 10825 } 10826 return offsetParent || documentElement; 10827 } ); 10828 } 10829} ); 10830 10831// Create scrollLeft and scrollTop methods 10832jQuery.each( { scrollLeft: "pageXOffset", scrollTop: "pageYOffset" }, function( method, prop ) { 10833 var top = /Y/.test( prop ); 10834 10835 jQuery.fn[ method ] = function( val ) { 10836 return access( this, function( elem, method, val ) { 10837 var win = getWindow( elem ); 10838 10839 if ( val === undefined ) { 10840 return win ? ( prop in win ) ? win[ prop ] : 10841 win.document.documentElement[ method ] : 10842 elem[ method ]; 10843 } 10844 10845 if ( win ) { 10846 win.scrollTo( 10847 !top ? val : jQuery( win ).scrollLeft(), 10848 top ? val : jQuery( win ).scrollTop() 10849 ); 10850 10851 } else { 10852 elem[ method ] = val; 10853 } 10854 }, method, val, arguments.length, null ); 10855 }; 10856} ); 10857 10858// Support: Safari<7-8+, Chrome<37-44+ 10859// Add the top/left cssHooks using jQuery.fn.position 10860// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084 10861// getComputedStyle returns percent when specified for top/left/bottom/right 10862// rather than make the css module depend on the offset module, we just check for it here 10863jQuery.each( [ "top", "left" ], function( i, prop ) { 10864 jQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition, 10865 function( elem, computed ) { 10866 if ( computed ) { 10867 computed = curCSS( elem, prop ); 10868 10869 // if curCSS returns percentage, fallback to offset 10870 return rnumnonpx.test( computed ) ? 10871 jQuery( elem ).position()[ prop ] + "px" : 10872 computed; 10873 } 10874 } 10875 ); 10876} ); 10877 10878 10879// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods 10880jQuery.each( { Height: "height", Width: "width" }, function( name, type ) { 10881 jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, 10882 function( defaultExtra, funcName ) { 10883 10884 // margin is only for outerHeight, outerWidth 10885 jQuery.fn[ funcName ] = function( margin, value ) { 10886 var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ), 10887 extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" ); 10888 10889 return access( this, function( elem, type, value ) { 10890 var doc; 10891 10892 if ( jQuery.isWindow( elem ) ) { 10893 10894 // As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there 10895 // isn't a whole lot we can do. See pull request at this URL for discussion: 10896 // https://github.com/jquery/jquery/pull/764 10897 return elem.document.documentElement[ "client" + name ]; 10898 } 10899 10900 // Get document width or height 10901 if ( elem.nodeType === 9 ) { 10902 doc = elem.documentElement; 10903 10904 // Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height], 10905 // whichever is greatest 10906 // unfortunately, this causes bug #3838 in IE6/8 only, 10907 // but there is currently no good, small way to fix it. 10908 return Math.max( 10909 elem.body[ "scroll" + name ], doc[ "scroll" + name ], 10910 elem.body[ "offset" + name ], doc[ "offset" + name ], 10911 doc[ "client" + name ] 10912 ); 10913 } 10914 10915 return value === undefined ? 10916 10917 // Get width or height on the element, requesting but not forcing parseFloat 10918 jQuery.css( elem, type, extra ) : 10919 10920 // Set width or height on the element 10921 jQuery.style( elem, type, value, extra ); 10922 }, type, chainable ? margin : undefined, chainable, null ); 10923 }; 10924 } ); 10925} ); 10926 10927 10928jQuery.fn.extend( { 10929 10930 bind: function( types, data, fn ) { 10931 return this.on( types, null, data, fn ); 10932 }, 10933 unbind: function( types, fn ) { 10934 return this.off( types, null, fn ); 10935 }, 10936 10937 delegate: function( selector, types, data, fn ) { 10938 return this.on( types, selector, data, fn ); 10939 }, 10940 undelegate: function( selector, types, fn ) { 10941 10942 // ( namespace ) or ( selector, types [, fn] ) 10943 return arguments.length === 1 ? 10944 this.off( selector, "**" ) : 10945 this.off( types, selector || "**", fn ); 10946 } 10947} ); 10948 10949// The number of elements contained in the matched element set 10950jQuery.fn.size = function() { 10951 return this.length; 10952}; 10953 10954jQuery.fn.andSelf = jQuery.fn.addBack; 10955 10956 10957 10958 10959// Register as a named AMD module, since jQuery can be concatenated with other 10960// files that may use define, but not via a proper concatenation script that 10961// understands anonymous AMD modules. A named AMD is safest and most robust 10962// way to register. Lowercase jquery is used because AMD module names are 10963// derived from file names, and jQuery is normally delivered in a lowercase 10964// file name. Do this after creating the global so that if an AMD module wants 10965// to call noConflict to hide this version of jQuery, it will work. 10966 10967// Note that for maximum portability, libraries that are not jQuery should 10968// declare themselves as anonymous modules, and avoid setting a global if an 10969// AMD loader is present. jQuery is a special case. For more information, see
10970// https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon 10971 10972if ( typeof define === "function" && define.amd ) { 10973 define( "jquery", [], function() { 10974 return jQuery; 10975 } ); 10976} 10977 10978 10979 10980var 10981 10982 // Map over jQuery in case of overwrite 10983 _jQuery = window.jQuery, 10984 10985 // Map over the $ in case of overwrite 10986 _$ = window.$; 10987 10988jQuery.noConflict = function( deep ) { 10989 if ( window.$ === jQuery ) { 10990 window.$ = _$; 10991 } 10992 10993 if ( deep && window.jQuery === jQuery ) { 10994 window.jQuery = _jQuery; 10995 } 10996 10997 return jQuery; 10998}; 10999 11000// Expose jQuery and $ identifiers, even in 11001// AMD (#7102#comment:10, https://github.com/jquery/jquery/pull/557) 11002// and CommonJS for browser emulators (#13566) 11003if ( !noGlobal ) { 11004 window.jQuery = window.$ = jQuery; 11005} 11006 11007return jQuery; 11008})); 11009/* jshint node: true */ 11010 11011/** 11012 * Unobtrusive scripting adapter for jQuery 11013 * https://github.com/rails/jquery-ujs 11014 * 11015 * Requires jQuery 1.8.0 or later. 11016 * 11017 * Released under the MIT license 11018 * 11019 */ 11020 11021(function() { 11022 'use strict'; 11023 11024 var jqueryUjsInit = function($, undefined) { 11025 11026 // Cut down on the number of issues from people inadvertently including jquery_ujs twice 11027 // by detecting and raising an error when it happens. 11028 if ( $.rails !== undefined ) { 11029 $.error('jquery-ujs has already been loaded!'); 11030 } 11031 11032 // Shorthand to make it a little easier to call public rails functions from within rails.js 11033 var rails; 11034 var $document = $(document); 11035 11036 $.rails = rails = { 11037 // Link elements bound by jquery-ujs 11038 linkClickSelector: 'a[data-confirm], a[data-method], a[data-remote]:not([disabled]), a[data-disable-with], a[data-disable]', 11039 11040 // Button elements bound by jquery-ujs 11041 buttonClickSelector: 'button[data-remote]:not([form]):not(form button), button[data-confirm]:not([form]):not(form button)', 11042 11043 // Select elements bound by jquery-ujs 11044 inputChangeSelector: 'select[data-remote], input[data-remote], textarea[data-remote]', 11045 11046 // Form elements bound by jquery-ujs 11047 formSubmitSelector: 'form:not([data-turbo=true])', 11048 11049 // Form input elements bound by jquery-ujs 11050 formInputClickSelector: 'form:not([data-turbo=true]) input[type=submit], form:not([data-turbo=true]) input[type=image], form:not([data-turbo=true]) button[type=submit], form:not([data-turbo=true]) button:not([type]), input[type=submit][form], input[type=image][form], button[type=submit][form], button[form]:not([type])', 11051 11052 // Form input elements disabled during form submission 11053 disableSelector: 'input[data-disable-with]:enabled, button[data-disable-with]:enabled, textarea[data-disable-with]:enabled, input[data-disable]:enabled, button[data-disable]:enabled, textarea[data-disable]:enabled', 11054 11055 // Form input elements re-enabled after form submission 11056 enableSelector: 'input[data-disable-with]:disabled, button[data-disable-with]:disabled, textarea[data-disable-with]:disabled, input[data-disable]:disabled, button[data-disable]:disabled, textarea[data-disable]:disabled', 11057 11058 // Form required input elements 11059 requiredInputSelector: 'input[name][required]:not([disabled]), textarea[name][required]:not([disabled])', 11060 11061 // Form file input elements 11062 fileInputSelector: 'input[name][type=file]:not([disabled])', 11063 11064 // Link onClick disable selector with possible reenable after remote submission 11065 linkDisableSelector: 'a[data-disable-with], a[data-disable]', 11066 11067 // Button onClick disable selector with possible reenable after remote submission 11068 buttonDisableSelector: 'button[data-remote][data-disable-with], button[data-remote][data-disable]', 11069 11070 // Up-to-date Cross-Site Request Forgery token 11071 csrfToken: function() { 11072 return $('meta[name=csrf-token]').attr('content'); 11073 }, 11074 11075 // URL param that must contain the CSRF token 11076 csrfParam: function() { 11077 return $('meta[name=csrf-param]').attr('content'); 11078 }, 11079 11080 // Make sure that every Ajax request sends the CSRF token 11081 CSRFProtection: function(xhr) { 11082 var token = rails.csrfToken(); 11083 if (token) xhr.setRequestHeader('X-CSRF-Token', token); 11084 }, 11085 11086 // Make sure that all forms have actual up-to-date tokens (cached forms contain old ones) 11087 refreshCSRFTokens: function(){ 11088 $('form input[name="' + rails.csrfParam() + '"]').val(rails.csrfToken()); 11089 }, 11090 11091 // Triggers an event on an element and returns false if the event result is false 11092 fire: function(obj, name, data) { 11093 var event = $.Event(name); 11094 obj.trigger(event, data); 11095 return event.result !== false; 11096 }, 11097 11098 // Default confirm dialog, may be overridden with custom confirm dialog in $.rails.confirm 11099 confirm: function(message) { 11100 return confirm(message); 11101 }, 11102 11103 // Default ajax function, may be overridden with custom function in $.rails.ajax 11104 ajax: function(options) { 11105 return $.ajax(options); 11106 }, 11107 11108 // Default way to get an element's href. May be overridden at $.rails.href. 11109 href: function(element) { 11110 return element[0].href; 11111 }, 11112 11113 // Checks "data-remote" if true to handle the request through a XHR request. 11114 isRemote: function(element) { 11115 return element.data('remote') !== undefined && element.data('remote') !== false; 11116 }, 11117 11118 // Submits "remote" forms and links with ajax 11119 handleRemote: function(element) { 11120 var method, url, data, withCredentials, dataType, options; 11121 11122 if (rails.fire(element, 'ajax:before')) { 11123 withCredentials = element.data('with-credentials') || null; 11124 dataType = element.data('type') || ($.ajaxSettings && $.ajaxSettings.dataType); 11125 11126 if (element.is('form')) { 11127 method = element.data('ujs:submit-button-formmethod') || element.attr('method'); 11128 url = element.data('ujs:submit-button-formaction') || element.attr('action'); 11129 data = $(element[0]).serializeArray(); 11130 // memoized value from clicked submit button 11131 var button = element.data('ujs:submit-button'); 11132 if (button) { 11133 data.push(button); 11134 element.data('ujs:submit-button', null); 11135 } 11136 element.data('ujs:submit-button-formmethod', null); 11137 element.data('ujs:submit-button-formaction', null); 11138 } else if (element.is(rails.inputChangeSelector)) { 11139 method = element.data('method'); 11140 url = element.data('url'); 11141 data = element.serialize(); 11142 if (element.data('params')) data = data + '&' + element.data('params'); 11143 } else if (element.is(rails.buttonClickSelector)) { 11144 method = element.data('method') || 'get'; 11145 url = element.data('url'); 11146 data = element.serialize(); 11147 if (element.data('params')) data = data + '&' + element.data('params'); 11148 } else { 11149 method = element.data('method'); 11150 url = rails.href(element); 11151 data = element.data('params') || null; 11152 } 11153 11154 options = { 11155 type: method || 'GET', data: data, dataType: dataType, 11156 // stopping the "ajax:beforeSend" event will cancel the ajax request 11157 beforeSend: function(xhr, settings) { 11158 if (settings.dataType === undefined) { 11159 xhr.setRequestHeader('accept', '*/*;q=0.5, ' + settings.accepts.script); 11160 } 11161 if (rails.fire(element, 'ajax:beforeSend', [xhr, settings])) {
11162 element.trigger('ajax:send', xhr); 11163 } else { 11164 return false; 11165 } 11166 }, 11167 success: function(data, status, xhr) { 11168 element.trigger('ajax:success', [data, status, xhr]); 11169 }, 11170 complete: function(xhr, status) { 11171 element.trigger('ajax:complete', [xhr, status]); 11172 }, 11173 error: function(xhr, status, error) { 11174 element.trigger('ajax:error', [xhr, status, error]); 11175 }, 11176 crossDomain: rails.isCrossDomain(url) 11177 }; 11178 11179 // There is no withCredentials for IE6-8 when 11180 // "Enable native XMLHTTP support" is disabled 11181 if (withCredentials) { 11182 options.xhrFields = { 11183 withCredentials: withCredentials 11184 }; 11185 } 11186 11187 // Only pass url to `ajax` options if not blank 11188 if (url) { options.url = url; } 11189 11190 return rails.ajax(options); 11191 } else { 11192 return false; 11193 } 11194 }, 11195 11196 // Determines if the request is a cross domain request. 11197 isCrossDomain: function(url) { 11198 var originAnchor = document.createElement('a'); 11199 originAnchor.href = location.href; 11200 var urlAnchor = document.createElement('a'); 11201 11202 try { 11203 urlAnchor.href = url; 11204 // This is a workaround to a IE bug. 11205 urlAnchor.href = urlAnchor.href; 11206 11207 // If URL protocol is false or is a string containing a single colon 11208 // *and* host are false, assume it is not a cross-domain request 11209 // (should only be the case for IE7 and IE compatibility mode). 11210 // Otherwise, evaluate protocol and host of the URL against the origin 11211 // protocol and host. 11212 return !(((!urlAnchor.protocol || urlAnchor.protocol === ':') && !urlAnchor.host) || 11213 (originAnchor.protocol + '//' + originAnchor.host === 11214 urlAnchor.protocol + '//' + urlAnchor.host)); 11215 } catch (e) { 11216 // If there is an error parsing the URL, assume it is crossDomain. 11217 return true; 11218 } 11219 }, 11220 11221 // Handles "data-method" on links such as: 11222 // <a href="/users/5" data-method="delete" rel="nofollow" data-confirm="Are you sure?">Delete</a> 11223 handleMethod: function(link) { 11224 var href = rails.href(link), 11225 method = link.data('method'), 11226 target = link.attr('target'), 11227 csrfToken = rails.csrfToken(), 11228 csrfParam = rails.csrfParam(), 11229 form = $('<form method="post" action="' + href + '"></form>'), 11230 metadataInput = '<input name="_method" value="' + method + '" type="hidden" />'; 11231 11232 if (csrfParam !== undefined && csrfToken !== undefined && !rails.isCrossDomain(href)) { 11233 metadataInput += '<input name="' + csrfParam + '" value="' + csrfToken + '" type="hidden" />'; 11234 } 11235 11236 if (target) { form.attr('target', target); } 11237 11238 form.hide().append(metadataInput).appendTo('body'); 11239 form.submit(); 11240 }, 11241 11242 // Helper function that returns form elements that match the specified CSS selector 11243 // If form is actually a "form" element this will return associated elements outside the from that have 11244 // the html form attribute set 11245 formElements: function(form, selector) { 11246 return form.is('form') ? $(form[0].elements).filter(selector) : form.find(selector); 11247 }, 11248 11249 /* Disables form elements: 11250 - Caches element value in 'ujs:enable-with' data store 11251 - Replaces element text with value of 'data-disable-with' attribute 11252 - Sets disabled property to true 11253 */ 11254 disableFormElements: function(form) { 11255 rails.formElements(form, rails.disableSelector).each(function() { 11256 rails.disableFormElement($(this)); 11257 }); 11258 }, 11259 11260 disableFormElement: function(element) { 11261 var method, replacement; 11262 11263 method = element.is('button') ? 'html' : 'val'; 11264 replacement = element.data('disable-with'); 11265 11266 if (replacement !== undefined) { 11267 element.data('ujs:enable-with', element[method]()); 11268 element[method](replacement); 11269 } 11270 11271 element.prop('disabled', true); 11272 element.data('ujs:disabled', true); 11273 }, 11274 11275 /* Re-enables disabled form elements: 11276 - Replaces element text with cached value from 'ujs:enable-with' data store (created in `disableFormElements`) 11277 - Sets disabled property to false 11278 */ 11279 enableFormElements: function(form) { 11280 rails.formElements(form, rails.enableSelector).each(function() { 11281 rails.enableFormElement($(this)); 11282 }); 11283 }, 11284 11285 enableFormElement: function(element) { 11286 var method = element.is('button') ? 'html' : 'val'; 11287 if (element.data('ujs:enable-with') !== undefined) { 11288 element[method](element.data('ujs:enable-with')); 11289 element.removeData('ujs:enable-with'); // clean up cache 11290 } 11291 element.prop('disabled', false); 11292 element.removeData('ujs:disabled'); 11293 }, 11294 11295 /* For 'data-confirm' attribute: 11296 - Fires `confirm` event 11297 - Shows the confirmation dialog 11298 - Fires the `confirm:complete` event 11299 11300 Returns `true` if no function stops the chain and user chose yes; `false` otherwise. 11301 Attaching a handler to the element's `confirm` event that returns a `falsy` value cancels the confirmation dialog. 11302 Attaching a handler to the element's `confirm:complete` event that returns a `falsy` value makes this function
11303 return false. The `confirm:complete` event is fired whether or not the user answered true or false to the dialog. 11304 */ 11305 allowAction: function(element) { 11306 var message = element.data('confirm'), 11307 answer = false, callback; 11308 if (!message) { return true; } 11309 11310 if (rails.fire(element, 'confirm')) { 11311 try { 11312 answer = rails.confirm(message); 11313 } catch (e) { 11314 (console.error || console.log).call(console, e.stack || e); 11315 } 11316 callback = rails.fire(element, 'confirm:complete', [answer]); 11317 } 11318 return answer && callback; 11319 }, 11320 11321 // Helper function which checks for blank inputs in a form that match the specified CSS selector 11322 blankInputs: function(form, specifiedSelector, nonBlank) { 11323 var foundInputs = $(), 11324 input, 11325 valueToCheck, 11326 radiosForNameWithNoneSelected, 11327 radioName, 11328 selector = specifiedSelector || 'input,textarea', 11329 requiredInputs = form.find(selector), 11330 checkedRadioButtonNames = {}; 11331 11332 requiredInputs.each(function() { 11333 input = $(this); 11334 if (input.is('input[type=radio]')) { 11335 11336 // Don't count unchecked required radio as blank if other radio with same name is checked, 11337 // regardless of whether same-name radio input has required attribute or not. The spec 11338 // states https://www.w3.org/TR/html5/forms.html#the-required-attribute 11339 radioName = input.attr('name'); 11340 11341 // Skip if we've already seen the radio with this name. 11342 if (!checkedRadioButtonNames[radioName]) { 11343 11344 // If none checked 11345 if (form.find('input[type=radio]:checked[name="' + radioName + '"]').length === 0) { 11346 radiosForNameWithNoneSelected = form.find( 11347 'input[type=radio][name="' + radioName + '"]'); 11348 foundInputs = foundInputs.add(radiosForNameWithNoneSelected); 11349 } 11350 11351 // We only need to check each name once. 11352 checkedRadioButtonNames[radioName] = radioName; 11353 } 11354 } else { 11355 valueToCheck = input.is('input[type=checkbox],input[type=radio]') ? input.is(':checked') : !!input.val(); 11356 if (valueToCheck === nonBlank) { 11357 foundInputs = foundInputs.add(input); 11358 } 11359 } 11360 }); 11361 return foundInputs.length ? foundInputs : false; 11362 }, 11363 11364 // Helper function which checks for non-blank inputs in a form that match the specified CSS selector 11365 nonBlankInputs: function(form, specifiedSelector) { 11366 return rails.blankInputs(form, specifiedSelector, true); // true specifies nonBlank 11367 }, 11368 11369 // Helper function, needed to provide consistent behavior in IE 11370 stopEverything: function(e) { 11371 $(e.target).trigger('ujs:everythingStopped'); 11372 e.stopImmediatePropagation(); 11373 return false; 11374 }, 11375 11376 // Replace element's html with the 'data-disable-with' after storing original html 11377 // and prevent clicking on it 11378 disableElement: function(element) { 11379 var replacement = element.data('disable-with'); 11380 11381 if (replacement !== undefined) { 11382 element.data('ujs:enable-with', element.html()); // store enabled state 11383 element.html(replacement); 11384 } 11385 11386 element.on('click.railsDisable', function(e) { // prevent further clicking 11387 return rails.stopEverything(e); 11388 }); 11389 element.data('ujs:disabled', true); 11390 }, 11391 11392 // Restore element to its original state which was disabled by 'disableElement' above 11393 enableElement: function(element) { 11394 if (element.data('ujs:enable-with') !== undefined) { 11395 element.html(element.data('ujs:enable-with')); // set to old enabled state 11396 element.removeData('ujs:enable-with'); // clean up cache 11397 } 11398 element.off('click.railsDisable'); // enable element 11399 element.removeData('ujs:disabled'); 11400 } 11401 }; 11402 11403 if (rails.fire($document, 'rails:attachBindings')) { 11404 11405 $.ajaxPrefilter(function(options, originalOptions, xhr){ if ( !options.crossDomain ) { rails.CSRFProtection(xhr); }}); 11406 11407 // This event works the same as the load event, except that it fires every 11408 // time the page is loaded. 11409 // 11410 // See https://github.com/rails/jquery-ujs/issues/357 11411 // See https://developer.mozilla.org/en-US/docs/Using_Firefox_1.5_caching 11412 $(window).on('pageshow.rails', function () { 11413 $($.rails.enableSelector).each(function () { 11414 var element = $(this); 11415 11416 if (element.data('ujs:disabled')) { 11417 $.rails.enableFormElement(element); 11418 } 11419 }); 11420 11421 $($.rails.linkDisableSelector).each(function () { 11422 var element = $(this); 11423 11424 if (element.data('ujs:disabled')) { 11425 $.rails.enableElement(element); 11426 } 11427 }); 11428 }); 11429 11430 $document.on('ajax:complete', rails.linkDisableSelector, function() { 11431 rails.enableElement($(this)); 11432 }); 11433 11434 $document.on('ajax:complete', rails.buttonDisableSelector, function() { 11435 rails.enableFormElement($(this)); 11436 }); 11437 11438 $document.on('click.rails', rails.linkClickSelector, function(e) { 11439 var link = $(this), method = link.data('method'), data = link.data('params'), metaClick = e.metaKey || e.ctrlKey; 11440 if (!rails.allowAction(link)) return rails.stopEverything(e); 11441 11442 if (!metaClick && link.is(rails.linkDisableSelector)) rails.disableElement(link); 11443 11444 if (rails.isRemote(link)) { 11445 if (metaClick && (!method || method === 'GET') && !data) { return true; } 11446 11447 var handleRemote = rails.handleRemote(link); 11448 // Response from rails.handleRemote() will either be false or a deferred object promise. 11449 if (handleRemote === false) { 11450 rails.enableElement(link); 11451 } else { 11452 handleRemote.fail( function() { rails.enableElement(link); } ); 11453 } 11454 return false;
11455 11456 } else if (method) { 11457 rails.handleMethod(link); 11458 return false; 11459 } 11460 }); 11461 11462 $document.on('click.rails', rails.buttonClickSelector, function(e) { 11463 var button = $(this); 11464 11465 if (!rails.allowAction(button) || !rails.isRemote(button)) return rails.stopEverything(e); 11466 11467 if (button.is(rails.buttonDisableSelector)) rails.disableFormElement(button); 11468 11469 var handleRemote = rails.handleRemote(button); 11470 // Response from rails.handleRemote() will either be false or a deferred object promise. 11471 if (handleRemote === false) { 11472 rails.enableFormElement(button); 11473 } else { 11474 handleRemote.fail( function() { rails.enableFormElement(button); } ); 11475 } 11476 return false; 11477 }); 11478 11479 $document.on('change.rails', rails.inputChangeSelector, function(e) { 11480 var link = $(this); 11481 if (!rails.allowAction(link) || !rails.isRemote(link)) return rails.stopEverything(e); 11482 11483 rails.handleRemote(link); 11484 return false; 11485 }); 11486 11487 $document.on('submit.rails', rails.formSubmitSelector, function(e) { 11488 var form = $(this), 11489 remote = rails.isRemote(form), 11490 blankRequiredInputs, 11491 nonBlankFileInputs; 11492 11493 if (!rails.allowAction(form)) return rails.stopEverything(e); 11494 11495 // Skip other logic when required values are missing or file upload is present 11496 if (form.attr('novalidate') === undefined) { 11497 if (form.data('ujs:formnovalidate-button') === undefined) { 11498 blankRequiredInputs = rails.blankInputs(form, rails.requiredInputSelector, false); 11499 if (blankRequiredInputs && rails.fire(form, 'ajax:aborted:required', [blankRequiredInputs])) { 11500 return rails.stopEverything(e); 11501 } 11502 } else { 11503 // Clear the formnovalidate in case the next button click is not on a formnovalidate button 11504 // Not strictly necessary to do here, since it is also reset on each button click, but just to be certain 11505 form.data('ujs:formnovalidate-button', undefined); 11506 } 11507 } 11508 11509 if (remote) { 11510 nonBlankFileInputs = rails.nonBlankInputs(form, rails.fileInputSelector); 11511 if (nonBlankFileInputs) { 11512 // Slight timeout so that the submit button gets properly serialized 11513 // (make it easy for event handler to serialize form without disabled values) 11514 setTimeout(function(){ rails.disableFormElements(form); }, 13); 11515 var aborted = rails.fire(form, 'ajax:aborted:file', [nonBlankFileInputs]); 11516 11517 // Re-enable form elements if event bindings return false (canceling normal form submission) 11518 if (!aborted) { setTimeout(function(){ rails.enableFormElements(form); }, 13); } 11519 11520 return aborted; 11521 } 11522 11523 rails.handleRemote(form); 11524 return false; 11525 11526 } else { 11527 // Slight timeout so that the submit button gets properly serialized 11528 setTimeout(function(){ rails.disableFormElements(form); }, 13); 11529 } 11530 }); 11531 11532 $document.on('click.rails', rails.formInputClickSelector, function(event) { 11533 var button = $(this); 11534 11535 if (!rails.allowAction(button)) return rails.stopEverything(event); 11536 11537 // Register the pressed submit button 11538 var name = button.attr('name'), 11539 data = name ? {name:name, value:button.val()} : null; 11540 11541 var form = button.closest('form'); 11542 if (form.length === 0) { 11543 form = $('#' + button.attr('form')); 11544 } 11545 form.data('ujs:submit-button', data); 11546 11547 // Save attributes from button 11548 form.data('ujs:formnovalidate-button', button.attr('formnovalidate')); 11549 form.data('ujs:submit-button-formaction', button.attr('formaction')); 11550 form.data('ujs:submit-button-formmethod', button.attr('formmethod')); 11551 }); 11552 11553 $document.on('ajax:send.rails', rails.formSubmitSelector, function(event) { 11554 if (this === event.target) rails.disableFormElements($(this)); 11555 }); 11556 11557 $document.on('ajax:complete.rails', rails.formSubmitSelector, function(event) { 11558 if (this === event.target) rails.enableFormElements($(this)); 11559 }); 11560 11561 $(function(){ 11562 rails.refreshCSRFTokens(); 11563 }); 11564 } 11565 11566 }; 11567 11568 if (window.jQuery) { 11569 jqueryUjsInit(jQuery); 11570 } else if (typeof exports === 'object' && typeof module === 'object') { 11571 module.exports = jqueryUjsInit; 11572 } 11573})(); 11574"use strict"; 11575 11576function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } 11577 11578function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); } 11579
11580function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } 11581 11582function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } 11583 11584function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); } 11585 11586function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } 11587 11588function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 11589 11590function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } 11591 11592function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } 11593 11594/* 11595 * 11596 * More info at [www.dropzonejs.com](http://www.dropzonejs.com) 11597 * 11598 * Copyright (c) 2012, Matias Meno 11599 * 11600 * Permission is hereby granted, free of charge, to any person obtaining a copy 11601 * of this software and associated documentation files (the "Software"), to deal 11602 * in the Software without restriction, including without limitation the rights 11603 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11604 * copies of the Software, and to permit persons to whom the Software is 11605 * furnished to do so, subject to the following conditions: 11606 * 11607 * The above copyright notice and this permission notice shall be included in 11608 * all copies or substantial portions of the Software. 11609 * 11610 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 11611 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 11612 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 11613 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 11614 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 11615 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 11616 * THE SOFTWARE. 11617 * 11618 */ 11619// The Emitter class provides the ability to call `.on()` on Dropzone to listen 11620// to events. 11621// It is strongly based on component's emitter class, and I removed the 11622// functionality because of the dependency hell with different frameworks. 11623var Emitter = 11624/*#__PURE__*/ 11625function () { 11626 function Emitter() { 11627 _classCallCheck(this, Emitter); 11628 } 11629 11630 _createClass(Emitter, [{ 11631 key: "on", 11632 // Add an event listener for given event 11633 value: function on(event, fn) { 11634 this._callbacks = this._callbacks || {}; // Create namespace for this event 11635 11636 if (!this._callbacks[event]) { 11637 this._callbacks[event] = []; 11638 } 11639 11640 this._callbacks[event].push(fn); 11641 11642 return this; 11643 } 11644 }, { 11645 key: "emit", 11646 value: function emit(event) { 11647 this._callbacks = this._callbacks || {}; 11648 var callbacks = this._callbacks[event]; 11649 11650 if (callbacks) { 11651 for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { 11652 args[_key - 1] = arguments[_key]; 11653 } 11654 11655 var _iteratorNormalCompletion = true; 11656 var _didIteratorError = false; 11657 var _iteratorError = undefined; 11658 11659 try { 11660 for (var _iterator = callbacks[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { 11661 var callback = _step.value; 11662 callback.apply(this, args); 11663 } 11664 } catch (err) {
11665 _didIteratorError = true; 11666 _iteratorError = err; 11667 } finally { 11668 try { 11669 if (!_iteratorNormalCompletion && _iterator["return"] != null) { 11670 _iterator["return"](); 11671 } 11672 } finally { 11673 if (_didIteratorError) { 11674 throw _iteratorError; 11675 } 11676 } 11677 } 11678 } 11679 11680 return this; 11681 } // Remove event listener for given event. If fn is not provided, all event 11682 // listeners for that event will be removed. If neither is provided, all 11683 // event listeners will be removed. 11684 11685 }, { 11686 key: "off", 11687 value: function off(event, fn) { 11688 if (!this._callbacks || arguments.length === 0) { 11689 this._callbacks = {}; 11690 return this; 11691 } // specific event 11692 11693 11694 var callbacks = this._callbacks[event]; 11695 11696 if (!callbacks) { 11697 return this; 11698 } // remove all handlers 11699 11700 11701 if (arguments.length === 1) { 11702 delete this._callbacks[event]; 11703 return this; 11704 } // remove specific handler 11705 11706 11707 for (var i = 0; i < callbacks.length; i++) { 11708 var callback = callbacks[i]; 11709 11710 if (callback === fn) { 11711 callbacks.splice(i, 1); 11712 break; 11713 } 11714 } 11715 11716 return this; 11717 } 11718 }]); 11719 11720 return Emitter; 11721}(); 11722 11723var Dropzone = 11724/*#__PURE__*/ 11725function (_Emitter) { 11726 _inherits(Dropzone, _Emitter); 11727 11728 _createClass(Dropzone, null, [{ 11729 key: "initClass", 11730 value: function initClass() { 11731 // Exposing the emitter class, mainly for tests 11732 this.prototype.Emitter = Emitter; 11733 /* 11734 This is a list of all available events you can register on a dropzone object. 11735 You can register an event handler like this: 11736 dropzone.on("dragEnter", function() { }); 11737 */ 11738 11739 this.prototype.events = ["drop", "dragstart", "dragend", "dragenter", "dragover", "dragleave", "addedfile", "addedfiles", "removedfile", "thumbnail", "error", "errormultiple", "processing", "processingmultiple", "uploadprogress", "totaluploadprogress", "sending", "sendingmultiple", "success", "successmultiple", "canceled", "canceledmultiple", "complete", "completemultiple", "reset", "maxfilesexceeded", "maxfilesreached", "queuecomplete"]; 11740 this.prototype.defaultOptions = { 11741 /** 11742 * Has to be specified on elements other than form (or when the form 11743 * doesn't have an `action` attribute). You can also 11744 * provide a function that will be called with `files` and 11745 * must return the url (since `v3.12.0`) 11746 */ 11747 url: null, 11748 11749 /** 11750 * Can be changed to `"put"` if necessary. You can also provide a function 11751 * that will be called with `files` and must return the method (since `v3.12.0`). 11752 */ 11753 method: "post", 11754 11755 /** 11756 * Will be set on the XHRequest. 11757 */ 11758 withCredentials: false, 11759 11760 /** 11761 * The timeout for the XHR requests in milliseconds (since `v4.4.0`). 11762 */ 11763 timeout: 30000, 11764 11765 /** 11766 * How many file uploads to process in parallel (See the 11767 * Enqueuing file uploads documentation section for more info) 11768 */ 11769 parallelUploads: 2, 11770 11771 /** 11772 * Whether to send multiple files in one request. If 11773 * this it set to true, then the fallback file input element will 11774 * have the `multiple` attribute as well. This option will 11775 * also trigger additional events (like `processingmultiple`). See the events 11776 * documentation section for more information. 11777 */ 11778 uploadMultiple: false, 11779 11780 /** 11781 * Whether you want files to be uploaded in chunks to your server. This can't be 11782 * used in combination with `uploadMultiple`. 11783 * 11784 * See [chunksUploaded](#config-chunksUploaded) for the callback to finalise an upload. 11785 */ 11786 chunking: false, 11787 11788 /** 11789 * If `chunking` is enabled, this defines whether **every** file should be chunked, 11790 * even if the file size is below chunkSize. This means, that the additional chunk 11791 * form data will be submitted and the `chunksUploaded` callback will be invoked. 11792 */ 11793 forceChunking: false, 11794 11795 /** 11796 * If `chunking` is `true`, then this defines the chunk size in bytes. 11797 */ 11798 chunkSize: 2000000, 11799 11800 /** 11801 * If `true`, the individual chunks of a file are being uploaded simultaneously. 11802 */ 11803 parallelChunkUploads: false, 11804 11805 /** 11806 * Whether a chunk should be retried if it fails. 11807 */
11808 retryChunks: false, 11809 11810 /** 11811 * If `retryChunks` is true, how many times should it be retried. 11812 */ 11813 retryChunksLimit: 3, 11814 11815 /** 11816 * If not `null` defines how many files this Dropzone handles. If it exceeds, 11817 * the event `maxfilesexceeded` will be called. The dropzone element gets the 11818 * class `dz-max-files-reached` accordingly so you can provide visual feedback. 11819 */ 11820 maxFilesize: 256, 11821 11822 /** 11823 * The name of the file param that gets transferred. 11824 * **NOTE**: If you have the option `uploadMultiple` set to `true`, then 11825 * Dropzone will append `[]` to the name. 11826 */ 11827 paramName: "file", 11828 11829 /** 11830 * Whether thumbnails for images should be generated 11831 */ 11832 createImageThumbnails: true, 11833 11834 /** 11835 * In MB. When the filename exceeds this limit, the thumbnail will not be generated. 11836 */ 11837 maxThumbnailFilesize: 10, 11838 11839 /** 11840 * If `null`, the ratio of the image will be used to calculate it. 11841 */ 11842 thumbnailWidth: 120, 11843 11844 /** 11845 * The same as `thumbnailWidth`. If both are null, images will not be resized. 11846 */ 11847 thumbnailHeight: 120, 11848 11849 /** 11850 * How the images should be scaled down in case both, `thumbnailWidth` and `thumbnailHeight` are provided. 11851 * Can be either `contain` or `crop`. 11852 */ 11853 thumbnailMethod: 'crop', 11854 11855 /** 11856 * If set, images will be resized to these dimensions before being **uploaded**. 11857 * If only one, `resizeWidth` **or** `resizeHeight` is provided, the original aspect 11858 * ratio of the file will be preserved. 11859 * 11860 * The `options.transformFile` function uses these options, so if the `transformFile` function 11861 * is overridden, these options don't do anything. 11862 */ 11863 resizeWidth: null, 11864 11865 /** 11866 * See `resizeWidth`. 11867 */ 11868 resizeHeight: null, 11869 11870 /** 11871 * The mime type of the resized image (before it gets uploaded to the server). 11872 * If `null` the original mime type will be used. To force jpeg, for example, use `image/jpeg`. 11873 * See `resizeWidth` for more information. 11874 */ 11875 resizeMimeType: null, 11876 11877 /** 11878 * The quality of the resized images. See `resizeWidth`. 11879 */ 11880 resizeQuality: 0.8, 11881 11882 /** 11883 * How the images should be scaled down in case both, `resizeWidth` and `resizeHeight` are provided. 11884 * Can be either `contain` or `crop`. 11885 */ 11886 resizeMethod: 'contain', 11887 11888 /** 11889 * The base that is used to calculate the filesize. You can change this to 11890 * 1024 if you would rather display kibibytes, mebibytes, etc... 11891 * 1024 is technically incorrect, because `1024 bytes` are `1 kibibyte` not `1 kilobyte`. 11892 * You can change this to `1024` if you don't care about validity. 11893 */ 11894 filesizeBase: 1000, 11895 11896 /** 11897 * Can be used to limit the maximum number of files that will be handled by this Dropzone 11898 */ 11899 maxFiles: null, 11900 11901 /** 11902 * An optional object to send additional headers to the server. Eg: 11903 * `{ "My-Awesome-Header": "header value" }` 11904 */ 11905 headers: null, 11906 11907 /** 11908 * If `true`, the dropzone element itself will be clickable, if `false` 11909 * nothing will be clickable. 11910 * 11911 * You can also pass an HTML element, a CSS selector (for multiple elements) 11912 * or an array of those. In that case, all of those elements will trigger an 11913 * upload when clicked. 11914 */ 11915 clickable: true, 11916 11917 /** 11918 * Whether hidden files in directories should be ignored. 11919 */ 11920 ignoreHiddenFiles: true, 11921 11922 /** 11923 * The default implementation of `accept` checks the file's mime type or 11924 * extension against this list. This is a comma separated list of mime
11925 * types or file extensions. 11926 * 11927 * Eg.: `image/*,application/pdf,.psd` 11928 * 11929 * If the Dropzone is `clickable` this option will also be used as 11930 * [`accept`](https://developer.mozilla.org/en-US/docs/HTML/Element/input#attr-accept) 11931 * parameter on the hidden file input as well. 11932 */ 11933 acceptedFiles: null, 11934 11935 /** 11936 * **Deprecated!** 11937 * Use acceptedFiles instead. 11938 */ 11939 acceptedMimeTypes: null, 11940 11941 /** 11942 * If false, files will be added to the queue but the queue will not be 11943 * processed automatically. 11944 * This can be useful if you need some additional user input before sending 11945 * files (or if you want want all files sent at once). 11946 * If you're ready to send the file simply call `myDropzone.processQueue()`. 11947 * 11948 * See the [enqueuing file uploads](#enqueuing-file-uploads) documentation 11949 * section for more information. 11950 */ 11951 autoProcessQueue: true, 11952 11953 /** 11954 * If false, files added to the dropzone will not be queued by default. 11955 * You'll have to call `enqueueFile(file)` manually. 11956 */ 11957 autoQueue: true, 11958 11959 /** 11960 * If `true`, this will add a link to every file preview to remove or cancel (if 11961 * already uploading) the file. The `dictCancelUpload`, `dictCancelUploadConfirmation` 11962 * and `dictRemoveFile` options are used for the wording. 11963 */ 11964 addRemoveLinks: false, 11965 11966 /** 11967 * Defines where to display the file previews â if `null` the 11968 * Dropzone element itself is used. Can be a plain `HTMLElement` or a CSS 11969 * selector. The element should have the `dropzone-previews` class so 11970 * the previews are displayed properly. 11971 */ 11972 previewsContainer: null, 11973 11974 /** 11975 * This is the element the hidden input field (which is used when clicking on the 11976 * dropzone to trigger file selection) will be appended to. This might 11977 * be important in case you use frameworks to switch the content of your page. 11978 * 11979 * Can be a selector string, or an element directly. 11980 */ 11981 hiddenInputContainer: "body", 11982 11983 /** 11984 * If null, no capture type will be specified 11985 * If camera, mobile devices will skip the file selection and choose camera 11986 * If microphone, mobile devices will skip the file selection and choose the microphone 11987 * If camcorder, mobile devices will skip the file selection and choose the camera in video mode 11988 * On apple devices multiple must be set to false. AcceptedFiles may need to 11989 * be set to an appropriate mime type (e.g. "image/*", "audio/*", or "video/*"). 11990 */ 11991 capture: null, 11992 11993 /** 11994 * **Deprecated**. Use `renameFile` instead. 11995 */ 11996 renameFilename: null, 11997 11998 /** 11999 * A function that is invoked before the file is uploaded to the server and renames the file. 12000 * This function gets the `File` as argument and can use the `file.name`. The actual name of the 12001 * file that gets used during the upload can be accessed through `file.upload.filename`. 12002 */ 12003 renameFile: null, 12004 12005 /** 12006 * If `true` the fallback will be forced. This is very useful to test your server 12007 * implementations first and make sure that everything works as 12008 * expected without dropzone if you experience problems, and to test 12009 * how your fallbacks will look. 12010 */ 12011 forceFallback: false, 12012 12013 /** 12014 * The text used before any files are dropped. 12015 */ 12016 dictDefaultMessage: "Drop files here to upload", 12017 12018 /** 12019 * The text that replaces the default message text it the browser is not supported. 12020 */ 12021 dictFallbackMessage: "Your browser does not support drag'n'drop file uploads.", 12022 12023 /** 12024 * The text that will be added before the fallback form. 12025 * If you provide a fallback element yourself, or if this option is `null` this will 12026 * be ignored. 12027 */ 12028 dictFallbackText: "Please use the fallback form below to upload your files like in the olde
vendor: 4,628 bytes, lines 12028-12152
12028n days.", 12029 12030 /** 12031 * If the filesize is too big. 12032 * `{{filesize}}` and `{{maxFilesize}}` will be replaced with the respective configuration values. 12033 */ 12034 dictFileTooBig: "File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB.", 12035 12036 /** 12037 * If the file doesn't match the file type. 12038 */ 12039 dictInvalidFileType: "You can't upload files of this type.", 12040 12041 /** 12042 * If the server response was invalid. 12043 * `{{statusCode}}` will be replaced with the servers status code. 12044 */ 12045 dictResponseError: "Server responded with {{statusCode}} code.", 12046 12047 /** 12048 * If `addRemoveLinks` is true, the text to be used for the cancel upload link. 12049 */ 12050 dictCancelUpload: "Cancel upload", 12051 12052 /** 12053 * The text that is displayed if an upload was manually canceled 12054 */ 12055 dictUploadCanceled: "Upload canceled.", 12056 12057 /** 12058 * If `addRemoveLinks` is true, the text to be used for confirmation when cancelling upload. 12059 */ 12060 dictCancelUploadConfirmation: "Are you sure you want to cancel this upload?", 12061 12062 /** 12063 * If `addRemoveLinks` is true, the text to be used to remove a file. 12064 */ 12065 dictRemoveFile: "Remove file", 12066 12067 /** 12068 * If this is not null, then the user will be prompted before removing a file. 12069 */ 12070 dictRemoveFileConfirmation: null, 12071 12072 /** 12073 * Displayed if `maxFiles` is st and exceeded. 12074 * The string `{{maxFiles}}` will be replaced by the configuration value. 12075 */ 12076 dictMaxFilesExceeded: "You can not upload any more files.", 12077 12078 /** 12079 * Allows you to translate the different units. Starting with `tb` for terabytes and going down to 12080 * `b` for bytes. 12081 */ 12082 dictFileSizeUnits: { 12083 tb: "TB", 12084 gb: "GB", 12085 mb: "MB", 12086 kb: "KB", 12087 b: "b" 12088 }, 12089 12090 /** 12091 * Called when dropzone initialized 12092 * You can add event listeners here 12093 */ 12094 init: function init() {}, 12095 12096 /** 12097 * Can be an **object** of additional parameters to transfer to the server, **or** a `Function` 12098 * that gets invoked with the `files`, `xhr` and, if it's a chunked upload, `chunk` arguments. In case 12099 * of a function, this needs to return a map. 12100 * 12101 * The default implementation does nothing for normal uploads, but adds relevant information for 12102 * chunked uploads. 12103 * 12104 * This is the same as adding hidden input fields in the form element. 12105 */ 12106 params: function params(files, xhr, chunk) { 12107 if (chunk) { 12108 return { 12109 dzuuid: chunk.file.upload.uuid, 12110 dzchunkindex: chunk.index, 12111 dztotalfilesize: chunk.file.size, 12112 dzchunksize: this.options.chunkSize, 12113 dztotalchunkcount: chunk.file.upload.totalChunkCount, 12114 dzchunkbyteoffset: chunk.index * this.options.chunkSize 12115 }; 12116 } 12117 }, 12118 12119 /** 12120 * A function that gets a [file](https://developer.mozilla.org/en-US/docs/DOM/File) 12121 * and a `done` function as parameters. 12122 * 12123 * If the done function is invoked without arguments, the file is "accepted" and will 12124 * be processed. If you pass an error message, the file is rejected, and the error 12125 * message will be displayed. 12126 * This function will not be called if the file is too big or doesn't match the mime types. 12127 */ 12128 accept: function accept(file, done) { 12129 return done(); 12130 }, 12131 12132 /** 12133 * The callback that will be invoked when all chunks have been uploaded for a file. 12134 * It gets the file for which the chunks have been uploaded as the first parameter, 12135 * and the `done` function as second. `done()` needs to be invoked when everything 12136 * needed to finish the upload process is done. 12137 */ 12138 chunksUploaded: function chunksUploaded(file, done) { 12139 done(); 12140 }, 12141 12142 /** 12143 * Gets called when the browser is not supported. 12144 * The default implementation shows the fallback input field and adds 12145 * a text. 12146 */ 12147 fallback: function fallback() { 12148 // This code should pass in IE7... :( 12149 var messageElement; 12150 this.element.className = "".concat(this.element.className, " dz-browser-not-supported"); 12151 var _iteratorNormalCompletion2 = true; 12152 var _didIteratorError2 = false;
12153 var _iteratorError2 = undefined; 12154 12155 try { 12156 for (var _iterator2 = this.element.getElementsByTagName("div")[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { 12157 var child = _step2.value; 12158 12159 if (/(^| )dz-message($| )/.test(child.className)) { 12160 messageElement = child; 12161 child.className = "dz-message"; // Removes the 'dz-default' class 12162 12163 break; 12164 } 12165 } 12166 } catch (err) { 12167 _didIteratorError2 = true; 12168 _iteratorError2 = err; 12169 } finally { 12170 try { 12171 if (!_iteratorNormalCompletion2 && _iterator2["return"] != null) { 12172 _iterator2["return"](); 12173 } 12174 } finally { 12175 if (_didIteratorError2) { 12176 throw _iteratorError2; 12177 } 12178 } 12179 } 12180 12181 if (!messageElement) { 12182 messageElement = Dropzone.createElement("<div class=\"dz-message\"><span></span></div>"); 12183 this.element.appendChild(messageElement); 12184 } 12185 12186 var span = messageElement.getElementsByTagName("span")[0]; 12187 12188 if (span) { 12189 if (span.textContent != null) { 12190 span.textContent = this.options.dictFallbackMessage; 12191 } else if (span.innerText != null) { 12192 span.innerText = this.options.dictFallbackMessage; 12193 } 12194 } 12195 12196 return this.element.appendChild(this.getFallbackForm()); 12197 }, 12198 12199 /** 12200 * Gets called to calculate the thumbnail dimensions. 12201 * 12202 * It gets `file`, `width` and `height` (both may be `null`) as parameters and must return an object c
vendor: 8,652 bytes, lines 12202-12344
12202ontaining: 12203 * 12204 * - `srcWidth` & `srcHeight` (required) 12205 * - `trgWidth` & `trgHeight` (required) 12206 * - `srcX` & `srcY` (optional, default `0`) 12207 * - `trgX` & `trgY` (optional, default `0`) 12208 * 12209 * Those values are going to be used by `ctx.drawImage()`. 12210 */ 12211 resize: function resize(file, width, height, resizeMethod) { 12212 var info = { 12213 srcX: 0, 12214 srcY: 0, 12215 srcWidth: file.width, 12216 srcHeight: file.height 12217 }; 12218 var srcRatio = file.width / file.height; // Automatically calculate dimensions if not specified 12219 12220 if (width == null && height == null) { 12221 width = info.srcWidth; 12222 height = info.srcHeight; 12223 } else if (width == null) { 12224 width = height * srcRatio; 12225 } else if (height == null) { 12226 height = width / srcRatio; 12227 } // Make sure images aren't upscaled 12228 12229 12230 width = Math.min(width, info.srcWidth); 12231 height = Math.min(height, info.srcHeight); 12232 var trgRatio = width / height; 12233 12234 if (info.srcWidth > width || info.srcHeight > height) { 12235 // Image is bigger and needs rescaling 12236 if (resizeMethod === 'crop') { 12237 if (srcRatio > trgRatio) { 12238 info.srcHeight = file.height; 12239 info.srcWidth = info.srcHeight * trgRatio; 12240 } else { 12241 info.srcWidth = file.width; 12242 info.srcHeight = info.srcWidth / trgRatio; 12243 } 12244 } else if (resizeMethod === 'contain') { 12245 // Method 'contain' 12246 if (srcRatio > trgRatio) { 12247 height = width / srcRatio; 12248 } else { 12249 width = height * srcRatio; 12250 } 12251 } else { 12252 throw new Error("Unknown resizeMethod '".concat(resizeMethod, "'")); 12253 } 12254 } 12255 12256 info.srcX = (file.width - info.srcWidth) / 2; 12257 info.srcY = (file.height - info.srcHeight) / 2; 12258 info.trgWidth = width; 12259 info.trgHeight = height; 12260 return info; 12261 }, 12262 12263 /** 12264 * Can be used to transform the file (for example, resize an image if necessary). 12265 * 12266 * The default implementation uses `resizeWidth` and `resizeHeight` (if provided) and resizes 12267 * images according to those dimensions. 12268 * 12269 * Gets the `file` as the first parameter, and a `done()` function as the second, that needs 12270 * to be invoked with the file when the transformation is done. 12271 */ 12272 transformFile: function transformFile(file, done) { 12273 if ((this.options.resizeWidth || this.options.resizeHeight) && file.type.match(/image.*/)) { 12274 return this.resizeImage(file, this.options.resizeWidth, this.options.resizeHeight, this.options.resizeMethod, done); 12275 } else { 12276 return done(file); 12277 } 12278 }, 12279 12280 /** 12281 * A string that contains the template used for each dropped 12282 * file. Change it to fulfill your needs but make sure to properly 12283 * provide all elements. 12284 * 12285 * If you want to use an actual HTML element instead of providing a String 12286 * as a config option, you could create a div with the id `tpl`, 12287 * put the template inside it and provide the element like this: 12288 * 12289 * document 12290 * .querySelector('#tpl') 12291 * .innerHTML 12292 * 12293 */ 12294 previewTemplate: "<div class=\"dz-preview dz-file-preview\">\n <div class=\"dz-image\"><img data-dz-thumbnail /></div>\n <div class=\"dz-details\">\n <div class=\"dz-size\"><span data-dz-size></span></div>\n <div class=\"dz-filename\"><span data-dz-name></span></div>\n </div>\n <div class=\"dz-progress\"><span class=\"dz-upload\" data-dz-uploadprogress></span></div>\n <div class=\"dz-error-message\"><span data-dz-errormessage></span></div>\n <div class=\"dz-success-mark\">\n <svg width=\"54px\" height=\"54px\" viewBox=\"0 0 54 54\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n <title>Check</title>\n <g stroke=\"none\" stroke-width=\"1\" fill=\"none\" fill-rule=\"evenodd\">\n <path d=\"M23.5,31.8431458 L17.5852419,25.9283877 C16.0248253,24.3679711 13.4910294,24.366835 11.9289322,25.9289322 C10.3700136,27.4878508 10.3665912,30.0234455 11.9283877,31.5852419 L20.4147581,40.0716123 C20.5133999,40.1702541 20.6159315,40.2626649 20.7218615,40.3488435 C22.2835669,41.8725651 24.794234,41.8626202 26.3461564,40.3106978 L43.3106978,23.3461564 C44.8771021,21.7797521 44.8758057,19.2483887 43.3137085,17.6862915 C41.7547899,16.1273729 39.2176035,16.1255422 37.6538436,17.6893022 L23.5,31.8431458 Z M27,53 C41.3594035,53 53,41.3594035 53,27 C53,12.6405965 41.3594035,1 27,1 C12.6405965,1 1,12.6405965 1,27 C1,41.3594035 12.6405965,53 27,53 Z\" stroke-opacity=\"0.198794158\" stroke=\"#747474\" fill-opacity=\"0.816519475\" fill=\"#FFFFFF\"></path>\n </g>\n </svg>\n </div>\n <div class=\"dz-error-mark\">\n <svg width=\"54px\" height=\"54px\" viewBox=\"0 0 54 54\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n <title>Error</title>\n <g stroke=\"none\" stroke-width=\"1\" fill=\"none\" fill-rule=\"evenodd\">\n <g stroke=\"#747474\" stroke-opacity=\"0.198794158\" fill=\"#FFFFFF\" fill-opacity=\"0.816519475\">\n <path d=\"M32.6568542,29 L38.3106978,23.3461564 C39.8771021,21.7797521 39.8758057,19.2483887 38.3137085,17.6862915 C36.7547899,16.1273729 34.2176035,16.1255422 32.6538436,17.6893022 L27,23.3431458 L21.3461564,17.6893022 C19.7823965,16.1255422 17.2452101,16.1273729 15.6862915,17.6862915 C14.1241943,19.2483887 14.1228979,21.7797521 15.6893022,23.3461564 L21.3431458,29 L15.6893022,34.6538436 C14.1228979,36.2202479 14.1241943,38.7516113 15.6862915,40.3137085 C17.2452101,41.8726271 19.7823965,41.8744578 21.3461564,40.3106978 L27,34.6568542 L32.6538436,40.3106978 C34.2176035,41.8744578 36.7547899,41.8726271 38.3137085,40.3137085 C39.8758057,38.7516113 39.8771021,36.2202479 38.3106978,34.6538436 L32.6568542,29 Z M27,53 C41.3594035,53 53,41.3594035 53,27 C53,12.6405965 41.3594035,1 27,1 C12.6405965,1 1,12.6405965 1,27 C1,41.3594035 12.6405965,53 27,53 Z\"></path>\n </g>\n </g>\n </svg>\n </div>\n</div>", 12295 // END OPTIONS 12296 // (Required by the dropzone documentation parser) 12297 12298 /* 12299 Those functions register themselves to the events on init and handle all 12300 the user interface specific stuff. Overwriting them won't break the upload 12301 but can break the way it's displayed. 12302 You can overwrite them if you don't like the default behavior. If you just 12303 want to add an additional event handler, register it on the dropzone object 12304 and don't overwrite those options. 12305 */ 12306 // Those are self explanatory and simply concern the DragnDrop. 12307 drop: function drop(e) { 12308 return this.element.classList.remove("dz-drag-hover"); 12309 }, 12310 dragstart: function dragstart(e) {}, 12311 dragend: function dragend(e) { 12312 return this.element.classList.remove("dz-drag-hover"); 12313 }, 12314 dragenter: function dragenter(e) { 12315 return this.element.classList.add("dz-drag-hover"); 12316 }, 12317 dragover: function dragover(e) { 12318 return this.element.classList.add("dz-drag-hover"); 12319 }, 12320 dragleave: function dragleave(e) { 12321 return this.element.classList.remove("dz-drag-hover"); 12322 }, 12323 paste: function paste(e) {}, 12324 // Called whenever there are no files left in the dropzone anymore, and the 12325 // dropzone should be displayed as if in the initial state. 12326 reset: function reset() { 12327 return this.element.classList.remove("dz-started"); 12328 }, 12329 // Called when a file is added to the queue 12330 // Receives `file` 12331 addedfile: function addedfile(file) { 12332 var _this2 = this; 12333 12334 if (this.element === this.previewsContainer) { 12335 this.element.classList.add("dz-started"); 12336 } 12337 12338 if (this.previewsContainer) { 12339 file.previewElement = Dropzone.createElement(this.options.previewTemplate.trim()); 12340 file.previewTemplate = file.previewElement; // Backwards compatibility 12341 12342 this.previewsContainer.appendChild(file.previewElement); 12343 var _iteratorNormalCompletion3 = true; 12344 var _didIteratorError3 = false;
12345 var _iteratorError3 = undefined; 12346 12347 try { 12348 for (var _iterator3 = file.previewElement.querySelectorAll("[data-dz-name]")[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { 12349 var node = _step3.value; 12350 node.textContent = file.name; 12351 } 12352 } catch (err) { 12353 _didIteratorError3 = true; 12354 _iteratorError3 = err; 12355 } finally { 12356 try { 12357 if (!_iteratorNormalCompletion3 && _iterator3["return"] != null) { 12358 _iterator3["return"](); 12359 } 12360 } finally { 12361 if (_didIteratorError3) { 12362 throw _iteratorError3; 12363 } 12364 } 12365 } 12366 12367 var _iteratorNormalCompletion4 = true; 12368 var _didIteratorError4 = false; 12369 var _iteratorError4 = undefined; 12370 12371 try { 12372 for (var _iterator4 = file.previewElement.querySelectorAll("[data-dz-size]")[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) { 12373 node = _step4.value; 12374 node.innerHTML = this.filesize(file.size); 12375 } 12376 } catch (err) { 12377 _didIteratorError4 = true; 12378 _iteratorError4 = err; 12379 } finally { 12380 try { 12381 if (!_iteratorNormalCompletion4 && _iterator4["return"] != null) { 12382 _iterator4["return"](); 12383 } 12384 } finally { 12385 if (_didIteratorError4) { 12386 throw _iteratorError4; 12387 } 12388 } 12389 } 12390 12391 if (this.options.addRemoveLinks) { 12392 file._removeLink = Dropzone.createElement("<a class=\"dz-remove\" href=\"javascript:undefined;\" data-dz-remove>".concat(this.options.dictRemoveFile, "</a>")); 12393 file.previewElement.appendChild(file._removeLink); 12394 } 12395 12396 var removeFileEvent = function removeFileEvent(e) { 12397 e.preventDefault(); 12398 e.stopPropagation(); 12399 12400 if (file.status === Dropzone.UPLOADING) { 12401 return Dropzone.confirm(_this2.options.dictCancelUploadConfirmation, function () { 12402 return _this2.removeFile(file); 12403 }); 12404 } else { 12405 if (_this2.options.dictRemoveFileConfirmation) { 12406 return Dropzone.confirm(_this2.options.dictRemoveFileConfirmation, function () { 12407 return _this2.removeFile(file); 12408 }); 12409 } else { 12410 return _this2.removeFile(file); 12411 } 12412 } 12413 }; 12414 12415 var _iteratorNormalCompletion5 = true; 12416 var _didIteratorError5 = false; 12417 var _iteratorError5 = undefined; 12418 12419 try { 12420 for (var _iterator5 = file.previewElement.querySelectorAll("[data-dz-remove]")[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) { 12421 var removeLink = _step5.value; 12422 removeLink.addEventListener("click", removeFileEvent); 12423 } 12424 } catch (err) { 12425 _didIteratorError5 = true; 12426 _iteratorError5 = err; 12427 } finally { 12428 try { 12429 if (!_iteratorNormalCompletion5 && _iterator5["return"] != null) { 12430 _iterator5["return"](); 12431 } 12432 } finally { 12433 if (_didIteratorError5) { 12434 throw _iteratorError5; 12435 } 12436 } 12437 } 12438 } 12439 }, 12440 // Called whenever a file is removed. 12441 removedfile: function removedfile(file) { 12442 if (file.previewElement != null && file.previewElement.parentNode != null) { 12443 file.previewElement.parentNode.removeChild(file.previewElement); 12444 } 12445 12446 return this._updateMaxFilesReachedClass(); 12447 }, 12448 // Called when a thumbnail has been generated 12449 // Receives `file` and `dataUrl` 12450 thumbnail: function thumbnail(file, dataUrl) { 12451 if (file.previewElement) { 12452 file.previewElement.classList.remove("dz-file-preview"); 12453 var _iteratorNormalCompletion6 = true; 12454 var _didIteratorError6 = false;
12455 var _iteratorError6 = undefined; 12456 12457 try { 12458 for (var _iterator6 = file.previewElement.querySelectorAll("[data-dz-thumbnail]")[Symbol.iterator](), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) { 12459 var thumbnailElement = _step6.value; 12460 thumbnailElement.alt = file.name; 12461 thumbnailElement.src = dataUrl; 12462 } 12463 } catch (err) { 12464 _didIteratorError6 = true; 12465 _iteratorError6 = err; 12466 } finally { 12467 try { 12468 if (!_iteratorNormalCompletion6 && _iterator6["return"] != null) { 12469 _iterator6["return"](); 12470 } 12471 } finally { 12472 if (_didIteratorError6) { 12473 throw _iteratorError6; 12474 } 12475 } 12476 } 12477 12478 return setTimeout(function () { 12479 return file.previewElement.classList.add("dz-image-preview"); 12480 }, 1); 12481 } 12482 }, 12483 // Called whenever an error occurs 12484 // Receives `file` and `message` 12485 error: function error(file, message) { 12486 if (file.previewElement) { 12487 file.previewElement.classList.add("dz-error"); 12488 12489 if (typeof message !== "String" && message.error) { 12490 message = message.error; 12491 } 12492 12493 var _iteratorNormalCompletion7 = true; 12494 var _didIteratorError7 = false; 12495 var _iteratorError7 = undefined; 12496 12497 try { 12498 for (var _iterator7 = file.previewElement.querySelectorAll("[data-dz-errormessage]")[Symbol.iterator](), _step7; !(_iteratorNormalCompletion7 = (_step7 = _iterator7.next()).done); _iteratorNormalCompletion7 = true) { 12499 var node = _step7.value; 12500 node.textContent = message; 12501 } 12502 } catch (err) { 12503 _didIteratorError7 = true; 12504 _iteratorError7 = err; 12505 } finally { 12506 try { 12507 if (!_iteratorNormalCompletion7 && _iterator7["return"] != null) { 12508 _iterator7["return"](); 12509 } 12510 } finally { 12511 if (_didIteratorError7) { 12512 throw _iteratorError7; 12513 } 12514 } 12515 } 12516 } 12517 }, 12518 errormultiple: function errormultiple() {}, 12519 // Called when a file gets processed. Since there is a cue, not all added 12520 // files are processed immediately. 12521 // Receives `file` 12522 processing: function processing(file) { 12523 if (file.previewElement) { 12524 file.previewElement.classList.add("dz-processing"); 12525 12526 if (file._removeLink) { 12527 return file._removeLink.innerHTML = this.options.dictCancelUpload; 12528 } 12529 } 12530 }, 12531 processingmultiple: function processingmultiple() {}, 12532 // Called whenever the upload progress gets updated. 12533 // Receives `file`, `progress` (percentage 0-100) and `bytesSent`. 12534 // To get the total number of bytes of the file, use `file.size` 12535 uploadprogress: function uploadprogress(file, progress, bytesSent) { 12536 if (file.previewElement) { 12537 var _iteratorNormalCompletion8 = true; 12538 var _didIteratorError8 = false; 12539 var _iteratorError8 = undefined; 12540 12541 try { 12542 for (var _iterator8 = file.previewElement.querySelectorAll("[data-dz-uploadprogress]")[Symbol.iterator](), _step8; !(_iteratorNormalCompletion8 = (_step8 = _iterator8.next()).done); _iteratorNormalCompletion8 = true) { 12543 var node = _step8.value; 12544 node.nodeName === 'PROGRESS' ? node.value = progress : node.style.width = "".concat(progress, "%"); 12545 } 12546 } catch (err) { 12547 _didIteratorError8 = true; 12548 _iteratorError8 = err; 12549 } finally { 12550 try { 12551 if (!_iteratorNormalCompletion8 && _iterator8["return"] != null) { 12552 _iterator8["return"](); 12553 } 12554 } finally { 12555 if (_didIteratorError8) { 12556 throw _iteratorError8; 12557 } 12558 } 12559 } 12560 } 12561 }, 12562 // Called whenever the total upload progress gets updated. 12563 // Called with totalUploadProgress (0-100), totalBytes and totalBytesSent 12564 totaluploadprogress: function totaluploadprogress() {}, 12565 // Called just before the file is sent. Gets the `xhr` object as second 12566 // parameter, so you can modify it (for example to add a CSRF token) and a 12567 // `formData` object to add additional information. 12568 sending: function sending() {}, 12569 sendingmultiple: function sendingmultiple() {}, 12570 // When the complete upload is finished and successful 12571 // Receives `file` 12572 success: function success(file) { 12573 if (file.previewElement) { 12574 return file.previewElement.classList.add("dz-success"); 12575 } 12576 }, 12577 successmultiple: function successmultiple() {}, 12578 // When the upload is canceled. 12579 canceled: function canceled(file) {
12580 return this.emit("error", file, this.options.dictUploadCanceled); 12581 }, 12582 canceledmultiple: function canceledmultiple() {}, 12583 // When the upload is finished, either with success or an error. 12584 // Receives `file` 12585 complete: function complete(file) { 12586 if (file._removeLink) { 12587 file._removeLink.innerHTML = this.options.dictRemoveFile; 12588 } 12589 12590 if (file.previewElement) { 12591 return file.previewElement.classList.add("dz-complete"); 12592 } 12593 }, 12594 completemultiple: function completemultiple() {}, 12595 maxfilesexceeded: function maxfilesexceeded() {}, 12596 maxfilesreached: function maxfilesreached() {}, 12597 queuecomplete: function queuecomplete() {}, 12598 addedfiles: function addedfiles() {} 12599 }; 12600 this.prototype._thumbnailQueue = []; 12601 this.prototype._processingThumbnail = false; 12602 } // global utility 12603 12604 }, { 12605 key: "extend", 12606 value: function extend(target) { 12607 for (var _len2 = arguments.length, objects = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { 12608 objects[_key2 - 1] = arguments[_key2]; 12609 } 12610 12611 for (var _i = 0, _objects = objects; _i < _objects.length; _i++) { 12612 var object = _objects[_i]; 12613 12614 for (var key in object) { 12615 var val = object[key]; 12616 target[key] = val; 12617 } 12618 } 12619 12620 return target; 12621 } 12622 }]); 12623 12624 function Dropzone(el, options) { 12625 var _this; 12626 12627 _classCallCheck(this, Dropzone); 12628 12629 _this = _possibleConstructorReturn(this, _getPrototypeOf(Dropzone).call(this)); 12630 var fallback, left; 12631 _this.element = el; // For backwards compatibility since the version was in the prototype previously 12632 12633 _this.version = Dropzone.version; 12634 _this.defaultOptions.previewTemplate = _this.defaultOptions.previewTemplate.replace(/\n*/g, ""); 12635 _this.clickableElements = []; 12636 _this.listeners = []; 12637 _this.files = []; // All files 12638 12639 if (typeof _this.element === "string") { 12640 _this.element = document.querySelector(_this.element); 12641 } // Not checking if instance of HTMLElement or Element since IE9 is extremely weird. 12642 12643 12644 if (!_this.element || _this.element.nodeType == null) { 12645 throw new Error("Invalid dropzone element."); 12646 } 12647 12648 if (_this.element.dropzone) { 12649 throw new Error("Dropzone already attached."); 12650 } // Now add this dropzone to the instances. 12651 12652 12653 Dropzone.instances.push(_assertThisInitialized(_this)); // Put the dropzone inside the element itself. 12654 12655 _this.element.dropzone = _assertThisInitialized(_this); 12656 var elementOptions = (left = Dropzone.optionsForElement(_this.element)) != null ? left : {}; 12657 _this.options = Dropzone.extend({}, _this.defaultOptions, elementOptions, options != null ? options : {}); // If the browser failed, just call the fallback and leave 12658 12659 if (_this.options.forceFallback || !Dropzone.isBrowserSupported()) { 12660 return _possibleConstructorReturn(_this, _this.options.fallback.call(_assertThisInitialized(_this))); 12661 } // @options.url = @element.getAttribute "action" unless @options.url? 12662 12663 12664 if (_this.options.url == null) { 12665 _this.options.url = _this.element.getAttribute("action"); 12666 } 12667 12668 if (!_this.options.url) { 12669 throw new Error("No URL provided."); 12670 } 12671 12672 if (_this.options.acceptedFiles && _this.options.acceptedMimeTypes) { 12673 throw new Error("You can't provide both 'acceptedFiles' and 'acceptedMimeTypes'. 'acceptedMimeTypes' is deprecated."); 12674 } 12675 12676 if (_this.options.uploadMultiple && _this.options.chunking) { 12677 throw new Error('You cannot set both: uploadMultiple and chunking.'); 12678 } // Backwards compatibility 12679 12680 12681 if (_this.options.acceptedMimeTypes) { 12682 _this.options.acceptedFiles = _this.options.acceptedMimeTypes; 12683 delete _this.options.acceptedMimeTypes; 12684 } // Backwards compatibility 12685 12686 12687 if (_this.options.renameFilename != null) { 12688 _this.options.renameFile = function (file) { 12689 return _this.options.renameFilename.call(_assertThisInitialized(_this), file.name, file); 12690 }; 12691 } 12692 12693 _this.options.method = _this.options.method.toUpperCase(); 12694 12695 if ((fallback = _this.getExistingFallback()) && fallback.parentNode) { 12696 // Remove the fallback 12697 fallback.parentNode.removeChild(fallback); 12698 } // Display previews in the previewsContainer element or the Dropzone element unless explicitly set to false 12699 12700 12701 if (_this.options.previewsContainer !== false) { 12702 if (_this.options.previewsContainer) { 12703 _this.previewsContainer = Dropzone.getElement(_this.options.previewsContainer, "previewsContainer"); 12704 } else { 12705 _this.previewsContainer = _this.element; 12706 } 12707 } 12708 12709 if (_this.options.clickable) { 12710 if (_this.options.clickable === true) { 12711 _this.clickableElements = [_this.element]; 12712 } else { 12713 _this.clickableElements = Dropzone.getElements(_this.options.clickable, "clickable"); 12714 } 12715 } 12716 12717 _this.init(); 12718 12719 return _this; 12720 } // Returns all files that have been accepted 12721 12722 12723 _createClass(Dropzone, [{ 12724 key: "getAcceptedFiles", 12725 value: function getAcceptedFiles() { 12726 return this.files.filter(function (file) { 12727 return file.accepted; 12728 }).map(function (file) { 12729 return file; 12730 }); 12731 } // Returns all files that have been rejected
12732 // Not sure when that's going to be useful, but added for completeness. 12733 12734 }, { 12735 key: "getRejectedFiles", 12736 value: function getRejectedFiles() { 12737 return this.files.filter(function (file) { 12738 return !file.accepted; 12739 }).map(function (file) { 12740 return file; 12741 }); 12742 } 12743 }, { 12744 key: "getFilesWithStatus", 12745 value: function getFilesWithStatus(status) { 12746 return this.files.filter(function (file) { 12747 return file.status === status; 12748 }).map(function (file) { 12749 return file; 12750 }); 12751 } // Returns all files that are in the queue 12752 12753 }, { 12754 key: "getQueuedFiles", 12755 value: function getQueuedFiles() { 12756 return this.getFilesWithStatus(Dropzone.QUEUED); 12757 } 12758 }, { 12759 key: "getUploadingFiles", 12760 value: function getUploadingFiles() { 12761 return this.getFilesWithStatus(Dropzone.UPLOADING); 12762 } 12763 }, { 12764 key: "getAddedFiles", 12765 value: function getAddedFiles() { 12766 return this.getFilesWithStatus(Dropzone.ADDED); 12767 } // Files that are either queued or uploading 12768 12769 }, { 12770 key: "getActiveFiles", 12771 value: function getActiveFiles() { 12772 return this.files.filter(function (file) { 12773 return file.status === Dropzone.UPLOADING || file.status === Dropzone.QUEUED; 12774 }).map(function (file) { 12775 return file; 12776 }); 12777 } // The function that gets called when Dropzone is initialized. You 12778 // can (and should) setup event listeners inside this function. 12779 12780 }, { 12781 key: "init", 12782 value: function init() { 12783 var _this3 = this; 12784 12785 // In case it isn't set already 12786 if (this.element.tagName === "form") { 12787 this.element.setAttribute("enctype", "multipart/form-data"); 12788 } 12789 12790 if (this.element.classList.contains("dropzone") && !this.element.querySelector(".dz-message")) { 12791 this.element.appendChild(Dropzone.createElement("<div class=\"dz-default dz-message\"><button class=\"dz-button\" type=\"button\">".concat(this.options.dictDefaultMessage, "</button></div>"))); 12792 } 12793 12794 if (this.clickableElements.length) { 12795 var setupHiddenFileInput = function setupHiddenFileInput() { 12796 if (_this3.hiddenFileInput) { 12797 _this3.hiddenFileInput.parentNode.removeChild(_this3.hiddenFileInput); 12798 } 12799 12800 _this3.hiddenFileInput = document.createElement("input"); 12801 12802 _this3.hiddenFileInput.setAttribute("type", "file"); 12803 12804 if (_this3.options.maxFiles === null || _this3.options.maxFiles > 1) { 12805 _this3.hiddenFileInput.setAttribute("multiple", "multiple"); 12806 } 12807 12808 _this3.hiddenFileInput.className = "dz-hidden-input"; 12809 12810 if (_this3.options.acceptedFiles !== null) { 12811 _this3.hiddenFileInput.setAttribute("accept", _this3.options.acceptedFiles); 12812 } 12813 12814 if (_this3.options.capture !== null) { 12815 _this3.hiddenFileInput.setAttribute("capture", _this3.options.capture); 12816 } // Not setting `display="none"` because some browsers don't accept clicks 12817 // on elements that aren't displayed. 12818 12819 12820 _this3.hiddenFileInput.style.visibility = "hidden"; 12821 _this3.hiddenFileInput.style.position = "absolute"; 12822 _this3.hiddenFileInput.style.top = "0"; 12823 _this3.hiddenFileInput.style.left = "0"; 12824 _this3.hiddenFileInput.style.height = "0"; 12825 _this3.hiddenFileInput.style.width = "0"; 12826 Dropzone.getElement(_this3.options.hiddenInputContainer, 'hiddenInputContainer').appendChild(_this3.hiddenFileInput); 12827 return _this3.hiddenFileInput.addEventListener("change", function () { 12828 var files = _this3.hiddenFileInput.files; 12829 12830 if (files.length) { 12831 var _iteratorNormalCompletion9 = true; 12832 var _didIteratorError9 = false; 12833 var _iteratorError9 = undefined; 12834 12835 try { 12836 for (var _iterator9 = files[Symbol.iterator](), _step9; !(_iteratorNormalCompletion9 = (_step9 = _iterator9.next()).done); _iteratorNormalCompletion9 = true) { 12837 var file = _step9.value; 12838 12839 _this3.addFile(file); 12840 } 12841 } catch (err) {
12842 _didIteratorError9 = true; 12843 _iteratorError9 = err; 12844 } finally { 12845 try { 12846 if (!_iteratorNormalCompletion9 && _iterator9["return"] != null) { 12847 _iterator9["return"](); 12848 } 12849 } finally { 12850 if (_didIteratorError9) { 12851 throw _iteratorError9; 12852 } 12853 } 12854 } 12855 } 12856 12857 _this3.emit("addedfiles", files); 12858 12859 return setupHiddenFileInput(); 12860 }); 12861 }; 12862 12863 setupHiddenFileInput(); 12864 } 12865 12866 this.URL = window.URL !== null ? window.URL : window.webkitURL; // Setup all event listeners on the Dropzone object itself. 12867 // They're not in @setupEventListeners() because they shouldn't be removed 12868 // again when the dropzone gets disabled. 12869 12870 var _iteratorNormalCompletion10 = true; 12871 var _didIteratorError10 = false; 12872 var _iteratorError10 = undefined; 12873 12874 try { 12875 for (var _iterator10 = this.events[Symbol.iterator](), _step10; !(_iteratorNormalCompletion10 = (_step10 = _iterator10.next()).done); _iteratorNormalCompletion10 = true) { 12876 var eventName = _step10.value; 12877 this.on(eventName, this.options[eventName]); 12878 } 12879 } catch (err) { 12880 _didIteratorError10 = true; 12881 _iteratorError10 = err; 12882 } finally { 12883 try { 12884 if (!_iteratorNormalCompletion10 && _iterator10["return"] != null) { 12885 _iterator10["return"](); 12886 } 12887 } finally { 12888 if (_didIteratorError10) { 12889 throw _iteratorError10; 12890 } 12891 } 12892 } 12893 12894 this.on("uploadprogress", function () { 12895 return _this3.updateTotalUploadProgress(); 12896 }); 12897 this.on("removedfile", function () { 12898 return _this3.updateTotalUploadProgress(); 12899 }); 12900 this.on("canceled", function (file) { 12901 return _this3.emit("complete", file); 12902 }); // Emit a `queuecomplete` event if all files finished uploading. 12903 12904 this.on("complete", function (file) { 12905 if (_this3.getAddedFiles().length === 0 && _this3.getUploadingFiles().length === 0 && _this3.getQueuedFiles().length === 0) { 12906 // This needs to be deferred so that `queuecomplete` really triggers after `complete` 12907 return setTimeout(function () { 12908 return _this3.emit("queuecomplete"); 12909 }, 0); 12910 } 12911 }); 12912 12913 var containsFiles = function containsFiles(e) { 12914 if (e.dataTransfer.types) { 12915 // Because e.dataTransfer.types is an Object in 12916 // IE, we need to iterate like this instead of 12917 // using e.dataTransfer.types.some() 12918 for (var i = 0; i < e.dataTransfer.types.length; i++) { 12919 if (e.dataTransfer.types[i] === "Files") return true; 12920 } 12921 } 12922 12923 return false; 12924 }; 12925 12926 var noPropagation = function noPropagation(e) { 12927 // If there are no files, we don't want to stop 12928 // propagation so we don't interfere with other 12929 // drag and drop behaviour. 12930 if (!containsFiles(e)) return; 12931 e.stopPropagation(); 12932 12933 if (e.preventDefault) { 12934 return e.preventDefault(); 12935 } else { 12936 return e.returnValue = false; 12937 } 12938 }; // Create the listeners 12939 12940 12941 this.listeners = [{ 12942 element: this.element, 12943 events: { 12944 "dragstart": function dragstart(e) { 12945 return _this3.emit("dragstart", e); 12946 }, 12947 "dragenter": function dragenter(e) { 12948 noPropagation(e); 12949 return _this3.emit("dragenter", e); 12950 }, 12951 "dragover": function dragover(e) { 12952 // Makes it possible to drag files from chrome's download bar 12953 // http://stackoverflow.com/questions/19526430/drag-and-drop-file-uploads-from-chrome-downloads-bar 12954 // Try is required to prevent bug in Internet Explorer 11 (SCRIPT65535 exception) 12955 var efct; 12956 12957 try { 12958 efct = e.dataTransfer.effectAllowed; 12959 } catch (error) {} 12960 12961 e.dataTransfer.dropEffect = 'move' === efct || 'linkMove' === efct ? 'move' : 'copy'; 12962 noPropagation(e); 12963 return _this3.emit("dragover", e); 12964 }, 12965 "dragleave": function dragleave(e) { 12966 return _this3.emit("dragleave", e); 12967 }, 12968 "drop": function drop(e) { 12969 noPropagation(e); 12970 return _this3.drop(e); 12971 }, 12972 "dragend": function dragend(e) { 12973 return _this3.emit("dragend", e); 12974 } 12975 } // This is disabled right now, because the browsers don't implement it properly. 12976 // "paste": (e) => 12977 // noPropagation e 12978 // @paste e 12979 12980 }];
12981 this.clickableElements.forEach(function (clickableElement) { 12982 return _this3.listeners.push({ 12983 element: clickableElement, 12984 events: { 12985 "click": function click(evt) { 12986 // Only the actual dropzone or the message element should trigger file selection 12987 if (clickableElement !== _this3.element || evt.target === _this3.element || Dropzone.elementInside(evt.target, _this3.element.querySelector(".dz-message"))) { 12988 _this3.hiddenFileInput.click(); // Forward the click 12989 12990 } 12991 12992 return true; 12993 } 12994 } 12995 }); 12996 }); 12997 this.enable(); 12998 return this.options.init.call(this); 12999 } // Not fully tested yet 13000 13001 }, { 13002 key: "destroy", 13003 value: function destroy() { 13004 this.disable(); 13005 this.removeAllFiles(true); 13006 13007 if (this.hiddenFileInput != null ? this.hiddenFileInput.parentNode : undefined) { 13008 this.hiddenFileInput.parentNode.removeChild(this.hiddenFileInput); 13009 this.hiddenFileInput = null; 13010 } 13011 13012 delete this.element.dropzone; 13013 return Dropzone.instances.splice(Dropzone.instances.indexOf(this), 1); 13014 } 13015 }, { 13016 key: "updateTotalUploadProgress", 13017 value: function updateTotalUploadProgress() { 13018 var totalUploadProgress; 13019 var totalBytesSent = 0; 13020 var totalBytes = 0; 13021 var activeFiles = this.getActiveFiles(); 13022 13023 if (activeFiles.length) { 13024 var _iteratorNormalCompletion11 = true; 13025 var _didIteratorError11 = false; 13026 var _iteratorError11 = undefined; 13027 13028 try { 13029 for (var _iterator11 = this.getActiveFiles()[Symbol.iterator](), _step11; !(_iteratorNormalCompletion11 = (_step11 = _iterator11.next()).done); _iteratorNormalCompletion11 = true) { 13030 var file = _step11.value; 13031 totalBytesSent += file.upload.bytesSent; 13032 totalBytes += file.upload.total; 13033 } 13034 } catch (err) { 13035 _didIteratorError11 = true; 13036 _iteratorError11 = err; 13037 } finally { 13038 try { 13039 if (!_iteratorNormalCompletion11 && _iterator11["return"] != null) { 13040 _iterator11["return"](); 13041 } 13042 } finally { 13043 if (_didIteratorError11) { 13044 throw _iteratorError11; 13045 } 13046 } 13047 } 13048 13049 totalUploadProgress = 100 * totalBytesSent / totalBytes; 13050 } else { 13051 totalUploadProgress = 100; 13052 } 13053 13054 return this.emit("totaluploadprogress", totalUploadProgress, totalBytes, totalBytesSent); 13055 } // @options.paramName can be a function taking one parameter rather than a string. 13056 // A parameter name for a file is obtained simply by calling this with an index number. 13057 13058 }, { 13059 key: "_getParamName", 13060 value: function _getParamName(n) { 13061 if (typeof this.options.paramName === "function") { 13062 return this.options.paramName(n); 13063 } else { 13064 return "".concat(this.options.paramName).concat(this.options.uploadMultiple ? "[".concat(n, "]") : ""); 13065 } 13066 } // If @options.renameFile is a function, 13067 // the function will be used to rename the file.name before appending it to the formData 13068 13069 }, { 13070 key: "_renameFile", 13071 value: function _renameFile(file) { 13072 if (typeof this.options.renameFile !== "function") { 13073 return file.name; 13074 } 13075 13076 return this.options.renameFile(file); 13077 } // Returns a form that can be used as fallback if the browser does not support DragnDrop 13078 // 13079 // If the dropzone is already a form, only the input field and button are returned. Otherwise a complete form element is provided. 13080 // This code has to pass in IE7 :( 13081 13082 }, { 13083 key: "getFallbackForm", 13084 value: function getFallbackForm() { 13085 var existingFallback, form; 13086 13087 if (existingFallback = this.getExistingFallback()) { 13088 return existingFallback; 13089 } 13090 13091 var fieldsString = "<div class=\"dz-fallback\">"; 13092 13093 if (this.options.dictFallbackText) { 13094 fieldsString += "<p>".concat(this.options.dictFallbackText, "</p>"); 13095 } 13096 13097 fieldsString += "<input type=\"file\" name=\"".concat(this._getParamName(0), "\" ").concat(this.options.uploadMultiple ? 'multiple="multiple"' : undefined, " /><input type=\"submit\" value=\"Upload!\"></div>"); 13098 var fields = Dropzone.createElement(fieldsString); 13099 13100 if (this.element.tagName !== "FORM") { 13101 form = Dropzone.createElement("<form action=\"".concat(this.options.url, "\" enctype=\"multipart/form-data\" method=\"").concat(this.options.method, "\"></form>")); 13102 form.appendChild(fields); 13103 } else { 13104 // Make sure that the enctype and method attributes are set properly 13105 this.element.setAttribute("enctype", "multipart/form-data"); 13106 this.element.setAttribute("method", this.options.method); 13107 } 13108 13109 return form != null ? form : fields; 13110 } // Returns the fallback elements if they exist already 13111 // 13112 // This code has to pass in IE7 :( 13113 13114 }, { 13115 key: "getExistingFallback", 13116 value: function getExistingFallback() { 13117 var getFallback = function getFallback(elements) { 13118 var _iteratorNormalCompletion12 = true; 13119 var _didIteratorError12 = false;
13120 var _iteratorError12 = undefined; 13121 13122 try { 13123 for (var _iterator12 = elements[Symbol.iterator](), _step12; !(_iteratorNormalCompletion12 = (_step12 = _iterator12.next()).done); _iteratorNormalCompletion12 = true) { 13124 var el = _step12.value; 13125 13126 if (/(^| )fallback($| )/.test(el.className)) { 13127 return el; 13128 } 13129 } 13130 } catch (err) { 13131 _didIteratorError12 = true; 13132 _iteratorError12 = err; 13133 } finally { 13134 try { 13135 if (!_iteratorNormalCompletion12 && _iterator12["return"] != null) { 13136 _iterator12["return"](); 13137 } 13138 } finally { 13139 if (_didIteratorError12) { 13140 throw _iteratorError12; 13141 } 13142 } 13143 } 13144 }; 13145 13146 for (var _i2 = 0, _arr = ["div", "form"]; _i2 < _arr.length; _i2++) { 13147 var tagName = _arr[_i2]; 13148 var fallback; 13149 13150 if (fallback = getFallback(this.element.getElementsByTagName(tagName))) { 13151 return fallback; 13152 } 13153 } 13154 } // Activates all listeners stored in @listeners 13155 13156 }, { 13157 key: "setupEventListeners", 13158 value: function setupEventListeners() { 13159 return this.listeners.map(function (elementListeners) { 13160 return function () { 13161 var result = []; 13162 13163 for (var event in elementListeners.events) { 13164 var listener = elementListeners.events[event]; 13165 result.push(elementListeners.element.addEventListener(event, listener, false)); 13166 } 13167 13168 return result; 13169 }(); 13170 }); 13171 } // Deactivates all listeners stored in @listeners 13172 13173 }, { 13174 key: "removeEventListeners", 13175 value: function removeEventListeners() { 13176 return this.listeners.map(function (elementListeners) { 13177 return function () { 13178 var result = []; 13179 13180 for (var event in elementListeners.events) { 13181 var listener = elementListeners.events[event]; 13182 result.push(elementListeners.element.removeEventListener(event, listener, false)); 13183 } 13184 13185 return result; 13186 }(); 13187 }); 13188 } // Removes all event listeners and cancels all files in the queue or being processed. 13189 13190 }, { 13191 key: "disable", 13192 value: function disable() { 13193 var _this4 = this; 13194 13195 this.clickableElements.forEach(function (element) { 13196 return element.classList.remove("dz-clickable"); 13197 }); 13198 this.removeEventListeners(); 13199 this.disabled = true; 13200 return this.files.map(function (file) { 13201 return _this4.cancelUpload(file); 13202 }); 13203 } 13204 }, { 13205 key: "enable", 13206 value: function enable() { 13207 delete this.disabled; 13208 this.clickableElements.forEach(function (element) { 13209 return element.classList.add("dz-clickable"); 13210 }); 13211 return this.setupEventListeners(); 13212 } // Returns a nicely formatted filesize 13213 13214 }, { 13215 key: "filesize", 13216 value: function filesize(size) { 13217 var selectedSize = 0; 13218 var selectedUnit = "b"; 13219 13220 if (size > 0) { 13221 var units = ['tb', 'gb', 'mb', 'kb', 'b']; 13222 13223 for (var i = 0; i < units.length; i++) { 13224 var unit = units[i]; 13225 var cutoff = Math.pow(this.options.filesizeBase, 4 - i) / 10; 13226 13227 if (size >= cutoff) { 13228 selectedSize = size / Math.pow(this.options.filesizeBase, 4 - i); 13229 selectedUnit = unit; 13230 break; 13231 } 13232 } 13233 13234 selectedSize = Math.round(10 * selectedSize) / 10; // Cutting of digits 13235 } 13236 13237 return "<strong>".concat(selectedSize, "</strong> ").concat(this.options.dictFileSizeUnits[selectedUnit]); 13238 } // Adds or removes the `dz-max-files-reached` class from the form. 13239 13240 }, { 13241 key: "_updateMaxFilesReachedClass", 13242 value: function _updateMaxFilesReachedClass() { 13243 if (this.options.maxFiles != null && this.getAcceptedFiles().length >= this.options.maxFiles) { 13244 if (this.getAcceptedFiles().length === this.options.maxFiles) { 13245 this.emit('maxfilesreached', this.files); 13246 } 13247 13248 return this.element.classList.add("dz-max-files-reached"); 13249 } else { 13250 return this.element.classList.remove("dz-max-files-reached"); 13251 } 13252 } 13253 }, { 13254 key: "drop", 13255 value: function drop(e) { 13256 if (!e.dataTransfer) { 13257 return; 13258 } 13259
13260 this.emit("drop", e); // Convert the FileList to an Array 13261 // This is necessary for IE11 13262 13263 var files = []; 13264 13265 for (var i = 0; i < e.dataTransfer.files.length; i++) { 13266 files[i] = e.dataTransfer.files[i]; 13267 } // Even if it's a folder, files.length will contain the folders. 13268 13269 13270 if (files.length) { 13271 var items = e.dataTransfer.items; 13272 13273 if (items && items.length && items[0].webkitGetAsEntry != null) { 13274 // The browser supports dropping of folders, so handle items instead of files 13275 this._addFilesFromItems(items); 13276 } else { 13277 this.handleFiles(files); 13278 } 13279 } 13280 13281 this.emit("addedfiles", files); 13282 } 13283 }, { 13284 key: "paste", 13285 value: function paste(e) { 13286 if (__guard__(e != null ? e.clipboardData : undefined, function (x) { 13287 return x.items; 13288 }) == null) { 13289 return; 13290 } 13291 13292 this.emit("paste", e); 13293 var items = e.clipboardData.items; 13294 13295 if (items.length) { 13296 return this._addFilesFromItems(items); 13297 } 13298 } 13299 }, { 13300 key: "handleFiles", 13301 value: function handleFiles(files) { 13302 var _iteratorNormalCompletion13 = true; 13303 var _didIteratorError13 = false; 13304 var _iteratorError13 = undefined; 13305 13306 try { 13307 for (var _iterator13 = files[Symbol.iterator](), _step13; !(_iteratorNormalCompletion13 = (_step13 = _iterator13.next()).done); _iteratorNormalCompletion13 = true) { 13308 var file = _step13.value; 13309 this.addFile(file); 13310 } 13311 } catch (err) { 13312 _didIteratorError13 = true; 13313 _iteratorError13 = err; 13314 } finally { 13315 try { 13316 if (!_iteratorNormalCompletion13 && _iterator13["return"] != null) { 13317 _iterator13["return"](); 13318 } 13319 } finally { 13320 if (_didIteratorError13) { 13321 throw _iteratorError13; 13322 } 13323 } 13324 } 13325 } // When a folder is dropped (or files are pasted), items must be handled 13326 // instead of files. 13327 13328 }, { 13329 key: "_addFilesFromItems", 13330 value: function _addFilesFromItems(items) { 13331 var _this5 = this; 13332 13333 return function () { 13334 var result = []; 13335 var _iteratorNormalCompletion14 = true; 13336 var _didIteratorError14 = false; 13337 var _iteratorError14 = undefined; 13338 13339 try { 13340 for (var _iterator14 = items[Symbol.iterator](), _step14; !(_iteratorNormalCompletion14 = (_step14 = _iterator14.next()).done); _iteratorNormalCompletion14 = true) { 13341 var item = _step14.value; 13342 var entry; 13343 13344 if (item.webkitGetAsEntry != null && (entry = item.webkitGetAsEntry())) { 13345 if (entry.isFile) { 13346 result.push(_this5.addFile(item.getAsFile())); 13347 } else if (entry.isDirectory) { 13348 // Append all files from that directory to files 13349 result.push(_this5._addFilesFromDirectory(entry, entry.name)); 13350 } else { 13351 result.push(undefined); 13352 } 13353 } else if (item.getAsFile != null) { 13354 if (item.kind == null || item.kind === "file") { 13355 result.push(_this5.addFile(item.getAsFile())); 13356 } else { 13357 result.push(undefined); 13358 } 13359 } else { 13360 result.push(undefined); 13361 } 13362 } 13363 } catch (err) { 13364 _didIteratorError14 = true; 13365 _iteratorError14 = err; 13366 } finally { 13367 try { 13368 if (!_iteratorNormalCompletion14 && _iterator14["return"] != null) { 13369 _iterator14["return"](); 13370 } 13371 } finally { 13372 if (_didIteratorError14) { 13373 throw _iteratorError14; 13374 } 13375 } 13376 } 13377 13378 return result; 13379 }(); 13380 } // Goes through the directory, and adds each file it finds recursively 13381 13382 }, { 13383 key: "_addFilesFromDirectory", 13384 value: function _addFilesFromDirectory(directory, path) { 13385 var _this6 = this; 13386 13387 var dirReader = directory.createReader(); 13388 13389 var errorHandler = function errorHandler(error) { 13390 return __guardMethod__(console, 'log', function (o) { 13391 return o.log(error); 13392 }); 13393 }; 13394 13395 var readEntries = function readEntries() { 13396 return dirReader.readEntries(function (entries) { 13397 if (entries.length > 0) { 13398 var _iteratorNormalCompletion15 = true; 13399 var _didIteratorError15 = false;
13400 var _iteratorError15 = undefined; 13401 13402 try { 13403 for (var _iterator15 = entries[Symbol.iterator](), _step15; !(_iteratorNormalCompletion15 = (_step15 = _iterator15.next()).done); _iteratorNormalCompletion15 = true) { 13404 var entry = _step15.value; 13405 13406 if (entry.isFile) { 13407 entry.file(function (file) { 13408 if (_this6.options.ignoreHiddenFiles && file.name.substring(0, 1) === '.') { 13409 return; 13410 } 13411 13412 file.fullPath = "".concat(path, "/").concat(file.name); 13413 return _this6.addFile(file); 13414 }); 13415 } else if (entry.isDirectory) { 13416 _this6._addFilesFromDirectory(entry, "".concat(path, "/").concat(entry.name)); 13417 } 13418 } // Recursively call readEntries() again, since browser only handle 13419 // the first 100 entries. 13420 // See: https://developer.mozilla.org/en-US/docs/Web/API/DirectoryReader#readEntries 13421 13422 } catch (err) { 13423 _didIteratorError15 = true; 13424 _iteratorError15 = err; 13425 } finally { 13426 try { 13427 if (!_iteratorNormalCompletion15 && _iterator15["return"] != null) { 13428 _iterator15["return"](); 13429 } 13430 } finally { 13431 if (_didIteratorError15) { 13432 throw _iteratorError15; 13433 } 13434 } 13435 } 13436 13437 readEntries(); 13438 } 13439 13440 return null; 13441 }, errorHandler); 13442 }; 13443 13444 return readEntries(); 13445 } // If `done()` is called without argument the file is accepted 13446 // If you call it with an error message, the file is rejected 13447 // (This allows for asynchronous validation) 13448 // 13449 // This function checks the filesize, and if the file.type passes the 13450 // `acceptedFiles` check. 13451 13452 }, { 13453 key: "accept", 13454 value: function accept(file, done) { 13455 if (this.options.maxFilesize && file.size > this.options.maxFilesize * 1024 * 1024) { 13456 done(this.options.dictFileTooBig.replace("{{filesize}}", Math.round(file.size / 1024 / 10.24) / 100).replace("{{maxFilesize}}", this.options.maxFilesize)); 13457 } else if (!Dropzone.isValidFile(file, this.options.acceptedFiles)) { 13458 done(this.options.dictInvalidFileType); 13459 } else if (this.options.maxFiles != null && this.getAcceptedFiles().length >= this.options.maxFiles) { 13460 done(this.options.dictMaxFilesExceeded.replace("{{maxFiles}}", this.options.maxFiles)); 13461 this.emit("maxfilesexceeded", file); 13462 } else { 13463 this.options.accept.call(this, file, done); 13464 } 13465 } 13466 }, { 13467 key: "addFile", 13468 value: function addFile(file) { 13469 var _this7 = this; 13470 13471 file.upload = { 13472 uuid: Dropzone.uuidv4(), 13473 progress: 0, 13474 // Setting the total upload size to file.size for the beginning 13475 // It's actual different than the size to be transmitted. 13476 total: file.size, 13477 bytesSent: 0, 13478 filename: this._renameFile(file) // Not setting chunking information here, because the acutal data â and 13479 // thus the chunks â might change if `options.transformFile` is set 13480 // and does something to the data. 13481 13482 }; 13483 this.files.push(file); 13484 file.status = Dropzone.ADDED; 13485 this.emit("addedfile", file); 13486 13487 this._enqueueThumbnail(file); 13488 13489 this.accept(file, function (error) { 13490 if (error) { 13491 file.accepted = false; 13492 13493 _this7._errorProcessing([file], error); // Will set the file.status 13494 13495 } else { 13496 file.accepted = true; 13497 13498 if (_this7.options.autoQueue) { 13499 _this7.enqueueFile(file); 13500 } // Will set .accepted = true 13501 13502 } 13503 13504 _this7._updateMaxFilesReachedClass(); 13505 }); 13506 } // Wrapper for enqueueFile 13507 13508 }, { 13509 key: "enqueueFiles", 13510 value: function enqueueFiles(files) { 13511 var _iteratorNormalCompletion16 = true; 13512 var _didIteratorError16 = false; 13513 var _iteratorError16 = undefined; 13514
13515 try { 13516 for (var _iterator16 = files[Symbol.iterator](), _step16; !(_iteratorNormalCompletion16 = (_step16 = _iterator16.next()).done); _iteratorNormalCompletion16 = true) { 13517 var file = _step16.value; 13518 this.enqueueFile(file); 13519 } 13520 } catch (err) { 13521 _didIteratorError16 = true; 13522 _iteratorError16 = err; 13523 } finally { 13524 try { 13525 if (!_iteratorNormalCompletion16 && _iterator16["return"] != null) { 13526 _iterator16["return"](); 13527 } 13528 } finally { 13529 if (_didIteratorError16) { 13530 throw _iteratorError16; 13531 } 13532 } 13533 } 13534 13535 return null; 13536 } 13537 }, { 13538 key: "enqueueFile", 13539 value: function enqueueFile(file) { 13540 var _this8 = this; 13541 13542 if (file.status === Dropzone.ADDED && file.accepted === true) { 13543 file.status = Dropzone.QUEUED; 13544 13545 if (this.options.autoProcessQueue) { 13546 return setTimeout(function () { 13547 return _this8.processQueue(); 13548 }, 0); // Deferring the call 13549 } 13550 } else { 13551 throw new Error("This file can't be queued because it has already been processed or was rejected."); 13552 } 13553 } 13554 }, { 13555 key: "_enqueueThumbnail", 13556 value: function _enqueueThumbnail(file) { 13557 var _this9 = this; 13558 13559 if (this.options.createImageThumbnails && file.type.match(/image.*/) && file.size <= this.options.maxThumbnailFilesize * 1024 * 1024) { 13560 this._thumbnailQueue.push(file); 13561 13562 return setTimeout(function () { 13563 return _this9._processThumbnailQueue(); 13564 }, 0); // Deferring the call 13565 } 13566 } 13567 }, { 13568 key: "_processThumbnailQueue", 13569 value: function _processThumbnailQueue() { 13570 var _this10 = this; 13571 13572 if (this._processingThumbnail || this._thumbnailQueue.length === 0) { 13573 return; 13574 } 13575 13576 this._processingThumbnail = true; 13577 13578 var file = this._thumbnailQueue.shift(); 13579 13580 return this.createThumbnail(file, this.options.thumbnailWidth, this.options.thumbnailHeight, this.options.thumbnailMethod, true, function (dataUrl) { 13581 _this10.emit("thumbnail", file, dataUrl); 13582 13583 _this10._processingThumbnail = false; 13584 return _this10._processThumbnailQueue(); 13585 }); 13586 } // Can be called by the user to remove a file 13587 13588 }, { 13589 key: "removeFile", 13590 value: function removeFile(file) { 13591 if (file.status === Dropzone.UPLOADING) { 13592 this.cancelUpload(file); 13593 } 13594 13595 this.files = without(this.files, file); 13596 this.emit("removedfile", file); 13597 13598 if (this.files.length === 0) { 13599 return this.emit("reset"); 13600 } 13601 } // Removes all files that aren't currently processed from the list 13602 13603 }, { 13604 key: "removeAllFiles", 13605 value: function removeAllFiles(cancelIfNecessary) { 13606 // Create a copy of files since removeFile() changes the @files array. 13607 if (cancelIfNecessary == null) { 13608 cancelIfNecessary = false; 13609 } 13610 13611 var _iteratorNormalCompletion17 = true; 13612 var _didIteratorError17 = false; 13613 var _iteratorError17 = undefined; 13614 13615 try { 13616 for (var _iterator17 = this.files.slice()[Symbol.iterator](), _step17; !(_iteratorNormalCompletion17 = (_step17 = _iterator17.next()).done); _iteratorNormalCompletion17 = true) { 13617 var file = _step17.value; 13618 13619 if (file.status !== Dropzone.UPLOADING || cancelIfNecessary) { 13620 this.removeFile(file); 13621 } 13622 } 13623 } catch (err) { 13624 _didIteratorError17 = true; 13625 _iteratorError17 = err; 13626 } finally { 13627 try { 13628 if (!_iteratorNormalCompletion17 && _iterator17["return"] != null) { 13629 _iterator17["return"](); 13630 } 13631 } finally { 13632 if (_didIteratorError17) { 13633 throw _iteratorError17; 13634 } 13635 } 13636 } 13637 13638 return null; 13639 } // Resizes an image before it gets sent to the server. This function is the default behavior of 13640 // `options.transformFile` if `resizeWidth` or `resizeHeight` are set. The callback is invoked with 13641 // the resized blob. 13642 13643 }, { 13644 key: "resizeImage", 13645 value: function resizeImage(file, width, height, resizeMethod, callback) { 13646 var _this11 = this; 13647 13648 return this.createThumbnail(file, width, height, resizeMethod, true, function (dataUrl, canvas) { 13649 if (canvas == null) { 13650 // The image has not been resized 13651 return callback(file); 13652 } else { 13653 var resizeMimeType = _this11.options.resizeMimeType; 13654 13655 if (resizeMimeType == null) { 13656 resizeMimeType = file.type; 13657 } 13658 13659 var resizedDataURL = canvas.toDataURL(resizeMimeType, _this11.options.resizeQuality); 13660 13661 if (resizeMimeType === 'image/jpeg' || resizeMimeType === 'image/jpg') { 13662 // Now add the original EXIF information 13663 resizedDataURL = ExifRestore.restore(file.dataURL, resizedDataURL); 13664 } 13665 13666 return callback(Dropzone.dataURItoBlob(resizedDataURL)); 13667 } 13668 }); 13669 } 13670 }, { 13671 key: "createThumbnail", 13672 value: function createThumbnail(file, width, height, resizeMethod, fixOrientation, callback) { 13673 var _this12 = this; 13674 13675 var fileReader = new FileReader(); 13676 13677 fileReader.onload = function () { 13678 file.dataURL = fileReader.result; // Don't bother creating a thumbnail for SVG images since they're vector 13679 13680 if (file.type === "image/svg+xml") { 13681 if (callback != null) { 13682 callback(fileReader.result); 13683 } 13684 13685 return; 13686 } 13687 13688 _this12.createThumbnailFromUrl(file, width, height, resizeMethod, fixOrientation, callback); 13689 }; 13690
vendor: 5,819 bytes, lines 13691-13869
13691 fileReader.readAsDataURL(file); 13692 } // `mockFile` needs to have these attributes: 13693 // 13694 // { name: 'name', size: 12345, imageUrl: '' } 13695 // 13696 // `callback` will be invoked when the image has been downloaded and displayed. 13697 // `crossOrigin` will be added to the `img` tag when accessing the file. 13698 13699 }, { 13700 key: "displayExistingFile", 13701 value: function displayExistingFile(mockFile, imageUrl, callback, crossOrigin) { 13702 var _this13 = this; 13703 13704 var resizeThumbnail = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : true; 13705 this.emit("addedfile", mockFile); 13706 this.emit("complete", mockFile); 13707 13708 if (!resizeThumbnail) { 13709 this.emit("thumbnail", mockFile, imageUrl); 13710 if (callback) callback(); 13711 } else { 13712 var onDone = function onDone(thumbnail) { 13713 _this13.emit('thumbnail', mockFile, thumbnail); 13714 13715 if (callback) callback(); 13716 }; 13717 13718 mockFile.dataURL = imageUrl; 13719 this.createThumbnailFromUrl(mockFile, this.options.thumbnailWidth, this.options.thumbnailHeight, this.options.resizeMethod, this.options.fixOrientation, onDone, crossOrigin); 13720 } 13721 } 13722 }, { 13723 key: "createThumbnailFromUrl", 13724 value: function createThumbnailFromUrl(file, width, height, resizeMethod, fixOrientation, callback, crossOrigin) { 13725 var _this14 = this; 13726 13727 // Not using `new Image` here because of a bug in latest Chrome versions. 13728 // See https://github.com/enyo/dropzone/pull/226 13729 var img = document.createElement("img"); 13730 13731 if (crossOrigin) { 13732 img.crossOrigin = crossOrigin; 13733 } 13734 13735 img.onload = function () { 13736 var loadExif = function loadExif(callback) { 13737 return callback(1); 13738 }; 13739 13740 if (typeof EXIF !== 'undefined' && EXIF !== null && fixOrientation) { 13741 loadExif = function loadExif(callback) { 13742 return EXIF.getData(img, function () { 13743 return callback(EXIF.getTag(this, 'Orientation')); 13744 }); 13745 }; 13746 } 13747 13748 return loadExif(function (orientation) { 13749 file.width = img.width; 13750 file.height = img.height; 13751 13752 var resizeInfo = _this14.options.resize.call(_this14, file, width, height, resizeMethod); 13753 13754 var canvas = document.createElement("canvas"); 13755 var ctx = canvas.getContext("2d"); 13756 canvas.width = resizeInfo.trgWidth; 13757 canvas.height = resizeInfo.trgHeight; 13758 13759 if (orientation > 4) { 13760 canvas.width = resizeInfo.trgHeight; 13761 canvas.height = resizeInfo.trgWidth; 13762 } 13763 13764 switch (orientation) { 13765 case 2: 13766 // horizontal flip 13767 ctx.translate(canvas.width, 0); 13768 ctx.scale(-1, 1); 13769 break; 13770 13771 case 3: 13772 // 180° rotate left 13773 ctx.translate(canvas.width, canvas.height); 13774 ctx.rotate(Math.PI); 13775 break; 13776 13777 case 4: 13778 // vertical flip 13779 ctx.translate(0, canvas.height); 13780 ctx.scale(1, -1); 13781 break; 13782 13783 case 5: 13784 // vertical flip + 90 rotate right 13785 ctx.rotate(0.5 * Math.PI); 13786 ctx.scale(1, -1); 13787 break; 13788 13789 case 6: 13790 // 90° rotate right 13791 ctx.rotate(0.5 * Math.PI); 13792 ctx.translate(0, -canvas.width); 13793 break; 13794 13795 case 7: 13796 // horizontal flip + 90 rotate right 13797 ctx.rotate(0.5 * Math.PI); 13798 ctx.translate(canvas.height, -canvas.width); 13799 ctx.scale(-1, 1); 13800 break; 13801 13802 case 8: 13803 // 90° rotate left 13804 ctx.rotate(-0.5 * Math.PI); 13805 ctx.translate(-canvas.height, 0); 13806 break; 13807 } // This is a bugfix for iOS' scaling bug. 13808 13809 13810 drawImageIOSFix(ctx, img, resizeInfo.srcX != null ? resizeInfo.srcX : 0, resizeInfo.srcY != null ? resizeInfo.srcY : 0, resizeInfo.srcWidth, resizeInfo.srcHeight, resizeInfo.trgX != null ? resizeInfo.trgX : 0, resizeInfo.trgY != null ? resizeInfo.trgY : 0, resizeInfo.trgWidth, resizeInfo.trgHeight); 13811 var thumbnail = canvas.toDataURL("image/png"); 13812 13813 if (callback != null) { 13814 return callback(thumbnail, canvas); 13815 } 13816 }); 13817 }; 13818 13819 if (callback != null) { 13820 img.onerror = callback; 13821 } 13822 13823 return img.src = file.dataURL; 13824 } // Goes through the queue and processes files if there aren't too many already. 13825 13826 }, { 13827 key: "processQueue", 13828 value: function processQueue() { 13829 var parallelUploads = this.options.parallelUploads; 13830 var processingLength = this.getUploadingFiles().length; 13831 var i = processingLength; // There are already at least as many files uploading than should be 13832 13833 if (processingLength >= parallelUploads) { 13834 return; 13835 } 13836 13837 var queuedFiles = this.getQueuedFiles(); 13838 13839 if (!(queuedFiles.length > 0)) { 13840 return; 13841 } 13842 13843 if (this.options.uploadMultiple) { 13844 // The files should be uploaded in one request 13845 return this.processFiles(queuedFiles.slice(0, parallelUploads - processingLength)); 13846 } else { 13847 while (i < parallelUploads) { 13848 if (!queuedFiles.length) { 13849 return; 13850 } // Nothing left to process 13851 13852 13853 this.processFile(queuedFiles.shift()); 13854 i++; 13855 } 13856 } 13857 } // Wrapper for `processFiles` 13858 13859 }, { 13860 key: "processFile", 13861 value: function processFile(file) { 13862 return this.processFiles([file]); 13863 } // Loads the file, then calls finishedLoading() 13864 13865 }, { 13866 key: "processFiles", 13867 value: function processFiles(files) { 13868 var _iteratorNormalCompletion18 = true; 13869 var _didIteratorError18 = false;
13870 var _iteratorError18 = undefined; 13871 13872 try { 13873 for (var _iterator18 = files[Symbol.iterator](), _step18; !(_iteratorNormalCompletion18 = (_step18 = _iterator18.next()).done); _iteratorNormalCompletion18 = true) { 13874 var file = _step18.value; 13875 file.processing = true; // Backwards compatibility 13876 13877 file.status = Dropzone.UPLOADING; 13878 this.emit("processing", file); 13879 } 13880 } catch (err) { 13881 _didIteratorError18 = true; 13882 _iteratorError18 = err; 13883 } finally { 13884 try { 13885 if (!_iteratorNormalCompletion18 && _iterator18["return"] != null) { 13886 _iterator18["return"](); 13887 } 13888 } finally { 13889 if (_didIteratorError18) { 13890 throw _iteratorError18; 13891 } 13892 } 13893 } 13894 13895 if (this.options.uploadMultiple) { 13896 this.emit("processingmultiple", files); 13897 } 13898 13899 return this.uploadFiles(files); 13900 } 13901 }, { 13902 key: "_getFilesWithXhr", 13903 value: function _getFilesWithXhr(xhr) { 13904 var files; 13905 return files = this.files.filter(function (file) { 13906 return file.xhr === xhr; 13907 }).map(function (file) { 13908 return file; 13909 }); 13910 } // Cancels the file upload and sets the status to CANCELED 13911 // **if** the file is actually being uploaded. 13912 // If it's still in the queue, the file is being removed from it and the status 13913 // set to CANCELED. 13914 13915 }, { 13916 key: "cancelUpload", 13917 value: function cancelUpload(file) { 13918 if (file.status === Dropzone.UPLOADING) { 13919 var groupedFiles = this._getFilesWithXhr(file.xhr); 13920 13921 var _iteratorNormalCompletion19 = true; 13922 var _didIteratorError19 = false; 13923 var _iteratorError19 = undefined; 13924 13925 try { 13926 for (var _iterator19 = groupedFiles[Symbol.iterator](), _step19; !(_iteratorNormalCompletion19 = (_step19 = _iterator19.next()).done); _iteratorNormalCompletion19 = true) { 13927 var groupedFile = _step19.value; 13928 groupedFile.status = Dropzone.CANCELED; 13929 } 13930 } catch (err) { 13931 _didIteratorError19 = true; 13932 _iteratorError19 = err; 13933 } finally { 13934 try { 13935 if (!_iteratorNormalCompletion19 && _iterator19["return"] != null) { 13936 _iterator19["return"](); 13937 } 13938 } finally { 13939 if (_didIteratorError19) { 13940 throw _iteratorError19; 13941 } 13942 } 13943 } 13944 13945 if (typeof file.xhr !== 'undefined') { 13946 file.xhr.abort(); 13947 } 13948 13949 var _iteratorNormalCompletion20 = true; 13950 var _didIteratorError20 = false; 13951 var _iteratorError20 = undefined; 13952 13953 try { 13954 for (var _iterator20 = groupedFiles[Symbol.iterator](), _step20; !(_iteratorNormalCompletion20 = (_step20 = _iterator20.next()).done); _iteratorNormalCompletion20 = true) { 13955 var _groupedFile = _step20.value; 13956 this.emit("canceled", _groupedFile); 13957 } 13958 } catch (err) { 13959 _didIteratorError20 = true; 13960 _iteratorError20 = err; 13961 } finally { 13962 try { 13963 if (!_iteratorNormalCompletion20 && _iterator20["return"] != null) { 13964 _iterator20["return"](); 13965 } 13966 } finally { 13967 if (_didIteratorError20) { 13968 throw _iteratorError20; 13969 } 13970 } 13971 } 13972 13973 if (this.options.uploadMultiple) { 13974 this.emit("canceledmultiple", groupedFiles); 13975 } 13976 } else if (file.status === Dropzone.ADDED || file.status === Dropzone.QUEUED) { 13977 file.status = Dropzone.CANCELED; 13978 this.emit("canceled", file); 13979 13980 if (this.options.uploadMultiple) { 13981 this.emit("canceledmultiple", [file]); 13982 } 13983 } 13984 13985 if (this.options.autoProcessQueue) { 13986 return this.processQueue(); 13987 } 13988 } 13989 }, { 13990 key: "resolveOption", 13991 value: function resolveOption(option) { 13992 if (typeof option === 'function') { 13993 for (var _len3 = arguments.length, args = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) { 13994 args[_key3 - 1] = arguments[_key3]; 13995 } 13996 13997 return option.apply(this, args); 13998 } 13999 14000 return option; 14001 } 14002 }, { 14003 key: "uploadFile", 14004 value: function uploadFile(file) { 14005 return this.uploadFiles([file]); 14006 } 14007 }, { 14008 key: "uploadFiles", 14009 value: function uploadFiles(files) { 14010 var _this15 = this; 14011 14012 this._transformFiles(files, function (transformedFiles) { 14013 if (_this15.options.chunking) { 14014 // Chunking is not allowed to be used with `uploadMultiple` so we know 14015 // that there is only __one__file. 14016 var transformedFile = transformedFiles[0]; 14017 files[0].upload.chunked = _this15.options.chunking && (_this15.options.forceChunking || transformedFile.size > _this15.options.chunkSize);
vendor: 4,150 bytes, lines 14018-14130
14018 files[0].upload.totalChunkCount = Math.ceil(transformedFile.size / _this15.options.chunkSize); 14019 } 14020 14021 if (files[0].upload.chunked) { 14022 // This file should be sent in chunks! 14023 // If the chunking option is set, we **know** that there can only be **one** file, since 14024 // uploadMultiple is not allowed with this option. 14025 var file = files[0]; 14026 var _transformedFile = transformedFiles[0]; 14027 var startedChunkCount = 0; 14028 file.upload.chunks = []; 14029 14030 var handleNextChunk = function handleNextChunk() { 14031 var chunkIndex = 0; // Find the next item in file.upload.chunks that is not defined yet. 14032 14033 while (file.upload.chunks[chunkIndex] !== undefined) { 14034 chunkIndex++; 14035 } // This means, that all chunks have already been started. 14036 14037 14038 if (chunkIndex >= file.upload.totalChunkCount) return; 14039 startedChunkCount++; 14040 var start = chunkIndex * _this15.options.chunkSize; 14041 var end = Math.min(start + _this15.options.chunkSize, file.size); 14042 var dataBlock = { 14043 name: _this15._getParamName(0), 14044 data: _transformedFile.webkitSlice ? _transformedFile.webkitSlice(start, end) : _transformedFile.slice(start, end), 14045 filename: file.upload.filename, 14046 chunkIndex: chunkIndex 14047 }; 14048 file.upload.chunks[chunkIndex] = { 14049 file: file, 14050 index: chunkIndex, 14051 dataBlock: dataBlock, 14052 // In case we want to retry. 14053 status: Dropzone.UPLOADING, 14054 progress: 0, 14055 retries: 0 // The number of times this block has been retried. 14056 14057 }; 14058 14059 _this15._uploadData(files, [dataBlock]); 14060 }; 14061 14062 file.upload.finishedChunkUpload = function (chunk) { 14063 var allFinished = true; 14064 chunk.status = Dropzone.SUCCESS; // Clear the data from the chunk 14065 14066 chunk.dataBlock = null; // Leaving this reference to xhr intact here will cause memory leaks in some browsers 14067 14068 chunk.xhr = null; 14069 14070 for (var i = 0; i < file.upload.totalChunkCount; i++) { 14071 if (file.upload.chunks[i] === undefined) { 14072 return handleNextChunk(); 14073 } 14074 14075 if (file.upload.chunks[i].status !== Dropzone.SUCCESS) { 14076 allFinished = false; 14077 } 14078 } 14079 14080 if (allFinished) { 14081 _this15.options.chunksUploaded(file, function () { 14082 _this15._finished(files, '', null); 14083 }); 14084 } 14085 }; 14086 14087 if (_this15.options.parallelChunkUploads) { 14088 for (var i = 0; i < file.upload.totalChunkCount; i++) { 14089 handleNextChunk(); 14090 } 14091 } else { 14092 handleNextChunk(); 14093 } 14094 } else { 14095 var dataBlocks = []; 14096 14097 for (var _i3 = 0; _i3 < files.length; _i3++) { 14098 dataBlocks[_i3] = { 14099 name: _this15._getParamName(_i3), 14100 data: transformedFiles[_i3], 14101 filename: files[_i3].upload.filename 14102 }; 14103 } 14104 14105 _this15._uploadData(files, dataBlocks); 14106 } 14107 }); 14108 } /// Returns the right chunk for given file and xhr 14109 14110 }, { 14111 key: "_getChunk", 14112 value: function _getChunk(file, xhr) { 14113 for (var i = 0; i < file.upload.totalChunkCount; i++) { 14114 if (file.upload.chunks[i] !== undefined && file.upload.chunks[i].xhr === xhr) { 14115 return file.upload.chunks[i]; 14116 } 14117 } 14118 } // This function actually uploads the file(s) to the server. 14119 // If dataBlocks contains the actual data to upload (meaning, that this could either be transformed 14120 // files, or individual chunks for chunked upload). 14121 14122 }, { 14123 key: "_uploadData", 14124 value: function _uploadData(files, dataBlocks) { 14125 var _this16 = this; 14126 14127 var xhr = new XMLHttpRequest(); // Put the xhr object in the file objects to be able to reference it later. 14128 14129 var _iteratorNormalCompletion21 = true; 14130 var _didIteratorError21 = false;
14131 var _iteratorError21 = undefined; 14132 14133 try { 14134 for (var _iterator21 = files[Symbol.iterator](), _step21; !(_iteratorNormalCompletion21 = (_step21 = _iterator21.next()).done); _iteratorNormalCompletion21 = true) { 14135 var file = _step21.value; 14136 file.xhr = xhr; 14137 } 14138 } catch (err) { 14139 _didIteratorError21 = true; 14140 _iteratorError21 = err; 14141 } finally { 14142 try { 14143 if (!_iteratorNormalCompletion21 && _iterator21["return"] != null) { 14144 _iterator21["return"](); 14145 } 14146 } finally { 14147 if (_didIteratorError21) { 14148 throw _iteratorError21; 14149 } 14150 } 14151 } 14152 14153 if (files[0].upload.chunked) { 14154 // Put the xhr object in the right chunk object, so it can be associated later, and found with _getChunk 14155 files[0].upload.chunks[dataBlocks[0].chunkIndex].xhr = xhr; 14156 } 14157 14158 var method = this.resolveOption(this.options.method, files); 14159 var url = this.resolveOption(this.options.url, files); 14160 xhr.open(method, url, true); // Setting the timeout after open because of IE11 issue: https://gitlab.com/meno/dropzone/issues/8 14161 14162 xhr.timeout = this.resolveOption(this.options.timeout, files); // Has to be after `.open()`. See https://github.com/enyo/dropzone/issues/179 14163 14164 xhr.withCredentials = !!this.options.withCredentials; 14165 14166 xhr.onload = function (e) { 14167 _this16._finishedUploading(files, xhr, e); 14168 }; 14169 14170 xhr.ontimeout = function () { 14171 _this16._handleUploadError(files, xhr, "Request timedout after ".concat(_this16.options.timeout, " seconds")); 14172 }; 14173 14174 xhr.onerror = function () { 14175 _this16._handleUploadError(files, xhr); 14176 }; // Some browsers do not have the .upload property 14177 14178 14179 var progressObj = xhr.upload != null ? xhr.upload : xhr; 14180 14181 progressObj.onprogress = function (e) { 14182 return _this16._updateFilesUploadProgress(files, xhr, e); 14183 }; 14184 14185 var headers = { 14186 "Accept": "application/json", 14187 "Cache-Control": "no-cache", 14188 "X-Requested-With": "XMLHttpRequest" 14189 }; 14190 14191 if (this.options.headers) { 14192 Dropzone.extend(headers, this.options.headers); 14193 } 14194 14195 for (var headerName in headers) { 14196 var headerValue = headers[headerName]; 14197 14198 if (headerValue) { 14199 xhr.setRequestHeader(headerName, headerValue); 14200 } 14201 } 14202 14203 var formData = new FormData(); // Adding all @options parameters 14204 14205 if (this.options.params) { 14206 var additionalParams = this.options.params; 14207 14208 if (typeof additionalParams === 'function') { 14209 additionalParams = additionalParams.call(this, files, xhr, files[0].upload.chunked ? this._getChunk(files[0], xhr) : null); 14210 } 14211 14212 for (var key in additionalParams) { 14213 var value = additionalParams[key]; 14214 formData.append(key, value); 14215 } 14216 } // Let the user add additional data if necessary 14217 14218 14219 var _iteratorNormalCompletion22 = true; 14220 var _didIteratorError22 = false; 14221 var _iteratorError22 = undefined; 14222 14223 try { 14224 for (var _iterator22 = files[Symbol.iterator](), _step22; !(_iteratorNormalCompletion22 = (_step22 = _iterator22.next()).done); _iteratorNormalCompletion22 = true) { 14225 var _file = _step22.value; 14226 this.emit("sending", _file, xhr, formData); 14227 } 14228 } catch (err) { 14229 _didIteratorError22 = true; 14230 _iteratorError22 = err; 14231 } finally { 14232 try { 14233 if (!_iteratorNormalCompletion22 && _iterator22["return"] != null) { 14234 _iterator22["return"](); 14235 } 14236 } finally { 14237 if (_didIteratorError22) { 14238 throw _iteratorError22; 14239 } 14240 } 14241 } 14242 14243 if (this.options.uploadMultiple) { 14244 this.emit("sendingmultiple", files, xhr, formData); 14245 } 14246 14247 this._addFormElementData(formData); // Finally add the files 14248 // Has to be last because some servers (eg: S3) expect the file to be the last parameter 14249 14250 14251 for (var i = 0; i < dataBlocks.length; i++) { 14252 var dataBlock = dataBlocks[i]; 14253 formData.append(dataBlock.name, dataBlock.data, dataBlock.filename); 14254 } 14255 14256 this.submitRequest(xhr, formData, files); 14257 } // Transforms all files with this.options.transformFile and invokes done with the transformed files when done. 14258 14259 }, { 14260 key: "_transformFiles", 14261 value: function _transformFiles(files, done) { 14262 var _this17 = this; 14263 14264 var transformedFiles = []; // Clumsy way of handling asynchronous calls, until I get to add a proper Future library. 14265 14266 var doneCounter = 0; 14267 14268 var _loop = function _loop(i) { 14269 _this17.options.transformFile.call(_this17, files[i], function (transformedFile) { 14270 transformedFiles[i] = transformedFile; 14271 14272 if (++doneCounter === files.length) { 14273 done(transformedFiles); 14274 } 14275 }); 14276 }; 14277 14278 for (var i = 0; i < files.length; i++) { 14279 _loop(i); 14280 } 14281 } // Takes care of adding other input elements of the form to the AJAX request 14282 14283 }, { 14284 key: "_addFormElementData", 14285 value: function _addFormElementData(formData) { 14286 // Take care of other input elements 14287 if (this.element.tagName === "FORM") { 14288 var _iteratorNormalCompletion23 = true; 14289 var _didIteratorError23 = false;
14290 var _iteratorError23 = undefined; 14291 14292 try { 14293 for (var _iterator23 = this.element.querySelectorAll("input, textarea, select, button")[Symbol.iterator](), _step23; !(_iteratorNormalCompletion23 = (_step23 = _iterator23.next()).done); _iteratorNormalCompletion23 = true) { 14294 var input = _step23.value; 14295 var inputName = input.getAttribute("name"); 14296 var inputType = input.getAttribute("type"); 14297 if (inputType) inputType = inputType.toLowerCase(); // If the input doesn't have a name, we can't use it. 14298 14299 if (typeof inputName === 'undefined' || inputName === null) continue; 14300 14301 if (input.tagName === "SELECT" && input.hasAttribute("multiple")) { 14302 // Possibly multiple values 14303 var _iteratorNormalCompletion24 = true; 14304 var _didIteratorError24 = false; 14305 var _iteratorError24 = undefined; 14306 14307 try { 14308 for (var _iterator24 = input.options[Symbol.iterator](), _step24; !(_iteratorNormalCompletion24 = (_step24 = _iterator24.next()).done); _iteratorNormalCompletion24 = true) { 14309 var option = _step24.value; 14310 14311 if (option.selected) { 14312 formData.append(inputName, option.value); 14313 } 14314 } 14315 } catch (err) { 14316 _didIteratorError24 = true; 14317 _iteratorError24 = err; 14318 } finally { 14319 try { 14320 if (!_iteratorNormalCompletion24 && _iterator24["return"] != null) { 14321 _iterator24["return"](); 14322 } 14323 } finally { 14324 if (_didIteratorError24) { 14325 throw _iteratorError24; 14326 } 14327 } 14328 } 14329 } else if (!inputType || inputType !== "checkbox" && inputType !== "radio" || input.checked) { 14330 formData.append(inputName, input.value); 14331 } 14332 } 14333 } catch (err) { 14334 _didIteratorError23 = true; 14335 _iteratorError23 = err; 14336 } finally { 14337 try { 14338 if (!_iteratorNormalCompletion23 && _iterator23["return"] != null) { 14339 _iterator23["return"](); 14340 } 14341 } finally { 14342 if (_didIteratorError23) { 14343 throw _iteratorError23; 14344 } 14345 } 14346 } 14347 } 14348 } // Invoked when there is new progress information about given files. 14349 // If e is not provided, it is assumed that the upload is finished. 14350 14351 }, { 14352 key: "_updateFilesUploadProgress", 14353 value: function _updateFilesUploadProgress(files, xhr, e) { 14354 var progress; 14355 14356 if (typeof e !== 'undefined') { 14357 progress = 100 * e.loaded / e.total; 14358 14359 if (files[0].upload.chunked) { 14360 var file = files[0]; // Since this is a chunked upload, we need to update the appropriate chunk progress. 14361 14362 var chunk = this._getChunk(file, xhr); 14363 14364 chunk.progress = progress; 14365 chunk.total = e.total; 14366 chunk.bytesSent = e.loaded; 14367 var fileProgress = 0, 14368 fileTotal, 14369 fileBytesSent; 14370 file.upload.progress = 0; 14371 file.upload.total = 0; 14372 file.upload.bytesSent = 0; 14373 14374 for (var i = 0; i < file.upload.totalChunkCount; i++) { 14375 if (file.upload.chunks[i] !== undefined && file.upload.chunks[i].progress !== undefined) { 14376 file.upload.progress += file.upload.chunks[i].progress; 14377 file.upload.total += file.upload.chunks[i].total; 14378 file.upload.bytesSent += file.upload.chunks[i].bytesSent; 14379 } 14380 } 14381 14382 file.upload.progress = file.upload.progress / file.upload.totalChunkCount; 14383 } else { 14384 var _iteratorNormalCompletion25 = true; 14385 var _didIteratorError25 = false; 14386 var _iteratorError25 = undefined; 14387 14388 try { 14389 for (var _iterator25 = files[Symbol.iterator](), _step25; !(_iteratorNormalCompletion25 = (_step25 = _iterator25.next()).done); _iteratorNormalCompletion25 = true) { 14390 var _file2 = _step25.value; 14391 _file2.upload.progress = progress; 14392 _file2.upload.total = e.total;
14393 _file2.upload.bytesSent = e.loaded; 14394 } 14395 } catch (err) { 14396 _didIteratorError25 = true; 14397 _iteratorError25 = err; 14398 } finally { 14399 try { 14400 if (!_iteratorNormalCompletion25 && _iterator25["return"] != null) { 14401 _iterator25["return"](); 14402 } 14403 } finally { 14404 if (_didIteratorError25) { 14405 throw _iteratorError25; 14406 } 14407 } 14408 } 14409 } 14410 14411 var _iteratorNormalCompletion26 = true; 14412 var _didIteratorError26 = false; 14413 var _iteratorError26 = undefined; 14414 14415 try { 14416 for (var _iterator26 = files[Symbol.iterator](), _step26; !(_iteratorNormalCompletion26 = (_step26 = _iterator26.next()).done); _iteratorNormalCompletion26 = true) { 14417 var _file3 = _step26.value; 14418 this.emit("uploadprogress", _file3, _file3.upload.progress, _file3.upload.bytesSent); 14419 } 14420 } catch (err) { 14421 _didIteratorError26 = true; 14422 _iteratorError26 = err; 14423 } finally { 14424 try { 14425 if (!_iteratorNormalCompletion26 && _iterator26["return"] != null) { 14426 _iterator26["return"](); 14427 } 14428 } finally { 14429 if (_didIteratorError26) { 14430 throw _iteratorError26; 14431 } 14432 } 14433 } 14434 } else { 14435 // Called when the file finished uploading 14436 var allFilesFinished = true; 14437 progress = 100; 14438 var _iteratorNormalCompletion27 = true; 14439 var _didIteratorError27 = false; 14440 var _iteratorError27 = undefined; 14441 14442 try { 14443 for (var _iterator27 = files[Symbol.iterator](), _step27; !(_iteratorNormalCompletion27 = (_step27 = _iterator27.next()).done); _iteratorNormalCompletion27 = true) { 14444 var _file4 = _step27.value; 14445 14446 if (_file4.upload.progress !== 100 || _file4.upload.bytesSent !== _file4.upload.total) { 14447 allFilesFinished = false; 14448 } 14449 14450 _file4.upload.progress = progress; 14451 _file4.upload.bytesSent = _file4.upload.total; 14452 } // Nothing to do, all files already at 100% 14453 14454 } catch (err) { 14455 _didIteratorError27 = true; 14456 _iteratorError27 = err; 14457 } finally { 14458 try { 14459 if (!_iteratorNormalCompletion27 && _iterator27["return"] != null) { 14460 _iterator27["return"](); 14461 } 14462 } finally { 14463 if (_didIteratorError27) { 14464 throw _iteratorError27; 14465 } 14466 } 14467 } 14468 14469 if (allFilesFinished) { 14470 return; 14471 } 14472 14473 var _iteratorNormalCompletion28 = true; 14474 var _didIteratorError28 = false; 14475 var _iteratorError28 = undefined; 14476 14477 try { 14478 for (var _iterator28 = files[Symbol.iterator](), _step28; !(_iteratorNormalCompletion28 = (_step28 = _iterator28.next()).done); _iteratorNormalCompletion28 = true) { 14479 var _file5 = _step28.value; 14480 this.emit("uploadprogress", _file5, progress, _file5.upload.bytesSent); 14481 } 14482 } catch (err) { 14483 _didIteratorError28 = true; 14484 _iteratorError28 = err; 14485 } finally { 14486 try { 14487 if (!_iteratorNormalCompletion28 && _iterator28["return"] != null) { 14488 _iterator28["return"](); 14489 } 14490 } finally { 14491 if (_didIteratorError28) { 14492 throw _iteratorError28; 14493 } 14494 } 14495 } 14496 } 14497 } 14498 }, { 14499 key: "_finishedUploading", 14500 value: function _finishedUploading(files, xhr, e) { 14501 var response; 14502 14503 if (files[0].status === Dropzone.CANCELED) { 14504 return; 14505 } 14506 14507 if (xhr.readyState !== 4) { 14508 return; 14509 } 14510 14511 if (xhr.responseType !== 'arraybuffer' && xhr.responseType !== 'blob') { 14512 response = xhr.responseText; 14513 14514 if (xhr.getResponseHeader("content-type") && ~xhr.getResponseHeader("content-type").indexOf("application/json")) { 14515 try { 14516 response = JSON.parse(response); 14517 } catch (error) { 14518 e = error; 14519 response = "Invalid JSON response from server."; 14520 } 14521 } 14522 } 14523 14524 this._updateFilesUploadProgress(files); 14525 14526 if (!(200 <= xhr.status && xhr.status < 300)) { 14527 this._handleUploadError(files, xhr, response); 14528 } else { 14529 if (files[0].upload.chunked) { 14530 files[0].upload.finishedChunkUpload(this._getChunk(files[0], xhr)); 14531 } else { 14532 this._finished(files, response, e); 14533 } 14534 } 14535 } 14536 }, { 14537 key: "_handleUploadError", 14538 value: function _handleUploadError(files, xhr, response) { 14539 if (files[0].status === Dropzone.CANCELED) { 14540 return; 14541 } 14542 14543 if (files[0].upload.chunked && this.options.retryChunks) { 14544 var chunk = this._getChunk(files[0], xhr); 14545 14546 if (chunk.retries++ < this.options.retryChunksLimit) { 14547 this._uploadData(files, [chunk.dataBlock]); 14548 14549 return; 14550 } else { 14551 console.warn('Retried this chunk too often. Giving up.'); 14552 } 14553 } 14554 14555 this._errorProcessing(files, response || this.options.dictResponseError.replace("{{statusCode}}", xhr.status), xhr); 14556 } 14557 }, { 14558 key: "submitRequest", 14559 value: function submitRequest(xhr, formData, files) { 14560 xhr.send(formData); 14561 }
14561 // Called internally when processing is finished. 14562 // Individual callbacks have to be called in the appropriate sections. 14563 14564 }, { 14565 key: "_finished", 14566 value: function _finished(files, responseText, e) { 14567 var _iteratorNormalCompletion29 = true; 14568 var _didIteratorError29 = false; 14569 var _iteratorError29 = undefined; 14570 14571 try { 14572 for (var _iterator29 = files[Symbol.iterator](), _step29; !(_iteratorNormalCompletion29 = (_step29 = _iterator29.next()).done); _iteratorNormalCompletion29 = true) { 14573 var file = _step29.value; 14574 file.status = Dropzone.SUCCESS; 14575 this.emit("success", file, responseText, e); 14576 this.emit("complete", file); 14577 } 14578 } catch (err) { 14579 _didIteratorError29 = true; 14580 _iteratorError29 = err; 14581 } finally { 14582 try { 14583 if (!_iteratorNormalCompletion29 && _iterator29["return"] != null) { 14584 _iterator29["return"](); 14585 } 14586 } finally { 14587 if (_didIteratorError29) { 14588 throw _iteratorError29; 14589 } 14590 } 14591 } 14592 14593 if (this.options.uploadMultiple) { 14594 this.emit("successmultiple", files, responseText, e); 14595 this.emit("completemultiple", files); 14596 } 14597 14598 if (this.options.autoProcessQueue) { 14599 return this.processQueue(); 14600 } 14601 } // Called internally when processing is finished. 14602 // Individual callbacks have to be called in the appropriate sections. 14603 14604 }, { 14605 key: "_errorProcessing", 14606 value: function _errorProcessing(files, message, xhr) { 14607 var _iteratorNormalCompletion30 = true; 14608 var _didIteratorError30 = false; 14609 var _iteratorError30 = undefined; 14610 14611 try { 14612 for (var _iterator30 = files[Symbol.iterator](), _step30; !(_iteratorNormalCompletion30 = (_step30 = _iterator30.next()).done); _iteratorNormalCompletion30 = true) { 14613 var file = _step30.value; 14614 file.status = Dropzone.ERROR; 14615 this.emit("error", file, message, xhr); 14616 this.emit("complete", file); 14617 } 14618 } catch (err) { 14619 _didIteratorError30 = true; 14620 _iteratorError30 = err; 14621 } finally { 14622 try { 14623 if (!_iteratorNormalCompletion30 && _iterator30["return"] != null) { 14624 _iterator30["return"](); 14625 } 14626 } finally { 14627 if (_didIteratorError30) { 14628 throw _iteratorError30; 14629 } 14630 } 14631 } 14632 14633 if (this.options.uploadMultiple) { 14634 this.emit("errormultiple", files, message, xhr); 14635 this.emit("completemultiple", files); 14636 } 14637 14638 if (this.options.autoProcessQueue) { 14639 return this.processQueue(); 14640 } 14641 } 14642 }], [{ 14643 key: "uuidv4", 14644 value: function uuidv4() { 14645 return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { 14646 var r = Math.random() * 16 | 0, 14647 v = c === 'x' ? r : r & 0x3 | 0x8; 14648 return v.toString(16); 14649 }); 14650 } 14651 }]); 14652 14653 return Dropzone; 14654}(Emitter); 14655 14656Dropzone.initClass(); 14657Dropzone.version = "5.7.1"; // This is a map of options for your different dropzones. Add configurations 14658// to this object for your different dropzone elemens. 14659// 14660// Example: 14661// 14662// Dropzone.options.myDropzoneElementId = { maxFilesize: 1 }; 14663// 14664// To disable autoDiscover for a specific element, you can set `false` as an option: 14665// 14666// Dropzone.options.myDisabledElementId = false; 14667// 14668// And in html: 14669// 14670// <form action="/upload" id="my-dropzone-element-id" class="dropzone"></form> 14671 14672Dropzone.options = {}; // Returns the options for an element or undefined if none available. 14673 14674Dropzone.optionsForElement = function (element) { 14675 // Get the `Dropzone.options.elementId` for this element if it exists 14676 if (element.getAttribute("id")) { 14677 return Dropzone.options[camelize(element.getAttribute("id"))]; 14678 } else { 14679 return undefined; 14680 } 14681}; // Holds a list of all dropzone instances 14682 14683 14684Dropzone.instances = []; // Returns the dropzone for given element if any 14685 14686Dropzone.forElement = function (element) { 14687 if (typeof element === "string") { 14688 element = document.querySelector(element); 14689 } 14690 14691 if ((element != null ? element.dropzone : undefined) == null) { 14692 throw new Error("No Dropzone found for given element. This is probably because you're trying to access it before Dropzone had the time to initialize. Use the `init` option to setup any additional observers on your Dropzone."); 14693 } 14694 14695 return element.dropzone; 14696}; // Set to false if you don't want Dropzone to automatically find and attach to .dropzone elements. 14697 14698 14699Dropzone.autoDiscover = true; // Looks for all .dropzone elements and creates a dropzone for them 14700 14701Dropzone.discover = function () { 14702 var dropzones; 14703 14704 if (document.querySelectorAll) { 14705 dropzones = document.querySelectorAll(".dropzone"); 14706 } else { 14707 dropzones = []; // IE :( 14708 14709 var checkElements = function checkElements(elements) { 14710 return function () { 14711 var result = []; 14712 var _iteratorNormalCompletion31 = true; 14713 var _didIteratorError31 = false;
14714 var _iteratorError31 = undefined; 14715 14716 try { 14717 for (var _iterator31 = elements[Symbol.iterator](), _step31; !(_iteratorNormalCompletion31 = (_step31 = _iterator31.next()).done); _iteratorNormalCompletion31 = true) { 14718 var el = _step31.value; 14719 14720 if (/(^| )dropzone($| )/.test(el.className)) { 14721 result.push(dropzones.push(el)); 14722 } else { 14723 result.push(undefined); 14724 } 14725 } 14726 } catch (err) { 14727 _didIteratorError31 = true; 14728 _iteratorError31 = err; 14729 } finally { 14730 try { 14731 if (!_iteratorNormalCompletion31 && _iterator31["return"] != null) { 14732 _iterator31["return"](); 14733 } 14734 } finally { 14735 if (_didIteratorError31) { 14736 throw _iteratorError31; 14737 } 14738 } 14739 } 14740 14741 return result; 14742 }(); 14743 }; 14744 14745 checkElements(document.getElementsByTagName("div")); 14746 checkElements(document.getElementsByTagName("form")); 14747 } 14748 14749 return function () { 14750 var result = []; 14751 var _iteratorNormalCompletion32 = true; 14752 var _didIteratorError32 = false; 14753 var _iteratorError32 = undefined; 14754 14755 try { 14756 for (var _iterator32 = dropzones[Symbol.iterator](), _step32; !(_iteratorNormalCompletion32 = (_step32 = _iterator32.next()).done); _iteratorNormalCompletion32 = true) { 14757 var dropzone = _step32.value; 14758 14759 // Create a dropzone unless auto discover has been disabled for specific element 14760 if (Dropzone.optionsForElement(dropzone) !== false) { 14761 result.push(new Dropzone(dropzone)); 14762 } else { 14763 result.push(undefined); 14764 } 14765 } 14766 } catch (err) {
14767 _didIteratorError32 = true; 14768 _iteratorError32 = err; 14769 } finally { 14770 try { 14771 if (!_iteratorNormalCompletion32 && _iterator32["return"] != null) { 14772 _iterator32["return"](); 14773 } 14774 } finally { 14775 if (_didIteratorError32) { 14776 throw _iteratorError32; 14777 } 14778 } 14779 } 14780 14781 return result; 14782 }(); 14783}; // Since the whole Drag'n'Drop API is pretty new, some browsers implement it, 14784// but not correctly. 14785// So I created a blacklist of userAgents. Yes, yes. Browser sniffing, I know. 14786// But what to do when browsers *theoretically* support an API, but crash 14787// when using it. 14788// 14789// This is a list of regular expressions tested against navigator.userAgent 14790// 14791// ** It should only be used on browser that *do* support the API, but 14792// incorrectly ** 14793// 14794 14795 14796Dropzone.blacklistedBrowsers = [// The mac os and windows phone version of opera 12 seems to have a problem with the File drag'n'drop API. 14797/opera.*(Macintosh|Windows Phone).*version\/12/i]; // Checks if the browser is supported 14798 14799Dropzone.isBrowserSupported = function () { 14800 var capableBrowser = true; 14801 14802 if (window.File && window.FileReader && window.FileList && window.Blob && window.FormData && document.querySelector) { 14803 if (!("classList" in document.createElement("a"))) { 14804 capableBrowser = false; 14805 } else { 14806 // The browser supports the API, but may be blacklisted. 14807 var _iteratorNormalCompletion33 = true; 14808 var _didIteratorError33 = false; 14809 var _iteratorError33 = undefined; 14810 14811 try { 14812 for (var _iterator33 = Dropzone.blacklistedBrowsers[Symbol.iterator](), _step33; !(_iteratorNormalCompletion33 = (_step33 = _iterator33.next()).done); _iteratorNormalCompletion33 = true) { 14813 var regex = _step33.value; 14814 14815 if (regex.test(navigator.userAgent)) { 14816 capableBrowser = false; 14817 continue; 14818 } 14819 } 14820 } catch (err) { 14821 _didIteratorError33 = true; 14822 _iteratorError33 = err; 14823 } finally { 14824 try { 14825 if (!_iteratorNormalCompletion33 && _iterator33["return"] != null) { 14826 _iterator33["return"](); 14827 } 14828 } finally { 14829 if (_didIteratorError33) { 14830 throw _iteratorError33; 14831 } 14832 } 14833 } 14834 } 14835 } else { 14836 capableBrowser = false; 14837 } 14838 14839 return capableBrowser; 14840}; 14841 14842Dropzone.dataURItoBlob = function (dataURI) { 14843 // convert base64 to raw binary data held in a string 14844 // doesn't handle URLEncoded DataURIs - see SO answer #6850276 for code that does this 14845 var byteString = atob(dataURI.split(',')[1]); // separate out the mime component 14846 14847 var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]; // write the bytes of the string to an ArrayBuffer 14848 14849 var ab = new ArrayBuffer(byteString.length); 14850 var ia = new Uint8Array(ab); 14851 14852 for (var i = 0, end = byteString.length, asc = 0 <= end; asc ? i <= end : i >= end; asc ? i++ : i--) { 14853 ia[i] = byteString.charCodeAt(i); 14854 } // write the ArrayBuffer to a blob 14855 14856 14857 return new Blob([ab], { 14858 type: mimeString 14859 }); 14860}; // Returns an array without the rejected item 14861 14862 14863var without = function without(list, rejectedItem) { 14864 return list.filter(function (item) { 14865 return item !== rejectedItem; 14866 }).map(function (item) { 14867 return item; 14868 }); 14869}; // abc-def_ghi -> abcDefGhi 14870 14871 14872var camelize = function camelize(str) { 14873 return str.replace(/[\-_](\w)/g, function (match) { 14874 return match.charAt(1).toUpperCase(); 14875 }); 14876}; // Creates an element from string 14877 14878 14879Dropzone.createElement = function (string) { 14880 var div = document.createElement("div"); 14881 div.innerHTML = string; 14882 return div.childNodes[0]; 14883}; // Tests if given element is inside (or simply is) the container 14884 14885 14886Dropzone.elementInside = function (element, container) { 14887 if (element === container) { 14888 return true; 14889 } // Coffeescript doesn't support do/while loops 14890 14891 14892 while (element = element.parentNode) { 14893 if (element === container) { 14894 return true; 14895 } 14896 } 14897 14898 return false; 14899}; 14900 14901Dropzone.getElement = function (el, name) { 14902 var element; 14903 14904 if (typeof el === "string") { 14905 element = document.querySelector(el); 14906 }
14906 else if (el.nodeType != null) { 14907 element = el; 14908 } 14909 14910 if (element == null) { 14911 throw new Error("Invalid `".concat(name, "` option provided. Please provide a CSS selector or a plain HTML element.")); 14912 } 14913 14914 return element; 14915}; 14916 14917Dropzone.getElements = function (els, name) { 14918 var el, elements; 14919 14920 if (els instanceof Array) { 14921 elements = []; 14922 14923 try { 14924 var _iteratorNormalCompletion34 = true; 14925 var _didIteratorError34 = false; 14926 var _iteratorError34 = undefined; 14927 14928 try { 14929 for (var _iterator34 = els[Symbol.iterator](), _step34; !(_iteratorNormalCompletion34 = (_step34 = _iterator34.next()).done); _iteratorNormalCompletion34 = true) { 14930 el = _step34.value; 14931 elements.push(this.getElement(el, name)); 14932 } 14933 } catch (err) { 14934 _didIteratorError34 = true; 14935 _iteratorError34 = err; 14936 } finally { 14937 try { 14938 if (!_iteratorNormalCompletion34 && _iterator34["return"] != null) { 14939 _iterator34["return"](); 14940 } 14941 } finally { 14942 if (_didIteratorError34) { 14943 throw _iteratorError34; 14944 } 14945 } 14946 } 14947 } catch (e) { 14948 elements = null; 14949 } 14950 } else if (typeof els === "string") { 14951 elements = []; 14952 var _iteratorNormalCompletion35 = true; 14953 var _didIteratorError35 = false; 14954 var _iteratorError35 = undefined; 14955 14956 try { 14957 for (var _iterator35 = document.querySelectorAll(els)[Symbol.iterator](), _step35; !(_iteratorNormalCompletion35 = (_step35 = _iterator35.next()).done); _iteratorNormalCompletion35 = true) { 14958 el = _step35.value; 14959 elements.push(el); 14960 } 14961 } catch (err) {
14962 _didIteratorError35 = true; 14963 _iteratorError35 = err; 14964 } finally { 14965 try { 14966 if (!_iteratorNormalCompletion35 && _iterator35["return"] != null) { 14967 _iterator35["return"](); 14968 } 14969 } finally { 14970 if (_didIteratorError35) { 14971 throw _iteratorError35; 14972 } 14973 } 14974 } 14975 } else if (els.nodeType != null) { 14976 elements = [els]; 14977 } 14978 14979 if (elements == null || !elements.length) { 14980 throw new Error("Invalid `".concat(name, "` option provided. Please provide a CSS selector, a plain HTML element or a list of those.")); 14981 } 14982 14983 return elements; 14984}; // Asks the user the question and calls accepted or rejected accordingly 14985// 14986// The default implementation just uses `window.confirm` and then calls the 14987// appropriate callback. 14988 14989 14990Dropzone.confirm = function (question, accepted, rejected) { 14991 if (window.confirm(question)) { 14992 return accepted(); 14993 } else if (rejected != null) { 14994 return rejected(); 14995 } 14996}; // Validates the mime type like this: 14997// 14998// https://developer.mozilla.org/en-US/docs/HTML/Element/input#attr-accept 14999 15000 15001Dropzone.isValidFile = function (file, acceptedFiles) { 15002 if (!acceptedFiles) { 15003 return true; 15004 } // If there are no accepted mime types, it's OK 15005 15006 15007 acceptedFiles = acceptedFiles.split(","); 15008 var mimeType = file.type; 15009 var baseMimeType = mimeType.replace(/\/.*$/, ""); 15010 var _iteratorNormalCompletion36 = true; 15011 var _didIteratorError36 = false; 15012 var _iteratorError36 = undefined; 15013 15014 try { 15015 for (var _iterator36 = acceptedFiles[Symbol.iterator](), _step36; !(_iteratorNormalCompletion36 = (_step36 = _iterator36.next()).done); _iteratorNormalCompletion36 = true) { 15016 var validType = _step36.value; 15017 validType = validType.trim(); 15018 15019 if (validType.charAt(0) === ".") { 15020 if (file.name.toLowerCase().indexOf(validType.toLowerCase(), file.name.length - validType.length) !== -1) { 15021 return true; 15022 } 15023 } else if (/\/\*$/.test(validType)) { 15024 // This is something like a image/* mime type 15025 if (baseMimeType === validType.replace(/\/.*$/, "")) { 15026 return true; 15027 } 15028 } else { 15029 if (mimeType === validType) { 15030 return true; 15031 } 15032 } 15033 } 15034 } catch (err) { 15035 _didIteratorError36 = true; 15036 _iteratorError36 = err; 15037 } finally { 15038 try { 15039 if (!_iteratorNormalCompletion36 && _iterator36["return"] != null) { 15040 _iterator36["return"](); 15041 } 15042 } finally { 15043 if (_didIteratorError36) { 15044 throw _iteratorError36; 15045 } 15046 } 15047 } 15048 15049 return false; 15050}; // Augment jQuery 15051 15052 15053if (typeof jQuery !== 'undefined' && jQuery !== null) { 15054 jQuery.fn.dropzone = function (options) { 15055 return this.each(function () { 15056 return new Dropzone(this, options); 15057 }); 15058 }; 15059} 15060 15061if (typeof module !== 'undefined' && module !== null) { 15062 module.exports = Dropzone; 15063} else { 15064 window.Dropzone = Dropzone; 15065} // Dropzone file status codes 15066 15067 15068Dropzone.ADDED = "added"; 15069Dropzone.QUEUED = "queued"; // For backwards compatibility. Now, if a file is accepted, it's either queued 15070// or uploading. 15071 15072Dropzone.ACCEPTED = Dropzone.QUEUED; 15073Dropzone.UPLOADING = "uploading"; 15074Dropzone.PROCESSING = Dropzone.UPLOADING; // alias 15075 15076Dropzone.CANCELED = "canceled"; 15077Dropzone.ERROR = "error"; 15078Dropzone.SUCCESS = "success"; 15079/* 15080 15081 Bugfix for iOS 6 and 7 15082 Source: http://stackoverflow.com/questions/11929099/html5-canvas-drawimage-ratio-bug-ios 15083 based on the work of https://github.com/stomita/ios-imagefile-megapixel 15084 15085 */ 15086// Detecting vertical squash in loaded image. 15087// Fixes a bug which squash image vertically while drawing into canvas for some images. 15088// This is a bug in iOS6 devices. This function from https://github.com/stomita/ios-imagefile-megapixel 15089 15090var detectVerticalSquash = function detectVerticalSquash(img) { 15091 var iw = img.naturalWidth; 15092 var ih = img.naturalHeight; 15093 var canvas = document.createElement("canvas"); 15094 canvas.width = 1; 15095 canvas.height = ih; 15096 var ctx = canvas.getContext("2d"); 15097 ctx.drawImage(img, 0, 0); 15098 15099 var _ctx$getImageData = ctx.getImageData(1, 0, 1, ih), 15100 data = _ctx$getImageData.data; // search image edge pixel position in case it is squashed vertically. 15101 15102 15103 var sy = 0; 15104 var ey = ih; 15105 var py = ih; 15106 15107 while (py > sy) { 15108 var alpha = data[(py - 1) * 4 + 3]; 15109 15110 if (alpha === 0) { 15111 ey = py; 15112 } else { 15113 sy = py; 15114 } 15115 15116 py = ey + sy >> 1; 15117 } 15118 15119 var ratio = py / ih; 15120 15121 if (ratio === 0) { 15122 return 1; 15123 } else { 15124 return ratio; 15125 } 15126}; // A replacement for context.drawImage 15127// (args are for source and destination). 15128 15129 15130var drawImageIOSFix = function drawImageIOSFix(ctx, img, sx, sy, sw, sh, dx, dy, dw, dh) { 15131 var vertSquashRatio = detectVerticalSquash(img); 15132 return ctx.drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh / vertSquashRatio); 15133}; // Based on MinifyJpeg 15134// Source: http://www.perry.cz/files/ExifRestorer.js 15135// http://elicon.blog57.fc2.com/blog-entry-206.html 15136 15137 15138var ExifRestore = 15139/*#__PURE__*/ 15140function () { 15141 function ExifRestore() { 15142 _classCallCheck(this, ExifRestore); 15143 } 15144 15145 _createClass(ExifRestore, null, [{ 15146 key: "initClass", 15147 value: function initClass() { 15148 this.KEY_STR = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
vendor: 5,099 bytes, lines 15148-15341
15148+/='; 15149 } 15150 }, { 15151 key: "encode64", 15152 value: function encode64(input) { 15153 var output = ''; 15154 var chr1 = undefined; 15155 var chr2 = undefined; 15156 var chr3 = ''; 15157 var enc1 = undefined; 15158 var enc2 = undefined; 15159 var enc3 = undefined; 15160 var enc4 = ''; 15161 var i = 0; 15162 15163 while (true) { 15164 chr1 = input[i++]; 15165 chr2 = input[i++]; 15166 chr3 = input[i++]; 15167 enc1 = chr1 >> 2; 15168 enc2 = (chr1 & 3) << 4 | chr2 >> 4; 15169 enc3 = (chr2 & 15) << 2 | chr3 >> 6; 15170 enc4 = chr3 & 63; 15171 15172 if (isNaN(chr2)) { 15173 enc3 = enc4 = 64; 15174 } else if (isNaN(chr3)) { 15175 enc4 = 64; 15176 } 15177 15178 output = output + this.KEY_STR.charAt(enc1) + this.KEY_STR.charAt(enc2) + this.KEY_STR.charAt(enc3) + this.KEY_STR.charAt(enc4); 15179 chr1 = chr2 = chr3 = ''; 15180 enc1 = enc2 = enc3 = enc4 = ''; 15181 15182 if (!(i < input.length)) { 15183 break; 15184 } 15185 } 15186 15187 return output; 15188 } 15189 }, { 15190 key: "restore", 15191 value: function restore(origFileBase64, resizedFileBase64) { 15192 if (!origFileBase64.match('data:image/jpeg;base64,')) { 15193 return resizedFileBase64; 15194 } 15195 15196 var rawImage = this.decode64(origFileBase64.replace('data:image/jpeg;base64,', '')); 15197 var segments = this.slice2Segments(rawImage); 15198 var image = this.exifManipulation(resizedFileBase64, segments); 15199 return "data:image/jpeg;base64,".concat(this.encode64(image)); 15200 } 15201 }, { 15202 key: "exifManipulation", 15203 value: function exifManipulation(resizedFileBase64, segments) { 15204 var exifArray = this.getExifArray(segments); 15205 var newImageArray = this.insertExif(resizedFileBase64, exifArray); 15206 var aBuffer = new Uint8Array(newImageArray); 15207 return aBuffer; 15208 } 15209 }, { 15210 key: "getExifArray", 15211 value: function getExifArray(segments) { 15212 var seg = undefined; 15213 var x = 0; 15214 15215 while (x < segments.length) { 15216 seg = segments[x]; 15217 15218 if (seg[0] === 255 & seg[1] === 225) { 15219 return seg; 15220 } 15221 15222 x++; 15223 } 15224 15225 return []; 15226 } 15227 }, { 15228 key: "insertExif", 15229 value: function insertExif(resizedFileBase64, exifArray) { 15230 var imageData = resizedFileBase64.replace('data:image/jpeg;base64,', ''); 15231 var buf = this.decode64(imageData); 15232 var separatePoint = buf.indexOf(255, 3); 15233 var mae = buf.slice(0, separatePoint); 15234 var ato = buf.slice(separatePoint); 15235 var array = mae; 15236 array = array.concat(exifArray); 15237 array = array.concat(ato); 15238 return array; 15239 } 15240 }, { 15241 key: "slice2Segments", 15242 value: function slice2Segments(rawImageArray) { 15243 var head = 0; 15244 var segments = []; 15245 15246 while (true) { 15247 var length; 15248 15249 if (rawImageArray[head] === 255 & rawImageArray[head + 1] === 218) { 15250 break; 15251 } 15252 15253 if (rawImageArray[head] === 255 & rawImageArray[head + 1] === 216) { 15254 head += 2; 15255 } else { 15256 length = rawImageArray[head + 2] * 256 + rawImageArray[head + 3]; 15257 var endPoint = head + length + 2; 15258 var seg = rawImageArray.slice(head, endPoint); 15259 segments.push(seg); 15260 head = endPoint; 15261 } 15262 15263 if (head > rawImageArray.length) { 15264 break; 15265 } 15266 } 15267 15268 return segments; 15269 } 15270 }, { 15271 key: "decode64", 15272 value: function decode64(input) { 15273 var output = ''; 15274 var chr1 = undefined; 15275 var chr2 = undefined; 15276 var chr3 = ''; 15277 var enc1 = undefined; 15278 var enc2 = undefined; 15279 var enc3 = undefined; 15280 var enc4 = ''; 15281 var i = 0; 15282 var buf = []; // remove all characters that are not A-Z, a-z, 0-9, +, /, or = 15283 15284 var base64test = /[^A-Za-z0-9\+\/\=]/g; 15285 15286 if (base64test.exec(input)) { 15287 console.warn('There were invalid base64 characters in the input text.\nValid base64 characters are A-Z, a-z, 0-9, \'+\', \'/\',and \'=\'\nExpect errors in decoding.'); 15288 } 15289 15290 input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ''); 15291 15292 while (true) { 15293 enc1 = this.KEY_STR.indexOf(input.charAt(i++)); 15294 enc2 = this.KEY_STR.indexOf(input.charAt(i++)); 15295 enc3 = this.KEY_STR.indexOf(input.charAt(i++)); 15296 enc4 = this.KEY_STR.indexOf(input.charAt(i++)); 15297 chr1 = enc1 << 2 | enc2 >> 4; 15298 chr2 = (enc2 & 15) << 4 | enc3 >> 2; 15299 chr3 = (enc3 & 3) << 6 | enc4; 15300 buf.push(chr1); 15301 15302 if (enc3 !== 64) { 15303 buf.push(chr2); 15304 } 15305 15306 if (enc4 !== 64) { 15307 buf.push(chr3); 15308 } 15309 15310 chr1 = chr2 = chr3 = ''; 15311 enc1 = enc2 = enc3 = enc4 = ''; 15312 15313 if (!(i < input.length)) { 15314 break; 15315 } 15316 } 15317 15318 return buf; 15319 } 15320 }]); 15321 15322 return ExifRestore; 15323}(); 15324 15325ExifRestore.initClass(); 15326/* 15327 * contentloaded.js 15328 * 15329 * Author: Diego Perini (diego.perini at gmail.com) 15330 * Summary: cross-browser wrapper for DOMContentLoaded 15331 * Updated: 20101020 15332 * License: MIT 15333 * Version: 1.2 15334 * 15335 * URL: 15336 * http://javascript.nwbox.com/ContentLoaded/ 15337 * http://javascript.nwbox.com/ContentLoaded/MIT-LICENSE 15338 */ 15339// @win window reference 15340// @fn function reference 15341
15342var contentLoaded = function contentLoaded(win, fn) { 15343 var done = false; 15344 var top = true; 15345 var doc = win.document; 15346 var root = doc.documentElement; 15347 var add = doc.addEventListener ? "addEventListener" : "attachEvent"; 15348 var rem = doc.addEventListener ? "removeEventListener" : "detachEvent"; 15349 var pre = doc.addEventListener ? "" : "on"; 15350 15351 var init = function init(e) { 15352 if (e.type === "readystatechange" && doc.readyState !== "complete") { 15353 return; 15354 } 15355 15356 (e.type === "load" ? win : doc)[rem](pre + e.type, init, false); 15357 15358 if (!done && (done = true)) { 15359 return fn.call(win, e.type || e); 15360 } 15361 }; 15362 15363 var poll = function poll() { 15364 try { 15365 root.doScroll("left"); 15366 } catch (e) { 15367 setTimeout(poll, 50); 15368 return; 15369 } 15370 15371 return init("poll"); 15372 }; 15373 15374 if (doc.readyState !== "complete") { 15375 if (doc.createEventObject && root.doScroll) { 15376 try { 15377 top = !win.frameElement; 15378 } catch (error) {} 15379 15380 if (top) { 15381 poll(); 15382 } 15383 } 15384 15385 doc[add](pre + "DOMContentLoaded", init, false); 15386 doc[add](pre + "readystatechange", init, false); 15387 return win[add](pre + "load", init, false); 15388 } 15389}; // As a single function to be able to write tests. 15390 15391 15392Dropzone._autoDiscoverFunction = function () { 15393 if (Dropzone.autoDiscover) { 15394 return Dropzone.discover(); 15395 } 15396}; 15397 15398contentLoaded(window, Dropzone._autoDiscoverFunction); 15399 15400function __guard__(value, transform) { 15401 return typeof value !== 'undefined' && value !== null ? transform(value) : undefined; 15402} 15403 15404function __guardMethod__(obj, methodName, transform) { 15405 if (typeof obj !== 'undefined' && obj !== null && typeof obj[methodName] === 'function') { 15406 return transform(obj, methodName); 15407 } else { 15408 return undefined; 15409 } 15410}; 15411 15412function start_admin_promotion() { 15413 15414 $('div.admin.promoted').each(function(){ 15415 $('input[type=checkbox]', $(this)).change(function(){ 15416 if ($(this).is(':checked')) { 15417 $.ajax({ 15418 type: 'POST', 15419 url: $(this).data('path')+'/promote', 15420 dataType: 'script' 15421 }); 15422 } else { 15423 $.ajax({ 15424 type: 'POST', 15425 url: $(this).data('path')+'/demote', 15426 dataType: 'script' 15427 }); 15428 } 15429 }) 15430 }); 15431 15432}; 15433function start_autocomplete($row) { 15434 15435 var $input_hidden = $('input.hidden', $row); 15436 var $input_search = $('input.search', $row); 15437 var $list_chosen = $('ol.chosen', $row); 15438 var $list_results = $('ol.results', $row); 15439 $list_chosen.hide(); 15440 $list_results.hide(); 15441 var $forgive_request; 15442 $input_search.keyup(function(){ 15443 $forgive_request = window.setTimeout(function(){ 15444 if ($input_search.val() == '') { 15445 $list_results.hide(); 15446 $list_results.empty(); 15447 } else { 15448 $list_results.show(); 15449 if ($('li.rowclick', $row).length == 0) { 15450 $list_results.html('<li>Loading...</li>'); 15451 } 15452 refresh_list_row($row); 15453 } 15454 }, 200); 15455 }); 15456 $input_search.keydown(function(){ 15457 window.clearTimeout($forgive_request); 15458 }); 15459 15460} 15461 15462function refresh_list_row($row) { 15463 15464 var $div_field = $('div.field', $row); 15465 var $input_hidden = $('input.hidden', $row); 15466 var $input_search = $('input.search', $row); 15467 var $div_selection = $('div.selection', $row); 15468 var $list_chosen = $('ol.chosen', $row); 15469 var $list_results = $('ol.results', $row); 15470 $list_results.addClass('disable'); 15471 15472 $.ajax({ 15473 dataType: 'json', 15474 data: { 15475 scope: {active: 1}, 15476 except: $row.data('except'), 15477 search: $input_search.val(), 15478 sort: {}, 15479 start: 1, 15480 limit: 10 15481 }, 15482 cache: false, 15483 url: $row.data('source'), 15484 success: $.proxy(function($data) { 15485 15486 $list_results.empty(); 15487 $list_results.removeClass('disable'); 15488 if ($data.length > 0) { 15489 $.each($data, $.proxy(function($key, $value) { 15490 if ($value['list_row']) { 15491 $list_row = $($value['list_row']) 15492 $list_row.click(function(){ 15493 $input_hidden.val($('span.id', $(this)).text()); 15494 $input_search.val(''); 15495 $div_field.hide(); 15496 $list_chosen.show(); 15497 $list_chosen.html($('<li>').append($(this).html())); 15498 $cancel = $('<a class="cancel icon grey mdi mdi-close"></a>') 15499 $cancel.click(function(){ 15500 $input_hidden.val(''); 15501 $div_field.show(); 15502 $list_chosen.hide(); 15503 $list_chosen.empty(); 15504 $(this).remove(); 15505 }); 15506 $div_selection.prepend($cancel); 15507 $list_results.hide(); 15508 $list_results.empty(); 15509 }); 15510 $list_results.append($list_row) 15511 } else { 15512 console.log('list_row not found in index.json'); 15513 } 15514 15515 }, this)); 15516 } else { 15517 $list_results.append('<li>No matching items</li>'); 15518 } 15519 15520 }, this) 15521 }); 15522 15523} 15524 15525 15526function start_autocomplete_or_new($row) { 15527 15528 $input_search = $('input.search', $row); 15529 $div_selection = $('div.selection', $row); 15530 $list_results = $('ol.results', $row); 15531 $cancel = $('<a class="cancel icon grey mdi mdi-close"></a>') 15532 $cancel.click(function(){ 15533 $div_selection.hide(); 15534 $list_results.empty(); 15535 }); 15536 $div_selection.prepend($cancel); 15537 $div_selection.hide(); 15538 15539 var $forgive_request; 15540 $input_search.keyup(function(){ 15541 $forgive_request = window.setTimeout(function(){ 15542 if ($input_search.val() == '') { 15543 $div_selection.hide(); 15544 $list_results.empty(); 15545 } else { 15546 15547 $.ajax({ 15548 dataType: 'json', 15549 data: { 15550 scope: {active: 1}, 15551 except: $row.data('except'), 15552 search: $input_search.val(), 15553 sort: {}, 15554 start: 1, 15555 limit: 10 15556 }, 15557 cache: false, 15558 url: $row.data('source'), 15559 success: $.proxy(function($data) { 15560 15561 if ($data.length > 0) { 15562 $div_selection.show(); 15563 $list_results.empty();
15564 $.each($data, $.proxy(function($key, $value) { 15565 if ($value['name']) { 15566 $list_name = $('<li class="rowclick">'+$value['name']+'</li>') 15567 $list_name.click(function(){ 15568 $input_search.val($(this).text()); 15569 $div_selection.hide(); 15570 $list_results.empty(); 15571 }); 15572 $list_results.append($list_name) 15573 } else { 15574 console.log('name not found in index.json'); 15575 } 15576 }, this)); 15577 } else { 15578 $div_selection.hide(); 15579 $list_results.empty(); 15580 } 15581 15582 }, this) 15583 }); 15584 } 15585 }, 200); 15586 }); 15587 $input_search.keydown(function(){ 15588 window.clearTimeout($forgive_request); 15589 }); 15590 $input_search.parents('form').focusin(function() { 15591 if (document.activeElement != $input_search) { 15592 $div_selection.hide(); 15593 $list_results.empty(); 15594 window.clearTimeout($forgive_request); 15595 } 15596 }); 15597 15598}; 15599(function(global, factory) { 15600 typeof exports === "object" && typeof module !== "undefined" ? factory(exports) : typeof define === "function" && define.amd ? define([ "exports" ], factory) : factory(global.ActionCable = {}); 15601})(this, function(exports) { 15602 "use strict"; 15603 var adapters = { 15604 logger: self.console, 15605 WebSocket: self.WebSocket 15606 }; 15607 var logger = { 15608 log: function log() { 15609 if (this.enabled) { 15610 var _adapters$logger; 15611 for (var _len = arguments.length, messages = Array(_len), _key = 0; _key < _len; _key++) { 15612 messages[_key] = arguments[_key]; 15613 } 15614 messages.push(Date.now()); 15615 (_adapters$logger = adapters.logger).log.apply(_adapters$logger, [ "[ActionCable]" ].concat(messages)); 15616 } 15617 } 15618 }; 15619 var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function(obj) { 15620 return typeof obj; 15621 } : function(obj) { 15622 return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; 15623 }; 15624 var classCallCheck = function(instance, Constructor) { 15625 if (!(instance instanceof Constructor)) { 15626 throw new TypeError("Cannot call a class as a function"); 15627 } 15628 }; 15629 var createClass = function() { 15630 function defineProperties(target, props) { 15631 for (var i = 0; i < props.length; i++) { 15632 var descriptor = props[i]; 15633 descriptor.enumerable = descriptor.enumerable || false; 15634 descriptor.configurable = true; 15635 if ("value" in descriptor) descriptor.writable = true; 15636 Object.defineProperty(target, descriptor.key, descriptor); 15637 } 15638 } 15639 return function(Constructor, protoProps, staticProps) { 15640 if (protoProps) defineProperties(Constructor.prototype, protoProps); 15641 if (staticProps) defineProperties(Constructor, staticProps); 15642 return Constructor; 15643 }; 15644 }(); 15645 var now = function now() { 15646 return new Date().getTime(); 15647 }; 15648 var secondsSince = function secondsSince(time) { 15649 return (now() - time) / 1e3; 15650 }; 15651 var clamp = function clamp(number, min, max) { 15652 return Math.max(min, Math.min(max, number)); 15653 }; 15654 var ConnectionMonitor = function() { 15655 function ConnectionMonitor(connection) { 15656 classCallCheck(this, ConnectionMonitor); 15657 this.visibilityDidChange = this.visibilityDidChange.bind(this); 15658 this.connection = connection; 15659 this.reconnectAttempts = 0; 15660 } 15661 ConnectionMonitor.prototype.start = function start() { 15662 if (!this.isRunning()) { 15663 this.startedAt = now(); 15664 delete this.stoppedAt; 15665 this.startPolling(); 15666 addEventListener("visibilitychange", this.visibilityDidChange); 15667 logger.log("ConnectionMonitor started. pollInterval = " + this.getPollInterval() + " ms"); 15668 } 15669 }; 15670 ConnectionMonitor.prototype.stop = function stop() { 15671 if (this.isRunning()) { 15672 this.stoppedAt = now(); 15673 this.stopPolling(); 15674 removeEventListener("visibilitychange", this.visibilityDidChange); 15675 logger.log("ConnectionMonitor stopped"); 15676 } 15677 }; 15678 ConnectionMonitor.prototype.isRunning = function isRunning() { 15679 return this.startedAt && !this.stoppedAt; 15680 }; 15681 ConnectionMonitor.prototype.recordPing = function recordPing() { 15682 this.pingedAt = now(); 15683 }; 15684 ConnectionMonitor.prototype.recordConnect = function recordConnect() { 15685 this.reconnectAttempts = 0; 15686 this.recordPing(); 15687 delete this.disconnectedAt; 15688 logger.log("ConnectionMonitor recorded connect"); 15689 }; 15690 ConnectionMonitor.prototype.recordDisconnect = function recordDisconnect() { 15691 this.disconnectedAt = now(); 15692 logger.log("ConnectionMonitor recorded disconnect"); 15693 }; 15694 ConnectionMonitor.prototype.startPolling = function startPolling() { 15695 this.stopPolling(); 15696 this.poll(); 15697 }; 15698 ConnectionMonitor.prototype.stopPolling = function stopPolling() { 15699 clearTimeout(this.pollTimeout); 15700 }; 15701 ConnectionMonitor.prototype.poll = function poll() { 15702 var _this = this; 15703 this.pollTimeout = setTimeout(function() { 15704 _this.reconnectIfStale(); 15705 _this.poll(); 15706 }, this.getPollInterval()); 15707 }; 15708 ConnectionMonitor.prototype.getPollInterval = function getPollInterval() { 15709 var _constructor$pollInte = this.constructor.pollInterval, min = _constructor$pollInte.min, max = _constructor$pollInte.max, multiplier = _constructor$pollInte.multiplier; 15710 var interval = multiplier * Math.log(this.reconnectAttempts + 1); 15711 return Math.round(clamp(interval, min, max) * 1e3); 15712 }; 15713 ConnectionMonitor.prototype.reconnectIfStale = function reconnectIfStale() { 15714 if (this.connectionIsStale()) {
15715 logger.log("ConnectionMonitor detected stale connection. reconnectAttempts = " + this.reconnectAttempts + ", pollInterval = " + this.getPollInterval() + " ms, time disconnected = " + secondsSince(this.disconnectedAt) + " s, stale threshold = " + this.constructor.staleThreshold + " s"); 15716 this.reconnectAttempts++; 15717 if (this.disconnectedRecently()) { 15718 logger.log("ConnectionMonitor skipping reopening recent disconnect"); 15719 } else { 15720 logger.log("ConnectionMonitor reopening"); 15721 this.connection.reopen(); 15722 } 15723 } 15724 }; 15725 ConnectionMonitor.prototype.connectionIsStale = function connectionIsStale() { 15726 return secondsSince(this.pingedAt ? this.pingedAt : this.startedAt) > this.constructor.staleThreshold; 15727 }; 15728 ConnectionMonitor.prototype.disconnectedRecently = function disconnectedRecently() { 15729 return this.disconnectedAt && secondsSince(this.disconnectedAt) < this.constructor.staleThreshold; 15730 }; 15731 ConnectionMonitor.prototype.visibilityDidChange = function visibilityDidChange() { 15732 var _this2 = this; 15733 if (document.visibilityState === "visible") { 15734 setTimeout(function() { 15735 if (_this2.connectionIsStale() || !_this2.connection.isOpen()) { 15736 logger.log("ConnectionMonitor reopening stale connection on visibilitychange. visibilityState = " + document.visibilityState); 15737 _this2.connection.reopen(); 15738 } 15739 }, 200); 15740 } 15741 }; 15742 return ConnectionMonitor; 15743 }(); 15744 ConnectionMonitor.pollInterval = { 15745 min: 3, 15746 max: 30, 15747 multiplier: 5 15748 }; 15749 ConnectionMonitor.staleThreshold = 6; 15750 var INTERNAL = { 15751 message_types: { 15752 welcome: "welcome", 15753 disconnect: "disconnect", 15754 ping: "ping", 15755 confirmation: "confirm_subscription", 15756 rejection: "reject_subscription" 15757 }, 15758 disconnect_reasons: { 15759 unauthorized: "unauthorized", 15760 invalid_request: "invalid_request", 15761 server_restart: "server_restart" 15762 }, 15763 default_mount_path: "/cable", 15764 protocols: [ "actioncable-v1-json", "actioncable-unsupported" ] 15765 }; 15766 var message_types = INTERNAL.message_types, protocols = INTERNAL.protocols; 15767 var supportedProtocols = protocols.slice(0, protocols.length - 1); 15768 var indexOf = [].indexOf; 15769 var Connection = function() { 15770 function Connection(consumer) { 15771 classCallCheck(this, Connection); 15772 this.open = this.open.bind(this); 15773 this.consumer = consumer; 15774 this.subscriptions = this.consumer.subscriptions; 15775 this.monitor = new ConnectionMonitor(this); 15776 this.disconnected = true; 15777 } 15778 Connection.prototype.send = function send(data) { 15779 if (this.isOpen()) { 15780 this.webSocket.send(JSON.stringify(data)); 15781 return true; 15782 } else { 15783 return false; 15784 } 15785 }; 15786 Connection.prototype.open = function open() { 15787 if (this.isActive()) { 15788 logger.log("Attempted to open WebSocket, but existing socket is " + this.getState()); 15789 return false; 15790 } else { 15791 logger.log("Opening WebSocket, current state is " + this.getState() + ", subprotocols: " + protocols); 15792 if (this.webSocket) { 15793 this.uninstallEventHandlers(); 15794 } 15795 this.webSocket = new adapters.WebSocket(this.consumer.url, protocols); 15796 this.installEventHandlers(); 15797 this.monitor.start(); 15798 return true; 15799 } 15800 }; 15801 Connection.prototype.close = function close() { 15802 var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : { 15803 allowReconnect: true 15804 }, allowReconnect = _ref.allowReconnect; 15805 if (!allowReconnect) { 15806 this.monitor.stop(); 15807 } 15808 if (this.isActive()) { 15809 return this.webSocket.close(); 15810 } 15811 }; 15812 Connection.prototype.reopen = function reopen() { 15813 logger.log("Reopening WebSocket, current state is " + this.getState()); 15814 if (this.isActive()) { 15815 try { 15816 return this.close(); 15817 } catch (error) { 15818 logger.log("Failed to reopen WebSocket", error); 15819 } finally { 15820 logger.log("Reopening WebSocket in " + this.constructor.reopenDelay + "ms"); 15821 setTimeout(this.open, this.constructor.reopenDelay); 15822 } 15823 } else { 15824 return this.open(); 15825 } 15826 }; 15827 Connection.prototype.getProtocol = function getProtocol() { 15828 if (this.webSocket) { 15829 return this.webSocket.protocol; 15830 } 15831 }; 15832 Connection.prototype.isOpen = function isOpen() { 15833 return this.isState("open"); 15834 }; 15835 Connection.prototype.isActive = function isActive() { 15836 return this.isState("open", "connecting"); 15837 };
15838 Connection.prototype.isProtocolSupported = function isProtocolSupported() { 15839 return indexOf.call(supportedProtocols, this.getProtocol()) >= 0; 15840 }; 15841 Connection.prototype.isState = function isState() { 15842 for (var _len = arguments.length, states = Array(_len), _key = 0; _key < _len; _key++) { 15843 states[_key] = arguments[_key]; 15844 } 15845 return indexOf.call(states, this.getState()) >= 0; 15846 }; 15847 Connection.prototype.getState = function getState() { 15848 if (this.webSocket) { 15849 for (var state in adapters.WebSocket) { 15850 if (adapters.WebSocket[state] === this.webSocket.readyState) { 15851 return state.toLowerCase(); 15852 } 15853 } 15854 } 15855 return null; 15856 }; 15857 Connection.prototype.installEventHandlers = function installEventHandlers() { 15858 for (var eventName in this.events) { 15859 var handler = this.events[eventName].bind(this); 15860 this.webSocket["on" + eventName] = handler; 15861 } 15862 }; 15863 Connection.prototype.uninstallEventHandlers = function uninstallEventHandlers() { 15864 for (var eventName in this.events) { 15865 this.webSocket["on" + eventName] = function() {}; 15866 } 15867 }; 15868 return Connection; 15869 }(); 15870 Connection.reopenDelay = 500; 15871 Connection.prototype.events = { 15872 message: function message(event) { 15873 if (!this.isProtocolSupported()) { 15874 return; 15875 } 15876 var _JSON$parse = JSON.parse(event.data), identifier = _JSON$parse.identifier, message = _JSON$parse.message, reason = _JSON$parse.reason, reconnect = _JSON$parse.reconnect, type = _JSON$parse.type; 15877 switch (type) { 15878 case message_types.welcome: 15879 this.monitor.recordConnect(); 15880 return this.subscriptions.reload(); 15881 15882 case message_types.disconnect: 15883 logger.log("Disconnecting. Reason: " + reason); 15884 return this.close({ 15885 allowReconnect: reconnect 15886 }); 15887 15888 case message_types.ping: 15889 return this.monitor.recordPing(); 15890 15891 case message_types.confirmation: 15892 this.subscriptions.confirmSubscription(identifier); 15893 return this.subscriptions.notify(identifier, "connected"); 15894 15895 case message_types.rejection: 15896 return this.subscriptions.reject(identifier); 15897 15898 default: 15899 return this.subscriptions.notify(identifier, "received", message); 15900 } 15901 }, 15902 open: function open() { 15903 logger.log("WebSocket onopen event, using '" + this.getProtocol() + "' subprotocol"); 15904 this.disconnected = false; 15905 if (!this.isProtocolSupported()) { 15906 logger.log("Protocol is unsupported. Stopping monitor and disconnecting."); 15907 return this.close({ 15908 allowReconnect: false 15909 }); 15910 } 15911 }, 15912 close: function close(event) { 15913 logger.log("WebSocket onclose event"); 15914 if (this.disconnected) { 15915 return; 15916 } 15917 this.disconnected = true; 15918 this.monitor.recordDisconnect(); 15919 return this.subscriptions.notifyAll("disconnected", { 15920 willAttemptReconnect: this.monitor.isRunning() 15921 }); 15922 }, 15923 error: function error() { 15924 logger.log("WebSocket onerror event"); 15925 } 15926 }; 15927 var extend = function extend(object, properties) { 15928 if (properties != null) { 15929 for (var key in properties) { 15930 var value = properties[key]; 15931 object[key] = value; 15932 } 15933 } 15934 return object; 15935 }; 15936 var Subscription = function() { 15937 function Subscription(consumer) { 15938 var params = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; 15939 var mixin = arguments[2]; 15940 classCallCheck(this, Subscription); 15941 this.consumer = consumer; 15942 this.identifier = JSON.stringify(params); 15943 extend(this, mixin); 15944 } 15945 Subscription.prototype.perform = function perform(action) { 15946 var data = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; 15947 data.action = action; 15948 return this.send(data); 15949 }; 15950 Subscription.prototype.send = function send(data) { 15951 return this.consumer.send({ 15952 command: "message", 15953 identifier: this.identifier, 15954 data: JSON.stringify(data) 15955 }); 15956 }; 15957 Subscription.prototype.unsubscribe = function unsubscribe() { 15958 return this.consumer.subscriptions.remove(this); 15959 }; 15960 return Subscription; 15961 }(); 15962 var SubscriptionGuarantor = function() { 15963 function SubscriptionGuarantor(subscriptions) { 15964 classCallCheck(this, SubscriptionGuarantor); 15965 this.subscriptions = subscriptions; 15966 this.pendingSubscriptions = []; 15967 } 15968 SubscriptionGuarantor.prototype.guarantee = function guarantee(subscription) { 15969 if (this.pendingSubscriptions.indexOf(subscription) == -1) { 15970 logger.log("SubscriptionGuarantor guaranteeing " + subscription.identifier); 15971 this.pendingSubscriptions.push(subscription); 15972 } else { 15973 logger.log("SubscriptionGuarantor already guaranteeing " + subscription.identifier); 15974 } 15975 this.startGuaranteeing(); 15976 }; 15977 SubscriptionGuarantor.prototype.forget = function forget(subscription) { 15978 logger.log("SubscriptionGuarantor forgetting " + subscription.identifier); 15979 this.pendingSubscriptions = this.pendingSubscriptions.filter(function(s) { 15980 return s !== subscription; 15981 }); 15982 }; 15983 SubscriptionGuarantor.prototype.startGuaranteeing = function startGuaranteeing() { 15984 this.stopGuaranteeing(); 15985 this.retrySubscribing(); 15986 }; 15987 SubscriptionGuarantor.prototype.stopGuaranteeing = function stopGuaranteeing() { 15988 clearTimeout(this.retryTimeout); 15989 }; 15990 SubscriptionGuarantor.prototype.retrySubscribing = function retrySubscribing() { 15991 var _this = this; 15992 this.retryTimeout = setTimeout(function() { 15993 if (_this.subscriptions && typeof _this.subscriptions.subscribe === "function") { 15994 _this.pendingSubscriptions.map(function(subscription) { 15995 logger.log("SubscriptionGuarantor resubscribing " + subscription.identifier); 15996 _this.subscriptions.subscribe(subscription); 15997 }); 15998 } 15999 }, 500); 16000 }; 16001 return SubscriptionGuarantor; 16002 }(); 16003 var Subscriptions = function() { 16004 function Subscriptions(consumer) { 16005 classCallCheck(this, Subscriptions); 16006 this.consumer = consumer; 16007 this.guarantor = new SubscriptionGuarantor(this); 16008 this.subscriptions = []; 16009 } 16010 Subscriptions.prototype.create = function create(channelName, mixin) { 16011 var channel = channelName; 16012 var params = (typeof channel === "undefined" ? "undefined" : _typeof(channel)) === "object" ? channel : { 16013 channel: channel 16014 }; 16015 var subscription = new Subscription(this.consumer, params, mixin); 16016 return this.add(subscription); 16017 }; 16018 Subscriptions.prototype.add = function add(subscription) { 16019 this.subscriptions.push(subscription); 16020 this.consumer.ensureActiveConnection(); 16021 this.notify(subscription, "initialized"); 16022 this.subscribe(subscription); 16023 return subscription; 16024 }; 16025 Subscriptions.prototype.remove = function remove(subscription) { 16026 this.forget(subscription); 16027 if (!this.findAll(subscription.identifier).length) { 16028 this.sendCommand(subscription, "unsubscribe"); 16029 } 16030 return subscription; 16031 }; 16032 Subscriptions.prototype.reject = function reject(identifier) { 16033 var _this = this; 16034 return this.findAll(identifier).map(function(subscription) { 16035 _this.forget(subscription); 16036 _this.notify(subscription, "rejected"); 16037 return subscription; 16038 }); 16039 }; 16040 Subscriptions.prototype.forget = function forget(subscription) { 16041 this.guarantor.forget(subscription); 16042 this.subscriptions = this.subscriptions.filter(function(s) { 16043 return s !== subscription; 16044 }); 16045 return subscription; 16046 }; 16047 Subscriptions.prototype.findAll = function findAll(identifier) { 16048 return this.subscriptions.filter(function(s) { 16049 return s.identifier === identifier; 16050 }); 16051 }; 16052 Subscriptions.prototype.reload = function reload() { 16053 var _this2 = this; 16054 return this.subscriptions.map(function(subscription) { 16055 return _this2.subscribe(subscription); 16056 }); 16057 }; 16058 Subscriptions.prototype.notifyAll = function notifyAll(callbackName) { 16059 var _this3 = this; 16060 for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { 16061 args[_key - 1] = arguments[_key]; 16062 } 16063 return this.subscriptions.map(function(subscription) { 16064 return _this3.notify.apply(_this3, [ subscription, callbackName ].concat(args)); 16065 }); 16066 }; 16067 Subscriptions.prototype.notify = function notify(subscription, callbackName) { 16068 for (var _len2 = arguments.length, args = Array(_len2 > 2 ? _len2 - 2 : 0), _key2 = 2; _key2 < _len2; _key2++) { 16069 args[_key2 - 2] = arguments[_key2]; 16070 } 16071 var subscriptions = void 0; 16072 if (typeof subscription === "string") { 16073 subscriptions = this.findAll(subscription); 16074 } else { 16075 subscriptions = [ subscription ]; 16076 } 16077 return subscriptions.map(function(subscription) { 16078 return typeof subscription[callbackName] === "function" ? subscription[callbackName].apply(subscription, args) : undefined; 16079 }); 16080 }; 16081 Subscriptions.prototype.subscribe = function subscribe(subscription) { 16082 if (this.sendCommand(subscription, "subscribe")) { 16083 this.guarantor.guarantee(subscription); 16084 } 16085 }; 16086 Subscriptions.prototype.confirmSubscription = function confirmSubscription(identifier) { 16087 var _this4 = this; 16088 logger.log("Subscription confirmed " + identifier); 16089 this.findAll(identifier).map(function(subscription) { 16090 return _this4.guarantor.forget(subscription); 16091 }); 16092 }; 16093 Subscriptions.prototype.sendCommand = function sendCommand(subscription, command) { 16094 var identifier = subscription.identifier; 16095 return this.consumer.send({ 16096 command: command, 16097 identifier: identifier 16098 }); 16099 }; 16100 return Subscriptions; 16101 }(); 16102 var Consumer = function() { 16103 function Consumer(url) { 16104 classCallCheck(this, Consumer); 16105 this._url = url; 16106 this.subscriptions = new Subscriptions(this); 16107 this.connection = new Connection(this); 16108 } 16109 Consumer.prototype.send = function send(data) { 16110 return this.connection.send(data); 16111 }; 16112 Consumer.prototype.connect = function connect() { 16113 return this.connection.open(); 16114 }; 16115 Consumer.prototype.disconnect = function disconnect() { 16116 return this.connection.close({ 16117 allowReconnect: false 16118 }); 16119 }; 16120 Consumer.prototype.ensureActiveConnection = function ensureActiveConnection() { 16121 if (!this.connection.isActive()) { 16122 return this.connection.open(); 16123 } 16124 }; 16125 createClass(Consumer, [ { 16126 key: "url", 16127 get: function get$$1() { 16128 return createWebSocketURL(this._url); 16129 } 16130 } ]); 16131 return Consumer; 16132 }(); 16133 function createWebSocketURL(url) { 16134 if (typeof url === "function") { 16135 url = url(); 16136 } 16137 if (url && !/^wss?:/i.test(url)) { 16138 var a = document.createElement("a"); 16139 a.href = url; 16140 a.href = a.href; 16141 a.protocol = a.protocol.replace("http", "ws"); 16142 return a.href; 16143 } else { 16144 return url; 16145 } 16146 } 16147 function createConsumer() { 16148 var url = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getConfig("url") || INTERNAL.default_mount_path; 16149 return new Consumer(url); 16150 } 16151 function getConfig(name) { 16152 var element = document.head.querySelector("meta[name='action-cable-" + name + "']"); 16153 if (element) { 16154 return element.getAttribute("content"); 16155 } 16156 } 16157 exports.Connection = Connection; 16158 exports.ConnectionMonitor = ConnectionMonitor; 16159 exports.Consumer = Consumer; 16160 exports.INTERNAL = INTERNAL; 16161 exports.Subscription = Subscription; 16162 exports.Subscriptions = Subscriptions; 16163 exports.SubscriptionGuarantor = SubscriptionGuarantor; 16164 exports.adapters = adapters; 16165 exports.createWebSocketURL = createWebSocketURL; 16166 exports.logger = logger; 16167 exports.createConsumer = createConsumer; 16168 exports.getConfig = getConfig; 16169 Object.defineProperty(exports, "__esModule", { 16170 value: true 16171 }); 16172}); 16173// Action Cable provides the framework to deal with WebSockets in Rails. 16174// You can generate new channels where WebSocket features live using the rails generate channel command. 16175// 16176 16177 16178 16179 16180(function() {
16181 this.App || (this.App = {}); 16182 16183 App.cable = ActionCable.createConsumer(); 16184 16185}).call(this); 16186 16187function start_categories() { 16188 16189 $('div.row.categories').each(function(){ 16190 16191 var $categories = $('input[id$=all_categories]', this).val().split(', '); 16192 $('ul.categories li label', this).each(function(){ 16193 if ($.inArray($(this).text(), $categories) >= 0) { 16194 $('input[type=checkbox]', $(this).parent('li')).prop('checked', true); 16195 } 16196 }); 16197 $('ul.categories li input[type=checkbox]', this).change(function(){ 16198 refresh_categories($(this).parents('div.row.categories')); 16199 }); 16200 $('input#newcategory', this).bind('change keyup', function(){ 16201 refresh_categories($(this).parents('div.row.categories')); 16202 }); 16203 $('input[id$=all_categories]', this).hide(); 16204 16205 }); 16206 16207} 16208 16209function refresh_categories($row) { 16210 16211 var $categories = []; 16212 $('input[type=checkbox]:checked', $row).each(function(){ 16213 $categories.push($('label', $(this).parent('li')).text()); 16214 }); 16215 var $newcategories = $('input#newcategory', $row).val().split(',') 16216 for (var $i = 0; $i < $newcategories.length; $i++) { 16217 if ($newcategories[$i].trim() != '') { 16218 $categories.push($newcategories[$i].trim()); 16219 } 16220 } 16221 $('input[id$=all_categories]', $row).val($categories.join(', ')); 16222 16223}; 16224//Override the default confirm dialog by rails 16225$.rails.allowAction = function($element){ 16226 if ($element.data("confirm") == undefined){ 16227 return true; 16228 } 16229 $.rails.showConfirmationDialog($element); 16230 return false; 16231} 16232//User click confirm button 16233$.rails.confirmed = function($element){ 16234 $element.data("confirm", null); 16235 $element.trigger("click.rails"); 16236} 16237//Display the confirmation dialog 16238$.rails.showConfirmationDialog = function($element){ 16239 var message = $element.data("confirm"); 16240 $confirm = $('<div id="confirm"></div>'); 16241 $confirm.append('<h2>Please confirm</h2>'); 16242 $content = $('<div class="content"></div>'); 16243 $content.append($('<p></p>').text(message)); 16244 $content.append('<div class="actions"><a href="#" class="confirm button">Confirm</a> <a href="#" class="cancel secondary button">Cancel</a></div>'); 16245 $confirm.append($content); 16246 start_modal($('<div>').append($confirm.clone()).html()); 16247 $('div#confirm a.confirm').click(function($event){ 16248 $.rails.confirmed($element); 16249 close_modal(); 16250 $event.preventDefault(); 16251 }); 16252 $('div#confirm a.cancel').click(function($event){ 16253 close_modal(); 16254 $event.preventDefault(); 16255 }); 16256} 16257 16258function confirm_labels() { 16259 $('label').click(function(){ 16260 if ($(this).data("confirm") == undefined){ 16261 return true; 16262 } 16263 $.rails.showConfirmationDialog($(this)); 16264 return false; 16265 }); 16266}; 16267function show_cookie_notice() { 16268 if (getParameterByName('cookie')) { 16269 $('div#cookie').show(); 16270 } 16271 if (document.cookie.indexOf('cookie_notice=true') < 0) { 16272 $('div#cookie').show(); 16273 } 16274} 16275 16276function hide_cookie_notice() { 16277 document.cookie = 'cookie_notice=true; expires=Thu, 31 Dec 2099 23:59:59 UTC; path=/'; 16278 $('div#cookie div.holder').fadeOut(200,function(){ 16279 $('div#cookie div.holder').css('display', 'block'); 16280 $('div#cookie div.holder').css('visibility', 'hidden'); 16281 $('div#cookie').slideUp(200); 16282 }); 16283}; 16284 16285function start_dates() { 16286 16287 if ($('div.row.datetime-start').length && $('div.row.datetime-end').length) { 16288 16289 $('div.row.datetime-start').each(function(){ 16290 $end_date_row = $('div.row.datetime-end', $(this).parents('form')); 16291 $checkbox = $('<input type="checkbox" id="toggle-end-'+$(this).index()+'" />'); 16292 if ($('input', $end_date_row).val() == '') { 16293 $end_date_row.hide(); 16294 } else { 16295 $checkbox.prop('checked', true); 16296 } 16297 $label = $('<label for="toggle-end-'+$(this).index()+'">Add end date</label>'); 16298 $('div.field', this).append($checkbox); 16299 $('div.field', this).append($label); 16300 $checkbox.change(function(){ 16301 toggle_end_date($checkbox, $(this).parents('div.row.datetime-start'), $end_date_row); 16302 }); 16303 }); 16304 16305 } 16306 16307} 16308 16309function pad(n, width) { 16310 z = '0'; 16311 n = n + ''; 16312 return n.length >= width ? n : new Array(width - n.length + 1).join(z) + n; 16313} 16314 16315function toggle_end_date($checkbox, $start_date_row, $end_date_row) { 16316 16317 if ($checkbox.prop('checked')) { 16318 $('input', $end_date_row).val($('input', $start_date_row).val()); 16319 $end_date_row.show(); 16320 } else { 16321 $('input', $end_date_row).val('') 16322 $end_date_row.hide(); 16323 } 16324 16325}; 16326function start_delegates($delegates) { 16327 16328 refresh_delegates($delegates); 16329 16330 $('a.add', $delegates).click(function(e){ 16331 add_delegate($delegates); 16332 e.preventDefault(); 16333 }); 16334 16335 $('a.remove', $delegates).click(function(e){ 16336 remove_delegate($delegates); 16337 e.preventDefault(); 16338 }); 16339 16340} 16341 16342function refresh_delegates($delegates) { 16343 16344 $('section.delegate', $delegates).each(function(){ 16345 if ($('input.delete', $(this)).prop('checked') == true) { 16346 $(this).hide(); 16347 } else { 16348 $(this).show(); 16349 } 16350 }); 16351 16352 16353 if ($('section.delegate:visible', $delegates).length < $('section.delegate', $delegates).length) { 16354// $('a.add', $delegates).show(); 16355 $('a.add', $delegates).removeClass('disabled'); 16356 } else { 16357// $('a.add', $delegates).hide(); 16358 $('a.add', $delegates).addClass('disabled'); 16359 } 16360 16361 if ($('section.delegate:visible', $delegates).length > 1) { 16362// $('a.remove', $delegates).show(); 16363 $('a.remove', $delegates).removeClass('disabled'); 16364 } else { 16365// $('a.remove', $delegates).hide(); 16366 $('a.remove', $delegates).addClass('disabled'); 16367 } 16368 16369} 16370 16371function add_delegate($delegates) { 16372 $checkbox = $('input.delete:checked:first', $delegates) 16373 $checkbox.prop('checked', false); 16374 $delegate = $checkbox.parents('section.delegate'); 16375 $delegate.slideDown(200,function(){ 16376 refresh_delegates($delegates); 16377 }); 16378} 16379 16380function remove_delegate($delegates) { 16381 $checkbox = $('input.delete:not(:checked):last', $delegates) 16382 $checkbox.prop('checked', true); 16383 $delegate = $checkbox.parents('section.delegate'); 16384 $delegate.slideUp(200,function(){ 16385 refresh_delegates($delegates); 16386 }); 16387}; 16388function start_fields() { 16389 16390 refresh_field_options($('select[id$="_input"]')); 16391 $('select[id$="_input"]').change(function(){ 16392 refresh_field_options($(this)); 16393 }); 16394 refresh_option_deletes(); 16395 attach_more_options_link(); 16396 confirm_labels(); 16397 16398} 16399 16400function refresh_field_options($select) { 16401 16402 $('div.optionsort').hide(); 16403 if ($('option:selected', $select).attr('class') == 'options') { 16404 $('div.optionsort').show(); 16405 } 16406 16407} 16408 16409function refresh_option_deletes() { 16410 16411 $('ol.options input.delete').change(function(){ 16412 if ($(this).is(':checked')) { 16413 $(this).parents('li.option').hide(); 16414 } 16415 }); 16416 16417} 16418 16419function start_option_sort() { 16420 16421 $('ol.options').each(function(){ 16422 refresh_option_sort($(this)); 16423 }); 16424 16425 $('div.optionsort').nestable({ 16426 maxDepth: 1,
16427 rootClass: 'optionsort', 16428 listClass: 'options', 16429 itemClass: 'option', 16430 dragClass: 'dragging', 16431 handleClass: 'weight', 16432 placeClass: 'place' 16433 }); 16434 $('div.optionsort').on('change', function() { 16435 refresh_option_sort($('ol.options')); 16436 }); 16437 16438} 16439 16440function refresh_option_sort($sortlist) { 16441 16442 $('select[id$="weight"]', $sortlist).each(function(index){ 16443 $(this).val($(this).parents('li').index()+1); 16444 }); 16445 16446} 16447 16448function attach_more_options_link() { 16449 16450 $link_add = $('<a href="#" class="mdi mdi-plus">Add an option</a>'); 16451 $link_add.click(function($event){ 16452 $i = $('li.option', $(this).parents('div.optionsort')).length; 16453 $new_option = $('<li class="option"><div class="weight"><span class="mdi mdi-drag-vertical"></span><div class="row select weight"><div class="field"><select name="'+$(this).parents('div.optionsort').data('target')+'_field[field_options_attributes]['+$i+'][weight]" id="'+$(this).parents('div.optionsort').data('target')+'_field_field_options_attributes_'+$i+'_weight"><option selected="selected" value="0">0</option></select></div></div></div> <div class="label"><div class="row text option snug"><div class="field"><input size="50" type="text" name="'+$(this).parents('div.optionsort').data('target')+'_field[field_options_attributes]['+$i+'][option]" id="'+$(this).parents('div.optionsort').data('target')+'_field_field_options_attributes_'+$i+'_option"></div></div></div> <div class="actions"><a href="#" class="delete icon mdi mdi-delete"><span>Delete</span></a></div><div class="count"></div></li>'); 16454 for ($i = 1; $i <= 1000; $i++) { 16455 $('div.weight select', $new_option).append('<option value="'+$i+'">'+$i+'</option>'); 16456 } 16457 $('ol.options', $(this).parents('div.optionsort')).append($new_option); 16458 $('div#options ol.options a.delete').click(function($event){ 16459 $(this).parents('li.option').remove(); 16460 refresh_option_sort($('ol.options', $(this).parents('div.optionsort'))); 16461 $event.preventDefault(); 16462 }); 16463 refresh_option_sort($('ol.options', $(this).parents('div.optionsort'))); 16464 $event.preventDefault(); 16465 }); 16466 $('div#options div.add').append($link_add); 16467 16468}; 16469function set_cursor($form) { 16470 16471 exceptions = [ 16472 'new_submission', 16473 'new_basket', 16474 'edit_basket' 16475 ] 16476 16477 if ($.inArray($form.attr('class'), exceptions) == -1) { 16478 $inputs = $form.find(':input.error') 16479 if ($inputs.length != 0) { 16480 if ($($inputs[0]).parents('div.tab-frame').length > 0) { 16481 $anchor = $('a[href="#'+$($inputs[0]).parents('div.tab-frame').attr('id')+'"]') 16482 set_tab_for($anchor); 16483 } 16484 $inputs[0].focus(); 16485 } else { 16486 $form.find(':input, div.redactor-in').filter(':visible:first').focus(); 16487 } 16488 } 16489 16490} 16491 16492function attach_error($id, $field, $message) { 16493 16494 selector = '[id^="'+$id+'"]'; 16495 $(selector).addClass('error'); 16496 $errors = $('<div class="info errors"></div>'); 16497 if ($field != '') { 16498 $errors.append('<p>'+$field+' '+$message+'</p>'); 16499 } else { 16500 $errors.append('<p>'+$message+'</p>'); 16501 } 16502 if ($('div.field', $($id)).length == 0) { 16503 $(selector).closest('div.field').append($errors); 16504 } else { 16505 $(selector).append($errors); 16506 } 16507 16508} 16509 16510function remove_errors($form) { 16511 16512 $('div.row', $form).removeClass('error'); 16513 $('input', $form).removeClass('error'); 16514 $('select', $form).removeClass('error'); 16515 $('textarea', $form).removeClass('error'); 16516 $('div.info.errors', $form).remove(); 16517 16518} 16519 16520function start_forms() { 16521 16522 if ($('body.show').length == 0) { 16523 set_cursor($('div#content form:first')); 16524 } 16525 16526} 16527 16528function start_form_attachments() { 16529 16530 refresh_form_attachments(); 16531 16532 $('div#form-attachments input.delete').each(function(){ 16533 $(this).change(function(){ 16534 if ($(this).is(':checked')) { 16535 $(this).parents('tr').hide(); 16536 } 16537 refresh_form_attachments(); 16538 }); 16539 if ($(this).is(':checked')) { 16540 $(this).parents('tr').hide(); 16541 } 16542 }); 16543 16544 $('div#form-attachments a.add').click(function(event){ 16545 $i = $('div#form-attachments table tr.attachment').length; 16546 $('div#form-attachments table').append('<tr class="attachment"><td class="field"><div class="row text description tight"><div class="field"><input size="30" placeholder="Description" type="text" name="'+$('body').data('model')+'[node_attributes][attachments_attributes]['+$i+'][description]" id="'+$('body').data('model')+'_node_attributes_attachments_attributes_'+$i+'_description"></div></div></td><td><div class="row file file tight"><div class="field"><input size="30" type="file" name="'+$('body').data('model')+'[node_attributes][attachments_attributes]['+$i+'][file]" id="'+$('body').data('model')+'_node_attributes_attachments_attributes_'+$i+'_file"><div class="info rules">The maximum file size is 10MB</div></div></div></td><td class="actions"><a href="#" class="delete icon mdi mdi-delete"><span>
16546Delete</span></a></td></tr>'); 16547 $('div#form-attachments table a.delete').click(function($event){ 16548 $(this).parents('tr.attachment').remove(); 16549 refresh_form_attachments(); 16550 $event.preventDefault(); 16551 }); 16552 refresh_form_attachments(); 16553 event.preventDefault(); 16554 }); 16555 16556} 16557 16558function refresh_form_attachments() { 16559 16560 if ($('div#form-attachments table tr.attachment:visible').length > 0) { 16561 $('div#form-attachments table tr.none').remove(); 16562 } else { 16563 $('div#form-attachments table').append('<tr class="none"><td colspan="3">There are no attachments at the moment.</td></tr>'); 16564 } 16565 16566} 16567 16568function start_file_attachments() { 16569 16570 refresh_file_attachments(); 16571 16572 $('div#file-attachments input.delete').each(function(){ 16573 $(this).change(function(){ 16574 if ($(this).is(':checked')) { 16575 $(this).parents('tr').hide(); 16576 } 16577 refresh_file_attachments(); 16578 }); 16579 if ($(this).is(':checked')) { 16580 $(this).parents('tr').hide(); 16581 } 16582 }); 16583 16584 $('div#file-attachments a.add').click(function(event){ 16585 $i = $('div#file-attachments table tr.attachment').length; 16586 $('div#file-attachments table').append('<tr class="attachment"><td class="field"><div class="row text description tight"><div class="field"><input size="30" placeholder="Description" type="text" name="'+$('body').data('model')+'[file_attachments_attributes]['+$i+'][description]" id="'+$('body').data('model')+'_file_attachments_attributes_'+$i+'_description"></div></div></td><td><div class="row file file tight"><div class="field"><input size="30" type="file" name="'+$('body').data('model')+'[file_attachments_attributes]['+$i+'][file]" id="'+$('body').data('model')+'_file_attachments_attributes_'+$i+'_file"><div class="info rules">The maximum file size is 10MB</div></div></div></td><td class="actions"><a href="#" class="delete icon mdi mdi-delete"><span>Delete</span></a></td></tr>'); 16587 $('div#file-attachments table a.delete').click(function($event){ 16588 $(this).parents('tr.attachment').remove(); 16589 refresh_file_attachments(); 16590 $event.preventDefault(); 16591 }); 16592 refresh_file_attachments(); 16593 event.preventDefault(); 16594 }); 16595 16596} 16597 16598function refresh_file_attachments() { 16599 16600 if ($('div#file-attachments table tr.attachment:visible').length > 0) { 16601 $('div#file-attachments table tr.none').remove(); 16602 } else { 16603 $('div#file-attachments table').append('<tr class="none"><td colspan="3">There are no attachments at the moment.</td></tr>'); 16604 } 16605 16606} 16607 16608function start_image_scale($target) { 16609 16610 reset_image_scale($target); 16611 16612 $('input[name$="['+$target+'_scale]"]').change(function(){ 16613 reset_image_scale($target); 16614 }); 16615 16616} 16617 16618function reset_image_scale($target) { 16619 16620 $('div[id^="preview-'+$target+'_asset_id"]').hide(); 16621 $('div.row.'+$target+'_scale').hide(); 16622 $('div.row.'+$target+'_link').hide(); 16623 $('div.row.'+$target+'_alt').hide(); 16624 16625 if (parseInt($('input[id$="'+$target+'_asset_id"]').val()) > 0) { 16626 //$('div#preview-'+$target+'_asset_id').html(''); 16627 $('div.row.'+$target+'_scale').show(); 16628 $('div.row.'+$target+'_link').show(); 16629 $('div.row.'+$target+'_alt').show(); 16630 console.log(); 16631 $.ajax({ 16632 type: 'GET', 16633 dataType: 'json', 16634 url: '/'+$target+'_assets/'+$('input[id$="'+$target+'_asset_id"]').val(), 16635 success: function($data) { 16636 $('input[name$="['+$target+'_scale]"]').parents('div.radios').append($('a[id^="remove-'+$target+'_asset_id"]')); 16637 $('input[name$="['+$target+'_scale]"]').each(function(){ 16638 $('label span.image', $(this).parents('div.option')).html(''); 16639 switch($(this).val()) { 16640 case 'fill': 16641 $('label span.image', $(this).parents('div.option')).append($data.preview_tile_fill); 16642 break; 16643 case 'fit': 16644 $('label span.image', $(this).parents('div.option')).append($data.preview_tile_fit); 16645 break; 16646 case 'full': 16647 $('label span.image', $(this).parents('div.option')).append($data.preview_banner); 16648 break; 16649 case 'half': 16650 $('label span.image', $(this).parents('div.option')).append($data.preview_banner_half); 16651 break; 16652 } 16653 }); 16654 switch($('input[name$="['+$target+'_scale]"]:checked').val()) { 16655 case 'fill': 16656 $('div[id^="preview-'+$target+'_asset_id"]').html($data.preview_tile_fill); 16657 break; 16658 case 'fit': 16659 $('div[id^="preview-'+$target+'_asset_id"]').html($data.preview_tile_fit); 16660 break; 16661 case 'full': 16662 $('div[id^="preview-'+$target+'_asset_id"]').html($data.preview_banner); 16663 break; 16664 case 'half': 16665 $('div[id^="preview-'+$target+'_asset_id"]').html($data.preview_banner_half); 16666 break; 16667 } 16668 } 16669 }); 16670 } 16671 16672} 16673 16674function reset_image_position($target) { 16675 16676 $('div.row.'+$target+'_position').hide(); 16677 $('div.row.'+$target+'_link').hide(); 16678 $('div.row.'+$target+'_alt').hide(); 16679 16680 if (parseInt($('input[id$="'+$target+'_asset_id"]').val()) > 0) { 16681 $('div.row.'+$target+'_position').show(); 16682 $('div.row.'+$target+'_link').show(); 16683 $('div.row.'+$target+'_alt').show(); 16684 } 16685 16686} 16687 16688function start_show_password() { 16689 $('#show_password_toggle').on('change', function() { 16690 var $password = $('#login_password'); 16691 if ($(this).is(':checked')) { 16692 $password.attr('type', 'text'); 16693 } else { 16694 $password.attr('type', 'password'); 16695 } 16696 }); 16697 16698}; 16699function fetchInvoice(invoice_hash_id) { 16700 return $.ajax({ 16701 type: 'GET', 16702 url: '/invoices/'+invoice_hash_id+'/intend', 16703 dataType: 'json' 16704 }); 16705}; 16706// This [jQuery](http://jquery.com/) plugin implements an `<iframe>` 16707// [transport](http://api.jquery.com/extending-ajax/#Transports) so that 16708// `$.ajax()` calls support the uploading of files using standard HTML file
16709// input fields. This is done by switching the exchange from `XMLHttpRequest` 16710// to a hidden `iframe` element containing a form that is submitted. 16711 16712// The [source for the plugin](http://github.com/cmlenz/jquery-iframe-transport) 16713// is available on [Github](http://github.com/) and dual licensed under the MIT 16714// or GPL Version 2 licenses. 16715 16716// ## Usage 16717 16718// To use this plugin, you simply add an `iframe` option with the value `true` 16719// to the Ajax settings an `$.ajax()` call, and specify the file fields to 16720// include in the submssion using the `files` option, which can be a selector, 16721// jQuery object, or a list of DOM elements containing one or more 16722// `<input type="file">` elements: 16723 16724// $("#myform").submit(function() { 16725// $.ajax(this.action, { 16726// files: $(":file", this), 16727// iframe: true 16728// }).complete(function(data) { 16729// console.log(data); 16730// }); 16731// }); 16732 16733// The plugin will construct hidden `<iframe>` and `<form>` elements, add the 16734// file field(s) to that form, submit the form, and process the response. 16735 16736// If you want to include other form fields in the form submission, include 16737// them in the `data` option, and set the `processData` option to `false`: 16738 16739// $("#myform").submit(function() { 16740// $.ajax(this.action, { 16741// data: $(":text", this).serializeArray(), 16742// files: $(":file", this), 16743// iframe: true, 16744// processData: false 16745// }).complete(function(data) { 16746// console.log(data); 16747// }); 16748// }); 16749 16750// ### Response Data Types 16751 16752// As the transport does not have access to the HTTP headers of the server 16753// response, it is not as simple to make use of the automatic content type 16754// detection provided by jQuery as with regular XHR. If you can't set the 16755// expected response data type (for example because it may vary depending on 16756// the outcome of processing by the server), you will need to employ a 16757// workaround on the server side: Send back an HTML document containing just a 16758// `<textarea>` element with a `data-type` attribute that specifies the MIME 16759// type, and put the actual payload in the textarea: 16760 16761// <textarea data-type="application/json"> 16762// {"ok": true, "message": "Thanks so much"} 16763// </textarea> 16764 16765// The iframe transport plugin will detect this and pass the value of the 16766// `data-type` attribute on to jQuery as if it was the "Content-Type" response 16767// header, thereby enabling the same kind of conversions that jQuery applies 16768// to regular responses. For the example above you should get a Javascript 16769// object as the `data` parameter of the `complete` callback, with the 16770// properties `ok: true` and `message: "Thanks so much"`. 16771 16772// ### Handling Server Errors 16773 16774// Another problem with using an `iframe` for file uploads is that it is 16775// impossible for the javascript code to determine the HTTP status code of the 16776// servers response. Effectively, all of the calls you make will look like they 16777// are getting successful responses, and thus invoke the `done()` or 16778// `complete()` callbacks. You can only determine communicate problems using 16779// the content of the response payload. For example, consider using a JSON 16780// response such as the following to indicate a problem with an uploaded file: 16781 16782// <textarea data-type="application/json"> 16783// {"ok": false, "message": "Please only upload reasonably sized files."} 16784// </textarea> 16785 16786// ### Compatibility 16787 16788// This plugin has primarily been tested on Safari 5 (or later), Firefox 4 (or 16789// later), and Internet Explorer (all the way back to version 6). While I 16790// haven't found any issues with it so far, I'm fairly sure it still doesn't 16791// work around all the quirks in all different browsers. But the code is still 16792// pretty simple overall, so you should be able to fix it and contribute a 16793// patch :) 16794 16795// ## Annotated Source 16796 16797(function($, undefined) { 16798 "use strict"; 16799 16800 // Register a prefilter that checks whether the `iframe` option is set, and 16801 // switches to the "iframe" data type if it is `true`. 16802 $.ajaxPrefilter(function(options, origOptions, jqXHR) { 16803 if (options.iframe) { 16804 return "iframe"; 16805 } 16806 }); 16807 16808 // Register a transport for the "iframe" data type. It will only activate 16809 // when the "files" option has been set to a non-empty list of enabled file 16810 // inputs. 16811 $.ajaxTransport("iframe", function(options, origOptions, jqXHR) { 16812 var form = null, 16813 iframe = null, 16814 name = "iframe-" + $.now(), 16815 files = $(options.files).filter(":file:enabled"), 16816 markers = null, 16817 accepts; 16818 16819 // This function gets called after a successful submission or an abortion 16820 // and should revert all changes made to the page to enable the 16821 // submission via this transport. 16822 function cleanUp() { 16823 markers.each(function(i){ 16824 $(this).replaceWith(files[i]); 16825 markers.splice(i, 1); 16826 }); 16827 form.remove(); 16828 iframe.bind("load", function() { iframe.remove(); }); 16829 iframe.attr("src", "about:blank"); 16830 } 16831 16832 // Remove "iframe" from the data types list so that further processing is 16833 // based on the content type returned by the server, without attempting an 16834 // (unsupported) conversion from "iframe" to the actual type. 16835 options.dataTypes.shift(); 16836 16837 if (files.length) { 16838 form = $("<form enctype='multipart/form-data' method='post'></form>"). 16839 hide().attr({action: options.url, target: name}); 16840 16841 // If there is any additional data specified via the `data` option, 16842 // we add it as hidden fields to the form. This (currently) requires 16843 // the `processData` option to be set to false so that the data doesn't 16844 // get serialized to a string. 16845 if (typeof(options.data) === "string" && options.data.length > 0) { 16846 $.error("data must not be serialized"); 16847 } 16848 $.each(options.data || {}, function(name, value) { 16849 if ($.isPlainObject(value)) { 16850 name = value.name; 16851 value = value.value; 16852 } 16853 $("<input type='hidden' />").attr({name: name, value: value}). 16854 appendTo(form); 16855 }); 16856 16857 // Add a hidden `X-Requested-With` field with the value `IFrame` to the 16858 // field, to help server-side code to determine that the upload happened 16859 // through this transport. 16860 $("<input type='hidden' value='IFrame' name='X-Requested-With' />"). 16861 appendTo(form); 16862 16863 // Borrowed straight from the JQuery source 16864 // Provides a way of specifying the accepted data type similar to HTTP_ACCEPTS 16865 accepts = options.dataTypes[ 0 ] && options.accepts[ options.dataTypes[0] ] ? 16866 options.accepts[ options.dataTypes[0] ] + ( options.dataTypes[ 0 ] !== "*" ? ", */*; q=0.01" : "" ) : 16867 options.accepts[ "*" ] 16868 16869 $("<input type='hidden' name='X-Http-Accept'>") 16870 .attr("value", accepts).appendTo(form); 16871 16872 // Move the file fields into the hidden form, but first remember their 16873 // original locations in the document by replacing them with disabled 16874 // clones. This should also avoid introducing unwanted changes to the 16875 // page layout during submission. 16876 markers = files.after(function(idx) { 16877 return $(this).clone().prop("disabled", true); 16878 }).next(); 16879 files.appendTo(form); 16880 16881 return { 16882 16883 // The `send` function is called by jQuery when the request should be 16884 // sent. 16885 send: function(headers, completeCallback) { 16886 iframe = $("<iframe src='about:blank' name='" + name + 16887 "' id='" + name + "' style='display:none'></iframe>"); 16888 16889 // The first load event gets fired after the iframe has been injected 16890 // into the DOM, and is used to prepare the actual submission. 16891 iframe.bind("load", function() { 16892 16893 // The second load event gets fired when the response to the form 16894 // submission is received. The implementation detects whether the 16895 // actual payload is embedded in a `<textarea>` element, and 16896 // prepares the required conversions to be made in that case. 16897 iframe.unbind("load").bind("load", function() { 16898 var doc = this.contentWindow ? this.contentWindow.document : 16899 (this.contentDocument ? this.contentDocument : this.document), 16900 root = doc.documentElement ? doc.documentElement : doc.body, 16901 textarea = root.getElementsByTagName("textarea")[0], 16902 type = textarea && textarea.getAttribute("data-type") || null, 16903 status = textarea && textarea.getAttribute("data-status") || 200, 16904 statusText = textarea && textarea.getAttribute("data-statusText") || "OK", 16905 content = { 16906 html: root.innerHTML, 16907 text: type ? 16908 textarea.value : 16909 root ? (root.textContent || root.innerText) : null 16910 }; 16911 cleanUp(); 16912 if (!jqXHR.responseText) { 16913 jqXHR.responseText = content.text; 16914 } 16915 completeCallback(status, statusText, content, type ? 16916 ("Content-Type: " + type) : 16917 null); 16918 }); 16919 16920 // Now that the load handler has been set up, submit the form. 16921 form[0].submit(); 16922 }); 16923 16924 // After everything has been set up correctly, the form and iframe 16925 // get injected into the DOM so that the submission can be 16926 // initiated. 16927 $("body").append(form, iframe); 16928 }, 16929 16930 // The `abort` function is called by jQuery when the request should be 16931 // aborted. 16932 abort: function() { 16933 if (iframe !== null) { 16934 iframe.unbind("load").attr("src", "javascript:false;"); 16935 cleanUp(); 16936 } 16937 } 16938 16939 }; 16940 } 16941 }); 16942 16943})(jQuery); 16944/*! 16945 * Nestable jQuery Plugin - Copyright (c) 2012 David Bushell - http://dbushell.com/ 16946 * Dual-licensed under the BSD or MIT licenses 16947 */ 16948;(function($, window, document, undefined) 16949{ 16950 var hasTouch = 'ontouchstart' in document; 16951 16952 var nestableIdCounter = 0; 16953 16954 /** 16955 * Detect CSS pointer-events property 16956 * events are normally disabled on the dragging element to avoid conflicts 16957 * https://github.com/ausi/Feature-detection-technique-for-pointer-events/blob/master/modernizr-pointerevents.js 16958 */ 16959 var hasPointerEvents = (function() 16960 { 16961 var el = document.createElement('div'), 16962 docEl = document.documentElement; 16963 if (!('pointerEvents' in el.style)) { 16964 return false;
16965 } 16966 el.style.pointerEvents = 'auto'; 16967 el.style.pointerEvents = 'x'; 16968 docEl.appendChild(el); 16969 var supports = window.getComputedStyle && window.getComputedStyle(el, '').pointerEvents === 'auto'; 16970 docEl.removeChild(el); 16971 return !!supports; 16972 })(); 16973 16974 var defaults = { 16975 listNodeName : 'ol', 16976 itemNodeName : 'li', 16977 rootClass : 'dd', 16978 listClass : 'dd-list', 16979 itemClass : 'dd-item', 16980 dragClass : 'dd-dragel', 16981 handleClass : 'dd-handle', 16982 collapsedClass : 'dd-collapsed', 16983 placeClass : 'dd-placeholder', 16984 noDragClass : 'dd-nodrag', 16985 emptyClass : 'dd-empty', 16986 expandBtnHTML : '<button data-action="expand" type="button">Expand</button>', 16987 collapseBtnHTML : '<button data-action="collapse" type="button">Collapse</button>', 16988 group : 0, 16989 maxDepth : 3, 16990 threshold : 20 16991 }; 16992 16993 function Plugin(element, options) 16994 { 16995 this.w = $(document); 16996 this.el = $(element); 16997 this.options = $.extend({}, defaults, options); 16998 this.init(); 16999 } 17000 17001 Plugin.prototype = { 17002 17003 init: function() 17004 { 17005 var list = this; 17006 17007 list.reset(); 17008 17009 list.el.data('nestable-group', this.options.group); 17010 17011 list.placeEl = $('<div class="' + list.options.placeClass + '"/>'); 17012 17013 $.each(this.el.find(list.options.itemNodeName), function(k, el) { 17014 list.setParent($(el)); 17015 }); 17016 17017 list.el.on('click', 'button', function(e) { 17018 if (list.dragEl) { 17019 return; 17020 } 17021 var target = $(e.currentTarget), 17022 action = target.data('action'), 17023 item = target.parent(list.options.itemNodeName); 17024 if (action === 'collapse') { 17025 list.collapseItem(item); 17026 } 17027 if (action === 'expand') { 17028 list.expandItem(item); 17029 } 17030 }); 17031 17032 var onStartEvent = function(e) 17033 { 17034 var handle = $(e.target); 17035 if (!handle.hasClass(list.options.handleClass)) { 17036 if (handle.closest('.' + list.options.noDragClass).length) { 17037 return; 17038 } 17039 handle = handle.closest('.' + list.options.handleClass); 17040 } 17041 17042 if (!handle.length || list.dragEl) { 17043 return; 17044 } 17045 17046 list.isTouch = /^touch/.test(e.type); 17047 if (list.isTouch && e.touches.length !== 1) { 17048 return; 17049 } 17050 17051 e.preventDefault(); 17052 list.dragStart(e.touches ? e.touches[0] : e); 17053 }; 17054 17055 var onMoveEvent = function(e) 17056 { 17057 if (list.dragEl) { 17058 e.preventDefault(); 17059 list.dragMove(e.touches ? e.touches[0] : e); 17060 } 17061 }; 17062 17063 var onEndEvent = function(e) 17064 { 17065 if (list.dragEl) { 17066 e.preventDefault(); 17067 list.dragStop(e.touches ? e.touches[0] : e); 17068 } 17069 }; 17070 17071 if (hasTouch) { 17072 list.el[0].addEventListener('touchstart', onStartEvent, false); 17073 window.addEventListener('touchmove', onMoveEvent, false); 17074 window.addEventListener('touchend', onEndEvent, false); 17075 window.addEventListener('touchcancel', onEndEvent, false); 17076 } 17077 17078 list.el.on('mousedown', onStartEvent); 17079 list.w.on('mousemove', onMoveEvent); 17080 list.w.on('mouseup', onEndEvent); 17081 17082 }, 17083 17084 serialize: function() 17085 { 17086 var data, 17087 depth = 0, 17088 list = this; 17089 step = function(level, depth) 17090 { 17091 var array = [ ], 17092 items = level.children(list.options.itemNodeName); 17093 items.each(function() 17094 { 17095 var li = $(this), 17096 item = $.extend({}, li.data()), 17097 sub = li.children(list.options.listNodeName); 17098 if (sub.length) { 17099 item.children = step(sub, depth + 1); 17100 } 17101 array.push(item); 17102 }); 17103 return array; 17104 }; 17105 data = step(list.el.find(list.options.listNodeName).first(), depth); 17106 return data; 17107 }, 17108 17109 serialise: function() 17110 { 17111 return this.serialize(); 17112 }, 17113 17114 reset: function() 17115 { 17116 this.mouse = { 17117 offsetX : 0, 17118 offsetY : 0, 17119 startX : 0, 17120 startY : 0, 17121 lastX : 0, 17122 lastY : 0, 17123 nowX : 0, 17124 nowY : 0, 17125 distX : 0, 17126 distY : 0, 17127 dirAx : 0, 17128 dirX : 0, 17129 dirY : 0, 17130 lastDirX : 0, 17131 lastDirY : 0, 17132 distAxX : 0, 17133 distAxY : 0 17134 }; 17135 this.isTouch = false;
17136 this.moving = false; 17137 this.dragEl = null; 17138 this.dragRootEl = null; 17139 this.dragDepth = 0; 17140 this.hasNewRoot = false; 17141 this.pointEl = null; 17142 }, 17143 17144 expandItem: function(li) 17145 { 17146 li.removeClass(this.options.collapsedClass); 17147 li.children('[data-action="expand"]').hide(); 17148 li.children('[data-action="collapse"]').show(); 17149 li.children(this.options.listNodeName).show(); 17150 }, 17151 17152 collapseItem: function(li) 17153 { 17154 var lists = li.children(this.options.listNodeName); 17155 if (lists.length) { 17156 li.addClass(this.options.collapsedClass); 17157 li.children('[data-action="collapse"]').hide(); 17158 li.children('[data-action="expand"]').show(); 17159 li.children(this.options.listNodeName).hide(); 17160 } 17161 }, 17162 17163 expandAll: function() 17164 { 17165 var list = this; 17166 list.el.find(list.options.itemNodeName).each(function() { 17167 list.expandItem($(this)); 17168 }); 17169 }, 17170 17171 collapseAll: function() 17172 { 17173 var list = this; 17174 list.el.find(list.options.itemNodeName).each(function() { 17175 list.collapseItem($(this)); 17176 }); 17177 }, 17178 17179 setParent: function(li) 17180 { 17181 if (li.children(this.options.listNodeName).length) { 17182 li.prepend($(this.options.expandBtnHTML)); 17183 li.prepend($(this.options.collapseBtnHTML)); 17184 } 17185 li.children('[data-action="expand"]').hide(); 17186 }, 17187 17188 unsetParent: function(li) 17189 { 17190 li.removeClass(this.options.collapsedClass); 17191 li.children('[data-action]').remove(); 17192 li.children(this.options.listNodeName).remove(); 17193 }, 17194 17195 dragStart: function(e) 17196 { 17197 var mouse = this.mouse, 17198 target = $(e.target), 17199 dragItem = target.closest(this.options.itemNodeName); 17200 17201 this.placeEl.css('height', dragItem.height()); 17202 17203 mouse.offsetX = e.offsetX !== undefined ? e.offsetX : e.pageX - target.offset().left; 17204 mouse.offsetY = e.offsetY !== undefined ? e.offsetY : e.pageY - target.offset().top; 17205 mouse.startX = mouse.lastX = e.pageX; 17206 mouse.startY = mouse.lastY = e.pageY; 17207 17208 this.dragRootEl = this.el; 17209 17210 this.dragEl = $(document.createElement(this.options.listNodeName)).addClass(this.options.listClass + ' ' + this.options.dragClass); 17211 this.dragEl.css('width', dragItem.width()); 17212 17213 dragItem.after(this.placeEl); 17214 dragItem[0].parentNode.removeChild(dragItem[0]); 17215 dragItem.appendTo(this.dragEl); 17216 17217 $(document.body).append(this.dragEl); 17218 this.dragEl.css({ 17219 'left' : e.pageX - mouse.offsetX, 17220 'top' : e.pageY - mouse.offsetY 17221 }); 17222 // total depth of dragging item 17223 var i, depth, 17224 items = this.dragEl.find(this.options.itemNodeName); 17225 for (i = 0; i < items.length; i++) { 17226 depth = $(items[i]).parents(this.options.listNodeName).length; 17227 if (depth > this.dragDepth) { 17228 this.dragDepth = depth; 17229 } 17230 } 17231 }, 17232 17233 dragStop: function(e) 17234 { 17235 var el = this.dragEl.children(this.options.itemNodeName).first(); 17236 el[0].parentNode.removeChild(el[0]); 17237 this.placeEl.replaceWith(el); 17238 17239 this.dragEl.remove(); 17240 this.el.trigger('change'); 17241 if (this.hasNewRoot) { 17242 this.dragRootEl.trigger('change'); 17243 } 17244 this.reset(); 17245 }, 17246 17247 dragMove: function(e) 17248 { 17249 var list, parent, prev, next, depth, 17250 opt = this.options, 17251 mouse = this.mouse; 17252 17253 this.dragEl.css({ 17254 'left' : e.pageX - mouse.offsetX, 17255 'top' : e.pageY - mouse.offsetY 17256 }); 17257 17258 // mouse position last events 17259 mouse.lastX = mouse.nowX; 17260 mouse.lastY = mouse.nowY; 17261 // mouse position this events 17262 mouse.nowX = e.pageX; 17263 mouse.nowY = e.pageY; 17264 // distance mouse moved between events 17265 mouse.distX = mouse.nowX - mouse.lastX; 17266 mouse.distY = mouse.nowY - mouse.lastY; 17267 // direction mouse was moving 17268 mouse.lastDirX = mouse.dirX; 17269 mouse.lastDirY = mouse.dirY; 17270 // direction mouse is now moving (on both axis) 17271 mouse.dirX = mouse.distX === 0 ? 0 : mouse.distX > 0 ? 1 : -1; 17272 mouse.dirY = mouse.distY === 0 ? 0 : mouse.distY > 0 ? 1 : -1; 17273 // axis mouse is now moving on 17274 var newAx = Math.abs(mouse.distX) > Math.abs(mouse.distY) ? 1 : 0; 17275 17276 // do nothing on first move 17277 if (!mouse.moving) { 17278 mouse.dirAx = newAx; 17279 mouse.moving = true; 17280 return; 17281 } 17282 17283 // calc distance moved on this axis (and direction) 17284 if (mouse.dirAx !== newAx) { 17285 mouse.distAxX = 0; 17286 mouse.distAxY = 0; 17287 } else { 17288 mouse.distAxX += Math.abs(mouse.distX); 17289 if (mouse.dirX !== 0 && mouse.dirX !== mouse.lastDirX) { 17290 mouse.distAxX = 0; 17291 } 17292 mouse.distAxY += Math.abs(mouse.distY); 17293 if (mouse.dirY !== 0 && mouse.dirY !== mouse.lastDirY) { 17294 mouse.distAxY = 0; 17295 } 17296 } 17297 mouse.dirAx = newAx; 17298 17299 /** 17300 * move horizontal 17301 */ 17302 if (mouse.dirAx && mouse.distAxX >= opt.threshold) { 17303 // reset move distance on x-axis for new phase 17304 mouse.distAxX = 0; 17305 prev = this.placeEl.prev(opt.itemNodeName); 17306 // increase horizontal level if previous sibling exists and is not collapsed 17307 if (mouse.distX > 0 && prev.length && !prev.hasClass(opt.collapsedClass)) { 17308 // cannot increase level when item above is collapsed 17309 list = prev.find(opt.listNodeName).last(); 17310 // check if depth limit has reached 17311 depth = this.placeEl.parents(opt.listNodeName).length; 17312 if (depth + this.dragDepth <= opt.maxDepth) { 17313 // create new sub-level if one doesn't exist 17314 if (!list.length) { 17315 list = $('<' + opt.listNodeName + '/>').addClass(opt.listClass); 17316 list.append(this.placeEl); 17317 prev.append(list); 17318 this.setParent(prev); 17319 } else { 17320 // else append to next level up 17321 list = prev.children(opt.listNodeName).last(); 17322 list.append(this.placeEl); 17323 } 17324 } 17325 } 17326 // decrease horizontal level 17327 if (mouse.distX < 0) { 17328 // we can't decrease a level if an item preceeds the current one 17329 next = this.placeEl.next(opt.itemNodeName); 17330 if (!next.length) { 17331 parent = this.placeEl.parent(); 17332 this.placeEl.closest(opt.itemNodeName).after(this.placeEl); 17333 if (!parent.children().length) { 17334 this.unsetParent(parent.parent()); 17335 } 17336 } 17337 } 17338 } 17339 17340 var isEmpty = false;
17341 17342 // find list item under cursor 17343 if (!hasPointerEvents) { 17344 this.dragEl[0].style.visibility = 'hidden'; 17345 } 17346 this.pointEl = $(document.elementFromPoint(e.pageX - document.body.scrollLeft, e.pageY - (window.pageYOffset || document.documentElement.scrollTop))); 17347 if (!hasPointerEvents) { 17348 this.dragEl[0].style.visibility = 'visible'; 17349 } 17350 if (this.pointEl.hasClass(opt.handleClass)) { 17351 this.pointEl = this.pointEl.parent(opt.itemNodeName); 17352 } 17353 if (this.pointEl.hasClass(opt.emptyClass)) { 17354 isEmpty = true; 17355 } 17356 else if (!this.pointEl.length || !this.pointEl.hasClass(opt.itemClass)) { 17357 return; 17358 } 17359 17360 // find parent list of item under cursor 17361 var pointElRoot = this.pointEl.closest('.' + opt.rootClass), 17362 isNewRoot = this.dragRootEl.data('nestable-id') !== pointElRoot.data('nestable-id'); 17363 17364 /** 17365 * move vertical 17366 */ 17367 if (!mouse.dirAx || isNewRoot || isEmpty) { 17368 // check if groups match if dragging over new root 17369 if (isNewRoot && opt.group !== pointElRoot.data('nestable-group')) { 17370 return; 17371 } 17372 // check depth limit 17373 depth = this.dragDepth - 1 + this.pointEl.parents(opt.listNodeName).length; 17374 if (depth > opt.maxDepth) { 17375 return; 17376 } 17377 var before = e.pageY < (this.pointEl.offset().top + this.pointEl.height() / 2); 17378 parent = this.placeEl.parent(); 17379 // if empty create new list to replace empty placeholder 17380 if (isEmpty) { 17381 list = $(document.createElement(opt.listNodeName)).addClass(opt.listClass); 17382 list.append(this.placeEl); 17383 this.pointEl.replaceWith(list); 17384 } 17385 else if (before) { 17386 this.pointEl.before(this.placeEl); 17387 } 17388 else { 17389 this.pointEl.after(this.placeEl); 17390 } 17391 if (!parent.children().length) { 17392 this.unsetParent(parent.parent()); 17393 } 17394 if (!this.dragRootEl.find(opt.itemNodeName).length && !this.dragRootEl.find('div.'+opt.placeClass).length && !this.dragRootEl.find('div.'+opt.emptyClass).length) { 17395 this.dragRootEl.append('<div class="' + opt.emptyClass + '"/>'); 17396 } 17397 // parent root list has changed 17398 if (isNewRoot) { 17399 this.dragRootEl = pointElRoot; 17400 this.hasNewRoot = this.el[0] !== this.dragRootEl[0]; 17401 } 17402 } 17403 } 17404 17405 }; 17406 17407 $.fn.nestable = function(params) 17408 { 17409 var lists = this, 17410 retval = this; 17411 17412 lists.each(function() 17413 { 17414 var plugin = $(this).data("nestable"); 17415 17416 if (!plugin) { 17417 $(this).data("nestable", new Plugin(this, params)); 17418 $(this).data("nestable-id", ++nestableIdCounter); 17419 } else { 17420 if (typeof params === 'string' && typeof plugin[params] === 'function') { 17421 retval = plugin[params](); 17422 } 17423 } 17424 }); 17425 17426 return retval || lists; 17427 }; 17428 17429})(window.jQuery || window.Zepto, window, document); 17430 17431 17432 17433(function($) { 17434 17435 var remotipart; 17436 17437 $.remotipart = remotipart = { 17438 17439 setup: function(form) { 17440 // Preserve form.data('ujs:submit-button') before it gets nulled by $.ajax.handleRemote 17441 var button = form.data('ujs:submit-button'), 17442 csrfParam = $('meta[name="csrf-param"]').attr('content'), 17443 csrfToken = $('meta[name="csrf-token"]').attr('content'), 17444 csrfInput = form.find('input[name="' + csrfParam + '"]').length; 17445 17446 form 17447 // Allow setup part of $.rails.handleRemote to setup remote settings before canceling default remote handler 17448 // This is required in order to change the remote settings using the form details 17449 .one('ajax:beforeSend.remotipart', function(e, xhr, settings){ 17450 // Delete the beforeSend bindings, since we're about to re-submit via ajaxSubmit with the beforeSubmit 17451 // hook that was just setup and triggered via the default `$.rails.handleRemote` 17452 // delete settings.beforeSend; 17453 delete settings.beforeSend; 17454 17455 settings.iframe = true; 17456 settings.files = $($.rails.fileInputSelector, form); 17457 settings.data = form.serializeArray(); 17458 17459 // Insert the name/value of the clicked submit button, if any 17460 if (button) 17461 settings.data.push(button); 17462 17463 // jQuery 1.9 serializeArray() contains input:file entries 17464 // so exclude them from settings.data, otherwise files will not be sent 17465 settings.files.each(function(i, file){ 17466 for (var j = settings.data.length - 1; j >= 0; j--) 17467 if (settings.data[j].name == file.name) 17468 settings.data.splice(j, 1); 17469 }) 17470 17471 settings.processData = false;
17472 17473 // Modify some settings to integrate JS request with rails helpers and middleware 17474 if (settings.dataType === undefined) { settings.dataType = 'script *'; } 17475 settings.data.push({name: 'remotipart_submitted', value: true}); 17476 if (csrfToken && csrfParam && !csrfInput) { 17477 settings.data.push({name: csrfParam, value: csrfToken}); 17478 } 17479 17480 // Allow remotipartSubmit to be cancelled if needed 17481 if ($.rails.fire(form, 'ajax:remotipartSubmit', [xhr, settings])) { 17482 // Second verse, same as the first 17483 $.rails.ajax(settings).complete(function(data){ 17484 $.rails.fire(form, 'ajax:remotipartComplete', [data]); 17485 }); 17486 setTimeout(function(){ $.rails.disableFormElements(form); }, 20); 17487 } 17488 17489 //Run cleanup 17490 remotipart.teardown(form); 17491 17492 // Cancel the jQuery UJS request 17493 return false; 17494 }) 17495 17496 // Keep track that we just set this particular form with Remotipart bindings 17497 // Note: The `true` value will get over-written with the `settings.dataType` from the `ajax:beforeSend` handler 17498 .data('remotipartSubmitted', true); 17499 }, 17500 17501 teardown: function(form) { 17502 form 17503 .unbind('ajax:beforeSend.remotipart') 17504 .removeData('remotipartSubmitted') 17505 } 17506 }; 17507 17508 $(document).on('ajax:aborted:file', 'form', function(){ 17509 var form = $(this); 17510 17511 remotipart.setup(form); 17512 17513 // Manually call jquery-ujs remote call so that it can setup form and settings as usual, 17514 // and trigger the `ajax:beforeSend` callback to which remotipart binds functionality. 17515 $.rails.handleRemote(form); 17516 return false; 17517 }); 17518 17519})(jQuery); 17520 17521function start_matrix() { 17522 17523 $('ol.matrix').each(function(){ 17524 17525 refresh_matrix($(this)); 17526 $('div.checkbox.active input', $(this)).change(function(){ 17527 refresh_matrix($(this).parents('ol.matrix')); 17528 $('div.checkbox.required input', $(this).parents('li.row')).prop('checked', true); 17529 }); 17530 17531 }); 17532 17533} 17534 17535function refresh_matrix($matrix) { 17536 17537 $('div.checkbox.active', $matrix).each(function(){ 17538 if ($('input', $(this)).is(':checked')) { 17539 $('div.checkbox.required', $(this).parents('li.row')).show(); 17540 $('div.label', $(this).parents('li.row')).show(); 17541 } else { 17542 $('div.checkbox.required', $(this).parents('li.row')).hide(); 17543 $('div.label', $(this).parents('li.row')).hide(); 17544 } 17545 }); 17546 17547} 17548 17549function start_matrix_sort() { 17550 17551 $('ol.matrix').each(function(){ 17552 refresh_matrix_sort($(this)); 17553 }); 17554 17555 $('div.matrixsort').nestable({ 17556 maxDepth: 1, 17557 rootClass: 'matrixsort', 17558 listClass: 'matrix', 17559 itemClass: 'row', 17560 dragClass: 'dragging', 17561 handleClass: 'weight', 17562 placeClass: 'place' 17563 }); 17564 $('div.matrixsort').on('change', function() { 17565 refresh_matrix_sort($('ol.matrix')); 17566 }); 17567 17568} 17569 17570function refresh_matrix_sort($sortlist) { 17571 17572 $('select[id$="weight"]', $sortlist).each(function(index){ 17573 $(this).val($(this).parents('li').index()+1); 17574 }); 17575 17576}; 17577 17578function start_modal(content) { 17579 17580 $('body').addClass('modal'); 17581 17582 $('#cover').fadeIn('fast'); 17583 $('#cover').click(function(){ 17584 //close_modal(); 17585 }); 17586 17587 $('#modal').html(content+'<div class="white">.</div>'); 17588 $('#window').show(); 17589 $('#window').click(function(e) { 17590 if (e.target == this) { 17591 //close_modal(); 17592 } 17593 }); 17594 17595 $('#window .close').click(function(event){ 17596 close_modal(); 17597 event.preventDefault(); 17598 }); 17599 17600 set_cursor($('#modal form:first')); 17601 17602} 17603 17604function close_modal() { 17605 17606 $('#modal').html(''); 17607 $('#window').hide(); 17608 $('#cover').fadeOut('fast', function(){ 17609 $('body').removeClass('modal'); 17610 }); 17611 17612}; 17613function start_match_panels($panels, $target) { 17614 17615 resize_match_panels($panels, $target); 17616 $(window).on('resize', function(){ 17617 resize_match_panels($panels, $target); 17618 }); 17619 17620} 17621 17622function resize_match_panels($panels, $target) { 17623 17624 $('div.panel '+$target, $panels).css('min-height', '0px'); 17625 $max_height = 0; 17626 $('div.panel '+$target, $panels).each(function(){ 17627 if ($(this).height() > $max_height) { 17628 $max_height = $(this).height(); 17629 } 17630 }); 17631 $('div.panel '+$target, $panels).css('min-height', $max_height+'px'); 17632 17633}; 17634 17635function start_picker() { 17636 17637 $('input.hex').each(function(){ 17638 set_picker_style($(this)); 17639 }); 17640 17641 $('a.picker').each(function(){ 17642 17643 var $field = $(this).data('field'); 17644 17645 var $swatch = $('<div data-field="'+$field+'" class="popup swatch"></div>'); 17646 $swatch.append('<div class="close">×</div>');
17647 $swatch.append('<canvas id="'+$field+'_swatch" width="320" height="240" />'); 17648 17649 $(this).parents('div.field').append($swatch); 17650 17651 var $context = document.getElementById($field+'_swatch').getContext('2d'); 17652 17653 var img = new Image(); 17654 img.src = '/assets/picker-bf36f247dd81d0bdda18cf27e78a8db916cb4c0c4323d6637bd8a23b6bf4e06d.png'; 17655 $(img).load(function(){ 17656 $context.drawImage(img,0,0) 17657 }); 17658 17659 $('div.colour', $swatch).each(function(){ 17660 $(this).css('background-color', $(this).data('colour')); 17661 }); 17662 17663 $('div.colour', $swatch).click(function(){ 17664 $input = $('input.hex', $(this).parents('div.field')) 17665 $input.val($(this).data('colour')); 17666 set_picker_style($input); 17667 }); 17668 17669 $('canvas', $swatch).click(function(event){ 17670 17671 // getting user coordinates 17672 var x = parseInt((event.pageX - $(this).offset().left),10); 17673 var y = parseInt((event.pageY - $(this).offset().top),10); 17674 // getting image data and RGB values 17675 var img_data = $context.getImageData(x, y, 1, 1).data; 17676 console.log(img_data); 17677 var R = img_data[0]; 17678 var G = img_data[1]; 17679 var B = img_data[2]; 17680 var rgb = R + ',' + G + ',' + B; 17681 // convert RGB to HEX 17682 var hex = rgbToHex(R,G,B); 17683 // making the color the value of the input 17684 17685 $input = $('input.hex', $(this).parents('div.field')) 17686 $input.val('#' + hex); 17687 set_picker_style($input); 17688 17689 }); 17690 17691 $('div.close', $swatch).click(function(){ 17692 $(this).parents('div.swatch').hide(); 17693 }); 17694 17695 $swatch.hide(); 17696 }); 17697 $('input.hex').keyup(function(){ 17698 set_picker_style($(this)); 17699 }); 17700 $('input.hex').change(function(){ 17701 set_picker_style($(this)); 17702 }); 17703 $('a.picker').click(function($event){ 17704 $('div.swatch', $(this).parents('div.field')).toggle(); 17705 $event.preventDefault(); 17706 }); 17707 17708} 17709 17710function rgbToHex(R,G,B) {return toHex(R)+toHex(G)+toHex(B)} 17711function toHex(n) { 17712 n = parseInt(n,10); 17713 if (isNaN(n)) return "00"; 17714 n = Math.max(0,Math.min(n,255)); 17715 return "0123456789ABCDEF".charAt((n-n%16)/16) + "0123456789ABCDEF".charAt(n%16); 17716} 17717 17718function is_dark($colour) { 17719 if (parseInt($colour.replace('#', ''), 16) < (0xffffff / 1.5)) { 17720 return true; 17721 } else { 17722 return false; 17723 } 17724} 17725 17726function set_picker_style($picker) { 17727 17728 if (($picker.val().length == 4)||($picker.val().length == 7)) { 17729 $('div.square', $picker.parents('div.field')).css('background-color', $picker.val()); 17730 } 17731 17732}; 17733 17734function start_preview() { 17735 17736 $('div.preview a').click(function(e){e.preventDefault()}); 17737 $('input').change(refresh_preview); 17738 $('input').keyup(refresh_preview); 17739 $('select').change(refresh_preview); 17740 $('textarea').change(refresh_preview); 17741 $('textarea').keyup(refresh_preview); 17742 17743 refresh_preview(); 17744 17745} 17746 17747function refresh_preview() { 17748 17749 $('div.domain').each(function(){ 17750 $(this).hide(); 17751 if ($('input#tenant_subdomain').val() != '') { 17752 $('input#tenant_subdomain').val($('input#tenant_subdomain').val().replace('\'','')); 17753 $('pre', this).html('https://'+$('input#tenant_subdomain').val()+'.whitefuse.net'); 17754 $(this).show(); 17755 } 17756 }); 17757 17758 $('div.row.logo').each(function(){ 17759 $('div.frame', $(this)).css('background-color', $('input[id^=theme_colour_header_back]:checked').val()); 17760 }); 17761 17762 $('div.preview.fonts').each(function(){ 17763 $('.heading1', this).css('font-family', $('input[id^=theme_font_heading1]:checked').val()); 17764 $('.heading1', this).css('font-weight', $('input[id^=theme_heading1_font_weight]:checked').val()); 17765 $('.heading2', this).css('font-family', $('input[id^=theme_font_heading2]:checked').val()); 17766 $('.heading2', this).css('font-weight', $('input[id^=theme_heading2_font_weight]:checked').val()); 17767 $('.heading3', this).css('font-family', $('input[id^=theme_font_heading3]:checked').val()); 17768 $('.heading3', this).css('font-weight', $('input[id^=theme_heading3_font_weight]:checked').val()); 17769 $('.heading4', this).css('font-family', $('input[id^=theme_font_heading4]:checked').val()); 17770 $('.heading4', this).css('font-weight', $('input[id^=theme_heading4_font_weight]:checked').val()); 17771 $('.quote', this).css('font-family', $('input[id^=theme_font_quote]:checked').val()); 17772 $('.quote', this).css('font-weight', $('input[id^=theme_quote_font_weight]:checked').val()); 17773 }); 17774 17775 $('div.preview.link').each(function(){ 17776 $('a', this).css('color', $('input[id^=theme_colour_link_text]:checked').val()); 17777 }); 17778 17779 $('div.preview.button').each(function(){ 17780 $('a.button', this).css('color', $('input#theme_colour_button_text').val()); 17781 $('a.button', this).css('background-color', $('input[id^=theme_colour_button_back]:checked').val()); 17782 switch ($('input[id^=theme_button_radius]:checked').val()) { 17783 case 'small': 17784 $('a.button', this).css('padding', '8px 10px'); 17785 $('a.button', this).css('border-radius', '2px'); 17786 break; 17787 case 'large': 17788 $('a.button', this).css('padding', '8px 15px'); 17789 $('a.button', this).css('border-radius', '100px'); 17790 break; 17791 } 17792 }); 17793 17794 $('div.preview.signpost').each(function(){ 17795 $('span.title', this).html($('input#signpost_title').val()); 17796 $('span.body', this).html($('textarea#signpost_body').val()); 17797 $('a.signpost', this).css('color', $('input#theme_colour_signpost_text').val()); 17798 $('a.signpost', this).css('background-color', $('input[id^=theme_colour_signpost_back]:checked').val()); 17799 $('span.title', this).css('font-family', $('input[id^=theme_font_signpost_title]:checked').val()); 17800 $('span.title', this).css('font-weight', $('input[id^=theme_signpost_title_font_weight]:checked').val()); 17801 switch ($('input[id^=theme_signpost_radius]:checked').val()) { 17802 case 'small': 17803 $('a.signpost', this).css('border-radius', '2px'); 17804 break; 17805 case 'large': 17806 $('a.signpost', this).css('border-radius', '10px'); 17807 break; 17808 } 17809 }); 17810 17811 $('div.preview.header').each(function(){ 17812 $('div.header', this).css('color', $('input#theme_colour_header_text').val()); 17813 $('div.header', this).css('background-color', $('input[id^=theme_colour_header_back]:checked').val()); 17814 $('div.header div.menu', this).css('font-family', $('input[id^=theme_menu_font_family]:checked').val()); 17815 $('div.header div.menu', this).css('font-weight', $('input[id^=theme_header_menu_font_weight]:checked').val()); 17816 $('div.header div.menu a', this).css('color', $('input[id^=theme_colour_menu_text]:checked').val()); 17817 $('div.header div.menu a', this).css('background-color', $('input[id^=theme_colour_menu_back]:checked').val()); 17818 switch ($('input[id^=theme_menu_font_size]:checked').val()) { 17819 case 'small': 17820 $('div.header div.menu', this).css('line-height', '22px'); 17821 $('div.header div.menu', this).css('font-size', '16px'); 17822 $('div.header div.menu a', this).css('padding', '5px 8px'); 17823 break; 17824 case 'large': 17825 $('div.header div.menu', this).css('line-height', '26px'); 17826 $('div.header div.menu', this).css('font-size', '20px'); 17827 $('div.header div.menu a', this).css('padding', '5px 10px'); 17828 break; 17829 } 17830 switch ($('input[id^=theme_menu_radius]:checked').val()) { 17831 case 'small': 17832 $('div.header div.menu a', this).css('border-radius', '2px'); 17833 break; 17834 case 'large': 17835 $('div.header div.menu a', this).css('padding', '5px 10px'); 17836 $('div.header div.menu a', this).css('border-radius', '100px'); 17837 break; 17838 } 17839 if ($('input[id^=theme_number_menu_highlight]:checked').val()) { 17840 $('div.header div.menu a:last-child', this).css('color', '#FFFFFF'); 17841 if (($('input[id^=theme_colour_menu_text]:checked').val() == $('input[id^=theme_colour_
178411]').val()) || ($('input[id^=theme_colour_menu_back]:checked').val() == $('input[id^=theme_colour_1]').val())) { 17842 $('div.header div.menu a:last-child', this).css('background-color', $('input[id^=theme_colour_2]').val()); 17843 } else { 17844 $('div.header div.menu a:last-child', this).css('background-color', $('input[id^=theme_colour_1]').val()); 17845 } 17846 } 17847 }); 17848 17849 $('div.preview.banner').each(function(){ 17850 $('div.banner', this).css('background-color', $('input[id^=theme_banner_cover_colour]:checked').val()); 17851 switch ($('select[id^=theme_banner_cover_shade]').val()) { 17852 case '0': 17853 $('div.cover', this).css('opacity', '0'); 17854 break; 17855 case '40': 17856 $('div.cover', this).css('opacity', '0.4'); 17857 break; 17858 default: 17859 $('div.cover', this).css('opacity', '0.2'); 17860 break; 17861 } 17862 }); 17863 17864 $('div.preview.content').each(function(){ 17865 if ($('input[id^=theme_colour_box_back]:checked').val() == '#F6F6F6') { 17866 $('div.box div.cover', this).hide(); 17867 $('div.box', this).css('border-color', '#E0E0E0'); 17868 } else { 17869 $('div.box div.cover', this).show(); 17870 $('div.box', this).css('border-color', $('input[id^=theme_colour_box_back]:checked').val()); 17871 } 17872 $('div.box', this).css('background-color', $('input[id^=theme_colour_box_back]:checked').val()); 17873 }); 17874 17875 $('div.preview.footer').each(function(){ 17876 if ($('input[id^=theme_colour_ribbon_back]:checked').val() == '#F6F6F6') { 17877 $('div.ribbon', this).css('color', '#222222'); 17878 $('div.ribbon div.cover', this).hide(); 17879 } else { 17880 $('div.ribbon', this).css('color', '#FFFFFF'); 17881 $('div.ribbon div.cover', this).show(); 17882 } 17883 $('div.ribbon', this).css('background-color', $('input[id^=theme_colour_ribbon_back]:checked').val()); 17884 }); 17885 17886}; 17887 17888function start_questions($type, $subtype) { 17889 17890 $('div.questions').each(function(){ 17891 start_questions_delete($(this)); 17892 $('select[id$="_input"]', $(this)).each(function(){ 17893 refresh_input_options($(this)); 17894 $(this).change(function(){ 17895 refresh_input_options($(this)); 17896 }); 17897 }); 17898 $('select[id$="_input"]', $(this)).change(function(){ 17899 refresh_input_options($(this)); 17900 }); 17901 $('ol.options', $(this)).each(function(){ 17902 create_add_option_link($(this), $type, $subtype); 17903 }); 17904 create_add_question_link($(this), $type, $subtype); 17905 }); 17906 17907} 17908 17909function start_questions_delete($questions) { 17910 17911 $('input.question.deactivate').click(function(){ 17912 if ($(this).not(':checked')) { 17913 $(this).parents('section.question').hide(); 17914 } 17915 }) 17916 17917 $('input.question.delete').click(function(){ 17918 if ($(this).is(':checked')) { 17919 $(this).parents('section.question').hide(); 17920 } 17921 }) 17922 17923 $('input.option.delete').click(function(){ 17924 if ($(this).is(':checked')) { 17925 $(this).parents('li.option').hide(); 17926 } 17927 }) 17928 17929} 17930 17931function start_question_sort() { 17932 17933 $('div.questions').each(function(){ 17934 refresh_question_sort($(this)); 17935 $('a.raise', $(this)).click(function($event){ 17936 raise_question($(this).parents('section.question')); 17937 $event.preventDefault(); 17938 }); 17939 $('a.lower', $(this)).click(function($event){ 17940 lower_question($(this).parents('section.question')); 17941 $event.preventDefault(); 17942 }); 17943 }); 17944 17945} 17946 17947function raise_question($question) { 17948 if ($question.prev().is('section')) { 17949 $question.prev().insertAfter($question); 17950 refresh_question_sort($question.parents('div.questions')); 17951 } 17952} 17953 17954function lower_question($question) { 17955 if ($question.next().is('section')) { 17956 $question.next().insertBefore($question); 17957 refresh_question_sort($question.parents('div.questions')); 17958 } 17959} 17960 17961function refresh_question_sort($questions) { 17962 17963 $('select[id$="weight"]', $questions).each(function(index){ 17964 $(this).val($(this).parents('section').index()+1); 17965 }); 17966 17967} 17968 17969function refresh_input_options($select) { 17970 17971 $('div.optionsort', $select.parents('div.input')).hide(); 17972 if ($('option:selected', $select).attr('class') == 'options') { 17973 $('div.optionsort', $select.parents('div.input')).show(); 17974 } 17975 17976} 17977 17978function create_add_question_link($questions, $type, $subtype) { 17979 17980 $actions = $('<div class="actions"></div>'); 17981 $link = $('<a href="#" class="create mdi mdi-plus">Add a question</a>'); 17982 $link.click(function($event){ 17983 $count = $('section.question', $questions).length; 17984 $section_question = $('<section class="question box" data-row="'+$count+'"></section>'); 17985 $div_actions = $('<div class="actions icons-1"></div>'); 17986 $div_actions_delete = $('<a href="#" class="delete icon mdi mdi-delete"><span>
17986Delete</span></a>'); 17987 $div_actions_delete.click(function($event){ 17988 $(this).parents('section.question').remove(); 17989 $event.preventDefault(); 17990 }); 17991 $div_actions.append($div_actions_delete); 17992 $section_question.append($div_actions); 17993 $div_weight = $('<div class="weight"></div>'); 17994 $div_weight_raise = $('<a href="#" class="icon raise mdi mdi-menu-up"><span>Raise</span></a>'); 17995 $div_weight_raise.click(function($event){ 17996 raise_question($(this).parents('section.question')); 17997 refresh_question_sort($(this).parents('div.questions')); 17998 $event.preventDefault(); 17999 }); 18000 $div_weight.append($div_weight_raise); 18001 $div_weight_lower = $('<a href="#" class="icon lower mdi mdi-menu-down"><span>Lower</span></a>'); 18002 $div_weight_lower.click(function($event){ 18003 lower_question($(this).parents('section.question')); 18004 refresh_question_sort($(this).parents('div.questions')); 18005 $event.preventDefault(); 18006 }); 18007 $div_weight.append($div_weight_lower); 18008 $div_weight_row = $('<div class="row select weight"></div>'); 18009 //$div_weight_row.append($('<div class="label"><label for="'+$type+'_'+$subtype+'_questions_attributes_'+$count+'_weight">Weight</label></div>')); 18010 $div_weight_row_field = $('<div class="field"></div>'); 18011 $div_weight_row_field_select = $('<select name="'+$type+'['+$subtype+'_questions_attributes]['+$count+'][weight]" id="'+$type+'_'+$subtype+'_questions_attributes_'+$count+'_weight"></select>'); 18012 for (var $i = 0; $i <= 20; $i++) { 18013 if ($i == 0) { 18014 $div_weight_row_field_select.append($('<option selected="selected" value="0">0</option>')); 18015 } else { 18016 $div_weight_row_field_select.append($('<option value="'+$i+'">'+$i+'</option>')); 18017 } 18018 } 18019 $div_weight_row_field.append($div_weight_row_field_select); 18020 $div_weight_row.append($div_weight_row_field); 18021 $div_weight.append($div_weight_row); 18022 $section_question.append($div_weight); 18023 $div_label = $('<div class="label"></div>'); 18024 $div_label.append($('<input type="hidden" name="'+$type+'['+$subtype+'_questions_attributes]['+$count+'][question_attributes][type]" value="SubmissionQuestion" />')); 18025 $div_label.append($('<div class="row text label snug"><div class="label"><label for="'+$type+'_'+$subtype+'_questions_attributes_'+$count+'_question_attributes_label">Question</label></div><div class="field"><input value="" size="50" type="text" name="'+$type+'['+$subtype+'_questions_attributes]['+$count+'][question_attributes][label]" id="'+$type+'_'+$subtype+'_questions_attributes_'+$count+'_question_attributes_label"></div></div>')); 18026 $section_question.append($div_label); 18027 $section_question.append(' '); 18028 $div_required = $('<div class="required"></div>'); 18029 $div_required.append($('<div class="row inline checkbox required"><div class="field"><div class="checkbox"><input name="'+$type+'['+$subtype+'_questions_attributes]['+$count+'][required]" type="hidden" value="0"><input type="checkbox" value="1" name="'+$type+'['+$subtype+'_questions_attributes]['+$count+'][required]" id="'+$type+'_'+$subtype+'_questions_attributes_'+$count+'_required"> <label for="'+$type+'_'+$subtype+'_questions_attributes_'+$count+'_required">Require</label></div></div></div>')); 18030 $section_question.append($div_required); 18031 $div_input = $('<div class="input"></div>'); 18032 $div_input_row = $('<div class="row select input"></div>'); 18033 $div_input_row.append('<div class="label"><label for="'+$type+'_'+$subtype+'_questions_attributes_'+$count+'_question_attributes_input">Response</label></div>'); 18034 $div_input_row_field = $('<div class="field"></div>'); 18035 $div_input_row_field_select = $('<select name="'+$type+'['+$subtype+'_questions_attributes]['+$count+'][question_attributes][input]" id="'+$type+'_'+$subtype+'_questions_attributes_'+$count+'_question_attributes_input"></select>'); 18036 $div_input_row_field_select.append($('<option value="text" selected="selected">Text (single line)</option>')); 18037 $div_input_row_field_select.append($('<option value="textarea">Text (paragraph)</option>')); 18038 $div_input_row_field_select.append($('<option value="date">Date</option></select>')); 18039 $div_input_row_field_select.append($('<option class="options" value="select">Drop-down</option>')); 18040 $div_input_row_field_select.append($('<option class="options" value="radios">Radio buttons</option>')); 18041 $div_input_row_field_select.append($('<option class="options" value="checkboxes">Checkboxes</option>')); 18042 $div_input_row_field_select.change(function(){ 18043 refresh_input_options($(this)); 18044 }); 18045 $div_input_row_field.append($div_input_row_field_select); 18046 $div_input_row.append($div_input_row_field); 18047 $div_input.append($div_input_row); 18048 $div_input_options = $('<div class="optionsort"></div>'); 18049 $div_input_options_list = $('<ol class="options"></ol>'); 18050 for (var $i = 0; $i < 2; $i++) { 18051 $div_input_options_list_li = $('<li class="option"></li>'); 18052 $div_input_options_list_li.append($('<div class="weight"><span class="mdi mdi-drag-vertical"></span>
18052<div class="row select weight"><div class="field"><select name="'+$type+'['+$subtype+'_questions_attributes]['+$count+'][question_attributes][question_options_attributes]['+$i+'][weight]" id="'+$type+'_'+$subtype+'_questions_attributes_'+$count+'_question_attributes_question_options_attributes_'+$i+'_weight"><option selected="selected" value="0">0</option><option value="1">1</option><option value="2">2</option><option value="3">3</option><option value="4">4</option><option value="5">5</option><option value="6">6</option><option value="7">7</option><option value="8">8</option><option value="9">9</option><option value="10">10</option><option value="11">11</option><option value="12">12</option><option value="13">13</option><option value="14">14</option><option value="15">15</option><option value="16">16</option><option value="17">17</option><option value="18">18</option><option value="19">19</option><option value="20">20</option></select></div></div></div>')); 18053 $div_input_options_list_li.append($('<div><div class="row text option"><div class="field"><input value="" size="50" type="text" name="'+$type+'['+$subtype+'_questions_attributes]['+$count+'][question_attributes][question_options_attributes]['+$i+'][option]" id="'+$type+'_'+$subtype+'_questions_attributes_'+$count+'_question_attributes_question_options_attributes_'+$i+'_option" placeholder="Option"></div></div></div>')); 18054 $div_input_options_list_li.append($('<div class="actions icons-1"></div>')); 18055 $div_input_options_list.append($div_input_options_list_li); 18056 } 18057 $div_input_options.append($div_input_options_list); 18058 $div_input_options.hide(); 18059 create_add_option_link($div_input_options_list, $type, $subtype); 18060 $div_input.append($div_input_options); 18061 $section_question.append($div_input); 18062 $questions.append($section_question); 18063 refresh_question_sort($questions); 18064 start_option_sort(); 18065 $event.preventDefault(); 18066 }); 18067 $actions.append($link); 18068 $questions.after($actions); 18069 18070} 18071 18072function create_add_option_link($list, $type, $subtype) { 18073 18074 $actions = $('<div class="actions"></div>'); 18075 var $link = $('<a href="#" class="create mdi mdi-plus">Add an option</a>'); 18076 $link.click(function(event){ 18077 $row = $(this).parents('section.question').data('row'); 18078 $count = $('li.option', $list).length; 18079 $li_option = $('<li class="option"></li>'); 18080 $div_weight = $('<div class="weight"></div>'); 18081 $div_weight.append($('<span class="mdi mdi-drag-vertical"></span>')); 18082 $div_weight_row = $('<div class="row select weight"></div>'); 18083 $div_weight_row.append($('<div class="field"><select name="'+$type+'['+$subtype+'_questions_attributes]['+$row+'][question_attributes][question_options_attributes]['+$count+'][weight]" id="'+$type+'_'+$subtype+'_questions_attributes_'+$row+'_question_attributes_question_options_attributes_'+$count+'_weight"><option selected="selected" value="0">0</option><option value="1">1</option><option value="2">2</option><option value="3">3</option><option value="4">4</option><option value="5">5</option><option value="6">6</option><option value="7">7</option><option value="8">8</option><option value="9">9</option><option value="10">10</option><option value="11">11</option><option value="12">12</option><option value="13">13</option><option value="14">14</option><option value="15">15</option><option value="16">16</option><option value="17">17</option><option value="18">18</option><option value="19">19</option><option value="20">20</option></select></div>')); 18084 $div_weight.append($div_weight_row); 18085 $li_option.append($div_weight); 18086 $li_option.append(' '); 18087 $div_option = $('<div class="option"></div>'); 18088 $div_option_row = $('<div class="row text option"></div>'); 18089 $div_option_row.append($('<div class="field"><input size="50" type="text" name="'+$type+'['+$subtype+'_questions_attributes]['+$row+'][question_attributes][question_options_attributes]['+$count+'][option]" id="'+$type+'_'+$subtype+'_questions_attributes_'+$row+'_question_attributes_question_options_attributes_'+$count+'_option" placeholder="Option"></div>')); 18090 $div_option.append($div_option_row); 18091 $li_option.append($div_option); 18092 $li_option.append(' '); 18093 $div_actions = $('<div class="actions icons-1"></div>'); 18094 $div_actions_delete = $('<a href="#" class="delete icon mdi mdi-delete"><span>
18094Delete</span></a>'); 18095 $div_actions_delete.click(function($event){ 18096 $(this).parents('li.option').remove(); 18097 refresh_option_sort($('ol.options', $(this).parents('div.optionsort'))); 18098 $event.preventDefault(); 18099 }); 18100 $div_actions.append($div_actions_delete); 18101 $li_option.append($div_actions); 18102 $list.append($li_option); 18103 refresh_option_sort($('ol.options', $(this).parents('div.optionsort'))); 18104 event.preventDefault(); 18105 }); 18106 $actions.append($link); 18107 $list.after($actions); 18108 18109}; 18110/* 18111 Redactor II 18112 Version 2.12 18113 Updated: December 4, 2017 18114 18115 http://imperavi.com/redactor/ 18116 18117 Copyright (c) 2009-2017, Imperavi LLC. 18118 License: http://imperavi.com/redactor/license/ 18119 18120 Usage: $('#content').redactor(); 18121*/ 18122 18123(function($) 18124{ 18125 'use strict'; 18126 18127 if (!Function.prototype.bind) 18128 { 18129 Function.prototype.bind = function(scope) 18130 { 18131 var fn = this; 18132 return function() 18133 { 18134 return fn.apply(scope); 18135 }; 18136 }; 18137 } 18138 18139 var uuid = 0; 18140 18141 // Plugin 18142 $.fn.redactor = function(options) 18143 { 18144 var val = []; 18145 var args = Array.prototype.slice.call(arguments, 1); 18146 18147 if (typeof options === 'string') 18148 { 18149 this.each(function() 18150 { 18151 var instance = $.data(this, 'redactor'); 18152 var func; 18153 18154 if (options.search(/\./) !== '-1') 18155 { 18156 func = options.split('.'); 18157 if (typeof instance[func[0]] !== 'undefined') 18158 { 18159 func = instance[func[0]][func[1]]; 18160 } 18161 } 18162 else 18163 { 18164 func = instance[options]; 18165 } 18166 18167 if (typeof instance !== 'undefined' && $.isFunction(func)) 18168 { 18169 var methodVal = func.apply(instance, args); 18170 if (methodVal !== undefined && methodVal !== instance) 18171 { 18172 val.push(methodVal); 18173 } 18174 } 18175 else 18176 { 18177 $.error('No such method "' + options + '" for Redactor'); 18178 } 18179 }); 18180 } 18181 else 18182 { 18183 this.each(function() 18184 { 18185 $.data(this, 'redactor', {}); 18186 $.data(this, 'redactor', Redactor(this, options)); 18187 }); 18188 } 18189 18190 if (val.length === 0) 18191 { 18192 return this; 18193 } 18194 else if (val.length === 1) 18195 { 18196 return val[0]; 18197 } 18198 else 18199 { 18200 return val; 18201 } 18202 18203 }; 18204 18205 // Initialization 18206 function Redactor(el, options) 18207 { 18208 return new Redactor.prototype.init(el, options); 18209 } 18210 18211 // Options 18212 $.Redactor = Redactor; 18213 $.Redactor.VERSION = '2.12'; 18214 $.Redactor.modules = ['air', 'autosave', 'block', 'buffer', 'build', 'button', 'caret', 'clean', 'code', 'core', 'detect', 'dropdown', 18215 'events', 'file', 'focus', 'image', 'indent', 'inline', 'insert', 'keydown', 'keyup', 18216 'lang', 'line', 'link', 'linkify', 'list', 'marker', 'modal', 'observe', 'offset', 'paragraphize', 'paste', 'placeholder', 18217 'progress', 'selection', 'shortcuts', 'storage', 'toolbar', 'upload', 'uploads3', 'utils', 18218 18219 'browser' // deprecated 18220 ]; 18221 18222 $.Redactor.settings = {}; 18223 $.Redactor.opts = { 18224 18225 // settings 18226 animation: false, 18227 lang: 'en', 18228 direction: 'ltr', 18229 spellcheck: true, 18230 overrideStyles: true,
18231 stylesClass: false, 18232 scrollTarget: document, 18233 18234 focus: false, 18235 focusEnd: false, 18236 18237 clickToEdit: false, 18238 structure: false, 18239 18240 tabindex: false, 18241 18242 minHeight: false, // string 18243 maxHeight: false, // string 18244 18245 maxWidth: false, // string 18246 18247 plugins: false, // array 18248 callbacks: {}, 18249 18250 placeholder: false, 18251 18252 linkify: true, 18253 enterKey: true, 18254 18255 pastePlainText: false, 18256 pasteImages: true, 18257 pasteLinks: true, 18258 pasteBlockTags: ['pre', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'table', 'tbody', 'thead', 'tfoot', 'th', 'tr', 'td', 'ul', 'ol', 'li', 'blockquote', 'p', 'figure', 'figcaption'], 18259 pasteInlineTags: ['br', 'strong', 'ins', 'code', 'del', 'span', 'samp', 'kbd', 'sup', 'sub', 'mark', 'var', 'cite', 'small', 'b', 'u', 'em', 'i'], 18260 18261 preClass: false, // string 18262 preSpaces: 4, // or false 18263 tabAsSpaces: false, // true or number of spaces 18264 tabKey: true, 18265 18266 autosave: false, // false or url 18267 autosaveName: false, 18268 autosaveFields: false, 18269 18270 imageUpload: null, 18271 imageUploadParam: 'file', 18272 imageUploadFields: false, 18273 imageUploadForms: false, 18274 imageTag: 'figure', 18275 imageEditable: true, 18276 imageCaption: true, 18277 18278 imagePosition: false, 18279 imageResizable: false, 18280 imageFloatMargin: '10px', 18281 18282 dragImageUpload: true, 18283 multipleImageUpload: true, 18284 clipboardImageUpload: true, 18285 18286 fileUpload: null, 18287 fileUploadParam: 'file', 18288 fileUploadFields: false, 18289 fileUploadForms: false, 18290 dragFileUpload: true, 18291 18292 s3: false, 18293 18294 linkNewTab: false, 18295 linkTooltip: true, 18296 linkNofollow: false, 18297 linkSize: 30, 18298 linkValidation: true, 18299 pasteLinkTarget: false, 18300 18301 videoContainerClass: 'video-container', 18302 18303 toolbar: true, 18304 toolbarFixed: true, 18305 toolbarFixedTarget: document, 18306 toolbarFixedTopOffset: 0, // pixels 18307 toolbarExternal: false, // ID selector 18308 toolbarOverflow: false, 18309 18310 air: false, 18311 airWidth: false, 18312 18313 formatting: ['p', 'blockquote', 'pre', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'], 18314 formattingAdd: false, 18315 18316 buttons: ['format', 'bold', 'italic', 'deleted', 'lists', 'image', 'file', 'link', 'horizontalrule'], // + 'horizontalrule', 'underline', 'ol', 'ul', 'indent', 'outdent' 18317 buttonsTextLabeled: false, 18318 buttonsHide: [], 18319 buttonsHideOnMobile: [], 18320 18321 script: true, 18322 removeNewlines: false, 18323 removeComments: true, 18324 replaceTags: { 18325 'b': 'strong', 18326 'i': 'em', 18327 'strike': 'del' 18328 }, 18329 18330 keepStyleAttr: [], // tag name array 18331 keepInlineOnEnter: false, 18332 18333 // shortcuts 18334 shortcuts: { 18335 'ctrl+shift+m, meta+shift+m': { func: 'inline.removeFormat' }, 18336 'ctrl+b, meta+b': { func: 'inline.format', params: ['bold'] }, 18337 'ctrl+i, meta+i': { func: 'inline.format', params: ['italic'] }, 18338 'ctrl+h, meta+h': { func: 'inline.format', params: ['superscript'] }, 18339 'ctrl+l, meta+l': { func: 'inline.format', params: ['subscript'] }, 18340 'ctrl+k, meta+k': { func: 'link.show' }, 18341 'ctrl+shift+7': { func: 'list.toggle', params: ['orderedlist'] }, 18342 'ctrl+shift+8': { func: 'list.toggle', params: ['unorderedlist'] } 18343 }, 18344 shortcutsAdd: false, 18345 18346 activeButtons: ['deleted', 'italic', 'bold'], 18347 activeButtonsStates: { 18348 b: 'bold', 18349 strong: 'bold', 18350 i: 'italic', 18351 em: 'italic', 18352 del: 'deleted', 18353 strike: 'deleted' 18354 }, 18355 18356 // private lang 18357 langs: { 18358 en: { 18359 18360 "format": "Format", 18361 "image": "Image", 18362 "file": "File", 18363 "link": "Link", 18364 "bold": "Bold", 18365 "italic": "Italic", 18366 "deleted": "Strikethrough", 18367 "underline": "Underline", 18368 "bold-abbr": "B", 18369 "italic-abbr": "I", 18370 "deleted-abbr": "S", 18371 "underline-abbr": "U", 18372 "lists": "Lists", 18373 "link-insert": "Insert link", 18374 "link-edit": "Edit link", 18375 "link-as-button": "Style link as button", 18376 "link-in-new-tab": "Open link in new tab", 18377 "unlink": "Unlink", 18378 "cancel": "Cancel", 18379 "close": "Close", 18380 "insert": "Insert", 18381 "save": "Save", 18382 "delete": "Delete", 18383 "text": "Text", 18384 "edit": "Edit", 18385 "title": "Title", 18386 "paragraph": "Normal text", 18387 "quote": "Quote", 18388 "code": "Code", 18389 "heading1": "Heading 1", 18390 "heading2": "Heading 2", 18391 "heading3": "Heading 3", 18392 "heading4": "Heading 4", 18393 "heading5": "Heading 5", 18394 "heading6": "Heading 6", 18395 "filename": "Name", 18396 "optional": "optional", 18397 "unorderedlist": "Unordered List", 18398 "orderedlist": "Ordered List", 18399 "outdent": "Outdent", 18400 "indent": "Indent", 18401 "horizontalrule": "Line", 18402 "upload-label": "Drop file here or ", 18403 "caption": "Caption", 18404 18405 "bulletslist": "Bullets", 18406 "numberslist": "Numbers", 18407 18408 "image-position": "Position", 18409 "none": "None", 18410 "left": "Left", 18411 "right": "Right", 18412 "center": "Center", 18413 18414 "accessibility-help-label": "Rich text editor" 18415 } 18416 }, 18417 18418 // private
18419 type: 'textarea', // textarea, div, inline, pre 18420 inline: false, 18421 inlineTags: ['a', 'span', 'strong', 'strike', 'b', 'u', 'em', 'i', 'code', 'del', 'ins', 'samp', 'kbd', 'sup', 'sub', 'mark', 'var', 'cite', 'small'], 18422 blockTags: ['pre', 'ul', 'ol', 'li', 'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'dl', 'dt', 'dd', 'div', 'td', 'blockquote', 'output', 'figcaption', 'figure', 'address', 'section', 'header', 'footer', 'aside', 'article', 'iframe'], 18423 paragraphize: true, 18424 paragraphizeBlocks: ['table', 'div', 'pre', 'form', 'ul', 'ol', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'dl', 'blockquote', 'figcaption', 18425 'address', 'section', 'header', 'footer', 'aside', 'article', 'object', 'style', 'script', 'iframe', 'select', 'input', 'textarea', 18426 'button', 'option', 'map', 'area', 'math', 'hr', 'fieldset', 'legend', 'hgroup', 'nav', 'figure', 'details', 'menu', 'summary', 'p'], 18427 emptyHtml: '<p>​</p>', 18428 invisibleSpace: '​', 18429 emptyHtmlRendered: $('').html('â').html(), 18430 imageTypes: ['image/png', 'image/jpeg', 'image/gif'], 18431 userAgent: navigator.userAgent.toLowerCase(), 18432 observe: { 18433 dropdowns: [] 18434 }, 18435 regexps: {
18436 linkyoutube: /https?:\/\/(?:[0-9A-Z-]+\.)?(?:youtu\.be\/|youtube\.com\S*[^\w\-\s])([\w\-]{11})(?=[^\w\-]|$)(?![?=&+%\w.\-]*(?:['"][^<>]*>|<\/a>))[?=&+%\w.-]*/ig, 18437 linkvimeo: /https?:\/\/(www\.)?vimeo.com\/(\d+)($|\/)/, 18438 linkimage: /((https?|www)[^\s]+\.)(jpe?g|png|gif)(\?[^\s-]+)?/ig, 18439 url: /(https?:\/\/(?:www\.|(?!www))[^\s\.]+\.[^\s]{2,}|www\.[^\s]+\.[^\s]{2,})/ig 18440 } 18441 18442 }; 18443 18444 // Functionality 18445 Redactor.fn = $.Redactor.prototype = { 18446 18447 keyCode: { 18448 BACKSPACE: 8, 18449 DELETE: 46, 18450 UP: 38, 18451 DOWN: 40, 18452 ENTER: 13, 18453 SPACE: 32, 18454 ESC: 27, 18455 TAB: 9, 18456 CTRL: 17, 18457 META: 91, 18458 SHIFT: 16, 18459 ALT: 18, 18460 RIGHT: 39, 18461 LEFT: 37, 18462 LEFT_WIN: 91 18463 }, 18464 18465 // =init 18466 init: function(el, options) 18467 { 18468 this.$element = $(el); 18469 this.uuid = uuid++; 18470 this.sBuffer = []; 18471 this.sRebuffer = []; 18472 18473 this.loadOptions(options); 18474 this.loadModules(); 18475 18476 // click to edit 18477 if (this.opts.clickToEdit && !this.$element.hasClass('redactor-click-to-edit')) 18478 { 18479 return this.loadToEdit(options); 18480 } 18481 else if (this.$element.hasClass('redactor-click-to-edit')) 18482 { 18483 this.$element.removeClass('redactor-click-to-edit'); 18484 } 18485 18486 // block & inline test tag regexp 18487 this.reIsBlock = new RegExp('^(' + this.opts.blockTags.join('|' ).toUpperCase() + ')$', 'i'); 18488 this.reIsInline = new RegExp('^(' + this.opts.inlineTags.join('|' ).toUpperCase() + ')$', 'i'); 18489 18490 // set up drag upload 18491 this.opts.dragImageUpload = (this.opts.imageUpload === null) ? false : this.opts.dragImageUpload; 18492 this.opts.dragFileUpload = (this.opts.fileUpload === null) ? false : this.opts.dragFileUpload; 18493 18494 // formatting storage 18495 this.formatting = {}; 18496 18497 // load lang 18498 this.lang.load(); 18499 18500 // extend shortcuts 18501 $.extend(this.opts.shortcuts, this.opts.shortcutsAdd); 18502 18503 // set editor 18504 this.$editor = this.$element; 18505 18506 // detect type of editor 18507 this.detectType(); 18508 18509 // start callback 18510 this.core.callback('start'); 18511 this.core.callback('startToEdit'); 18512 18513 // build 18514 this.start = true; 18515 this.build.start(); 18516 18517 }, 18518 detectType: function() 18519 { 18520 if (this.build.isInline() || this.opts.inline) 18521 { 18522 this.opts.type = 'inline'; 18523 } 18524 else if (this.build.isTag('DIV')) 18525 { 18526 this.opts.type = 'div'; 18527 } 18528 else if (this.build.isTag('PRE')) 18529 { 18530 this.opts.type = 'pre'; 18531 } 18532 }, 18533 loadToEdit: function(options) 18534 { 18535 18536 this.$element.on('click.redactor-click-to-edit', $.proxy(function() 18537 { 18538 this.initToEdit(options); 18539 18540 }, this)); 18541 18542 this.$element.addClass('redactor-click-to-edit'); 18543 18544 return; 18545 }, 18546 initToEdit: function(options) 18547 { 18548 $.extend(options.callbacks, { 18549 startToEdit: function() 18550 { 18551 this.insert.node(this.marker.get(), false); 18552 }, 18553 initToEdit: function() 18554 { 18555 this.selection.restore(); 18556 this.clickToCancelStorage = this.code.get(); 18557 18558 // cancel 18559 $(this.opts.clickToCancel).off('.redactor-click-to-edit'); 18560 $(this.opts.clickToCancel).show().on('click.redactor-click-to-edit', $.proxy(function(e) 18561 { 18562 e.preventDefault(); 18563 18564 this.core.destroy(); 18565 this.events.syncFire = false; 18566 this.$element.html(this.clickToCancelStorage); 18567 this.core.callback('cancel', this.clickToCancelStorage); 18568 this.events.syncFire = true; 18569 this.clickToCancelStorage = ''; 18570 $(this.opts.clickToCancel).hide(); 18571 $(this.opts.clickToSave).hide(); 18572 18573 this.$element.on('click.redactor-click-to-edit', $.proxy(function() 18574 { 18575 this.initToEdit(options); 18576 }, this)); 18577 18578 this.$element.addClass('redactor-click-to-edit'); 18579 18580 }, this)); 18581 18582 // save 18583 $(this.opts.clickToSave).off('.redactor-click-to-edit'); 18584 $(this.opts.clickToSave).show().on('click.redactor-click-to-edit', $.proxy(function(e) 18585 { 18586 e.preventDefault(); 18587 18588 this.core.destroy(); 18589 this.core.callback('save', this.code.get()); 18590 $(this.opts.clickToCancel).hide(); 18591 $(this.opts.clickToSave).hide(); 18592 this.$element.on('click.redactor-click-to-edit', $.proxy(function() 18593 { 18594 this.initToEdit(options); 18595 }, this)); 18596 this.$element.addClass('redactor-click-to-edit'); 18597 18598 }, this)); 18599 } 18600 18601 }); 18602 18603 this.$element.redactor(options); 18604 this.$element.off('.redactor-click-to-edit'); 18605 18606 }, 18607 loadOptions: function(options) 18608 { 18609 var settings = {}; 18610 18611 // check namespace 18612 if (typeof $.Redactor.settings.namespace !== 'undefined') 18613 { 18614 if (this.$element.hasClass($.Redactor.settings.namespace)) 18615 { 18616 settings = $.Redactor.settings; 18617 } 18618 } 18619 else 18620 {
18621 settings = $.Redactor.settings; 18622 } 18623 18624 this.opts = $.extend( 18625 {}, 18626 $.Redactor.opts, 18627 this.$element.data(), 18628 options 18629 ); 18630 18631 this.opts = $.extend({}, this.opts, settings); 18632 18633 }, 18634 getModuleMethods: function(object) 18635 { 18636 return Object.getOwnPropertyNames(object).filter(function(property) 18637 { 18638 return typeof object[property] === 'function'; 18639 }); 18640 }, 18641 loadModules: function() 18642 { 18643 var len = $.Redactor.modules.length; 18644 for (var i = 0; i < len; i++) 18645 { 18646 this.bindModuleMethods($.Redactor.modules[i]); 18647 } 18648 }, 18649 bindModuleMethods: function(module) 18650 { 18651 if (typeof this[module] === 'undefined') 18652 { 18653 return; 18654 } 18655 18656 // init module 18657 this[module] = this[module](); 18658 18659 var methods = this.getModuleMethods(this[module]); 18660 var len = methods.length; 18661 18662 // bind methods 18663 for (var z = 0; z < len; z++) 18664 { 18665 this[module][methods[z]] = this[module][methods[z]].bind(this); 18666 } 18667 }, 18668 18669 // =air 18670 air: function() 18671 { 18672 return { 18673 enabled: false, 18674 collapsed: function() 18675 { 18676 if (this.opts.air) 18677 { 18678 this.selection.get().collapseToStart(); 18679 } 18680 }, 18681 collapsedEnd: function() 18682 { 18683 if (this.opts.air) 18684 { 18685 this.selection.get().collapseToEnd(); 18686 } 18687 }, 18688 build: function() 18689 { 18690 if (this.detect.isMobile()) 18691 { 18692 return; 18693 } 18694 18695 this.button.hideButtons(); 18696 this.button.hideButtonsOnMobile(); 18697 18698 if (this.opts.buttons.length === 0) 18699 { 18700 return; 18701 } 18702 18703 this.$air = this.air.createContainer(); 18704 18705 if (this.opts.airWidth !== false) 18706 { 18707 this.$air.css('width', this.opts.airWidth); 18708 } 18709 18710 this.air.append(); 18711 this.button.$toolbar = this.$air; 18712 this.button.setFormatting(); 18713 this.button.load(this.$air); 18714 18715 this.core.editor().on('mouseup.redactor', this, $.proxy(function(e) 18716 { 18717 if (this.selection.text() !== '') 18718 { 18719 this.air.show(e); 18720 } 18721 }, this)); 18722 18723 }, 18724 append: function() 18725 { 18726 this.$air.appendTo('body'); 18727 }, 18728 createContainer: function() 18729 { 18730 return $('<ul>').addClass('redactor-air').attr({ 'id': 'redactor-air-' + this.uuid, 'role': 'toolbar' }).hide(); 18731 }, 18732 show: function (e) 18733 { 18734 //this.marker.remove(); 18735 this.selection.saveInstant(); 18736 //this.selection.restore(false); 18737 18738 $('.redactor-air').hide(); 18739 18740 var leftFix = 0; 18741 var width = this.$air.innerWidth(); 18742 18743 if ($(window).width() < (e.clientX + width)) 18744 { 18745 leftFix = 200; 18746 } 18747 18748 this.$air.css({ 18749 left: (e.clientX - leftFix) + 'px', 18750 top: (e.clientY + 10 + $(document).scrollTop()) + 'px' 18751 }).show(); 18752 18753 this.air.enabled = true; 18754 this.air.bindHide(); 18755 }, 18756 bindHide: function() 18757 { 18758 $(document).on('mousedown.redactor-air.' + this.uuid, $.proxy(function(e) 18759 { 18760 var dropdown = $(e.target).closest('.redactor-dropdown').length; 18761 18762 if ($(e.target).closest(this.$air).length === 0 && dropdown === 0) 18763 { 18764 var hide = this.air.hide(e); 18765 if (hide !== false) 18766 { 18767 this.marker.remove(); 18768 } 18769 } 18770 18771 }, this)).on('keydown.redactor-air.' + this.uuid, $.proxy(function(e) 18772 { 18773 var key = e.which; 18774 if ((!this.utils.isRedactorParent(e.target) && !$(e.target).hasClass('redactor-in')) || $(e.target).closest('#redactor-modal').length !== 0) 18775 { 18776 return; 18777 } 18778 18779 if (key === this.keyCode.ESC) 18780 { 18781 this.selection.get().collapseToStart(); 18782 //this.marker.remove(); 18783 } 18784 else if (key === this.keyCode.BACKSPACE || key === this.keyCode.DELETE) 18785 { 18786 var sel = this.selection.get(); 18787 var range = this.selection.range(sel); 18788 range.deleteContents(); 18789 //this.marker.remove(); 18790 } 18791 else if (key === this.keyCode.ENTER) 18792 { 18793 this.selection.get().collapseToEnd(); 18794 //this.marker.remove(); 18795 } 18796 18797 if (this.air.enabled) 18798 { 18799 this.air.hide(e); 18800 } 18801 else 18802 { 18803 this.selection.get().collapseToStart(); 18804 //this.marker.remove(); 18805 } 18806 18807 18808 }, this)); 18809 }, 18810 hide: function(e) 18811 { 18812 var ctrl = e.ctrlKey || e.metaKey || (e.shiftKey && e.altKey); 18813 if (ctrl) 18814 { 18815 return false;
18816 } 18817 18818 this.button.setInactiveAll(); 18819 this.$air.fadeOut(100); 18820 this.air.enabled = false; 18821 $(document).off('mousedown.redactor-air.' + this.uuid); 18822 $(document).off('keydown.redactor-air.' + this.uuid); 18823 18824 } 18825 }; 18826 }, 18827 18828 // =autosave 18829 autosave: function() 18830 { 18831 return { 18832 enabled: false, 18833 html: false, 18834 init: function() 18835 { 18836 if (!this.opts.autosave) 18837 { 18838 return; 18839 } 18840 18841 this.autosave.enabled = true; 18842 this.autosave.name = (this.opts.autosaveName) ? this.opts.autosaveName : this.$textarea.attr('name'); 18843 18844 }, 18845 is: function() 18846 { 18847 return this.autosave.enabled; 18848 }, 18849 send: function() 18850 { 18851 if (!this.opts.autosave) 18852 { 18853 return; 18854 } 18855 18856 this.autosave.source = this.code.get(); 18857 18858 if (this.autosave.html === this.autosave.source) 18859 { 18860 return; 18861 } 18862 18863 // data 18864 var data = {}; 18865 data.name = this.autosave.name; 18866 data[this.autosave.name] = this.autosave.source; 18867 data = this.autosave.getHiddenFields(data); 18868 18869 // ajax 18870 var jsxhr = $.ajax({ 18871 url: this.opts.autosave, 18872 type: 'post', 18873 data: data 18874 }); 18875 18876 jsxhr.done(this.autosave.success); 18877 }, 18878 getHiddenFields: function(data) 18879 { 18880 if (this.opts.autosaveFields === false || typeof this.opts.autosaveFields !== 'object') 18881 { 18882 return data; 18883 } 18884 18885 $.each(this.opts.autosaveFields, $.proxy(function(k, v) 18886 { 18887 if (v !== null && v.toString().indexOf('#') === 0) 18888 { 18889 v = $(v).val(); 18890 } 18891 18892 data[k] = v; 18893 18894 }, this)); 18895 18896 return data; 18897 18898 }, 18899 success: function(data) 18900 { 18901 var json; 18902 try 18903 { 18904 json = JSON.parse(data); 18905 } 18906 catch(e) 18907 { 18908 //data has already been parsed 18909 json = data; 18910 } 18911 18912 var callbackName = (typeof json.error === 'undefined') ? 'autosave' : 'autosaveError'; 18913 18914 this.core.callback(callbackName, this.autosave.name, json); 18915 this.autosave.html = this.autosave.source; 18916 }, 18917 disable: function() 18918 { 18919 this.autosave.enabled = false; 18920 18921 clearInterval(this.autosaveTimeout); 18922 } 18923 }; 18924 }, 18925 18926 // =block 18927 block: function() 18928 { 18929 return { 18930 format: function(tag, attr, value, type) 18931 { 18932 tag = (tag === 'quote') ? 'blockquote' : tag; 18933 18934 this.block.tags = ['p', 'blockquote', 'pre', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'div', 'figure']; 18935 if ($.inArray(tag, this.block.tags) === -1) 18936 { 18937 return; 18938 } 18939 18940 if (tag === 'p' && typeof attr === 'undefined') 18941 { 18942 // remove all 18943 attr = 'class'; 18944 } 18945 18946 this.placeholder.hide(); 18947 this.buffer.set(); 18948 18949 return (this.utils.isCollapsed()) ? this.block.formatCollapsed(tag, attr, value, type) : this.block.formatUncollapsed(tag, attr, value, type); 18950 }, 18951 formatCollapsed: function(tag, attr, value, type) 18952 { 18953 this.selection.save(); 18954 18955 var block = this.selection.block(); 18956 var currentTag = block.tagName.toLowerCase(); 18957 if ($.inArray(currentTag, this.block.tags) === -1) 18958 { 18959 this.selection.restore(); 18960 return; 18961 } 18962 18963 var clearAllAttrs = false; 18964 if (currentTag === tag && attr === undefined) 18965 { 18966 tag = 'p'; 18967 clearAllAttrs = true; 18968 } 18969 18970 18971 if (clearAllAttrs) 18972 { 18973 this.block.removeAllClass(); 18974 this.block.removeAllAttr(); 18975 } 18976 18977 18978 var replaced; 18979 if (currentTag === 'blockquote' && this.utils.isEndOfElement(block)) 18980 { 18981 this.marker.remove(); 18982 18983 replaced = document.createElement('p'); 18984 replaced.innerHTML = this.opts.invisibleSpace; 18985 18986 $(block).after(replaced); 18987 this.caret.start(replaced); 18988 var $last = $(block).children().last(); 18989 18990 if ($last.length !== 0 && $last[0].tagName === 'BR') 18991 { 18992 $last.remove(); 18993 } 18994 } 18995 else 18996 { 18997 replaced = this.utils.replaceToTag(block, tag); 18998 } 18999 19000 19001 if (typeof attr === 'object') 19002 { 19003 type = value; 19004 for (var key in attr) 19005 { 19006 replaced = this.block.setAttr(replaced, key, attr[key], type); 19007 } 19008 } 19009 else 19010 { 19011 replaced = this.block.setAttr(replaced, attr, value, type); 19012 } 19013 19014 19015 // trim pre 19016 if (tag === 'pre' && replaced.length === 1) 19017 { 19018 $(replaced).html($.trim($(replaced).html())); 19019 } 19020
19021 this.selection.restore(); 19022 this.block.removeInlineTags(replaced); 19023 19024 return replaced; 19025 }, 19026 formatUncollapsed: function(tag, attr, value, type) 19027 { 19028 this.selection.save(); 19029 19030 var replaced = []; 19031 var blocks = this.selection.blocks(); 19032 19033 if (blocks[0] && ($(blocks[0]).hasClass('redactor-in') || $(blocks[0]).hasClass('redactor-box'))) 19034 { 19035 blocks = this.core.editor().find(this.opts.blockTags.join(', ')); 19036 } 19037 19038 var len = blocks.length; 19039 for (var i = 0; i < len; i++) 19040 { 19041 var currentTag = blocks[i].tagName.toLowerCase(); 19042 if ($.inArray(currentTag, this.block.tags) !== -1 && currentTag !== 'figure') 19043 { 19044 var block = this.utils.replaceToTag(blocks[i], tag); 19045 19046 if (typeof attr === 'object') 19047 { 19048 type = value; 19049 for (var key in attr) 19050 { 19051 block = this.block.setAttr(block, key, attr[key], type); 19052 } 19053 } 19054 else 19055 { 19056 block = this.block.setAttr(block, attr, value, type); 19057 } 19058 19059 replaced.push(block); 19060 this.block.removeInlineTags(block); 19061 } 19062 } 19063 19064 this.selection.restore(); 19065 19066 // combine pre 19067 if (tag === 'pre' && replaced.length !== 0) 19068 { 19069 var first = replaced[0]; 19070 $.each(replaced, function(i,s) 19071 { 19072 if (i !== 0) 19073 { 19074 $(first).append("\n" + $.trim(s.html())); 19075 $(s).remove(); 19076 } 19077 }); 19078 19079 replaced = []; 19080 replaced.push(first); 19081 } 19082 19083 return replaced; 19084 }, 19085 removeInlineTags: function(node) 19086 { 19087 node = node[0] || node; 19088 19089 var tags = this.opts.inlineTags; 19090 var blocks = ['PRE', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6']; 19091 19092 if ($.inArray(node.tagName, blocks) === - 1) 19093 { 19094 return; 19095 } 19096 19097 if (node.tagName !== 'PRE') 19098 { 19099 var index = tags.indexOf('a'); 19100 tags.splice(index, 1); 19101 } 19102 19103 $(node).find(tags.join(',')).not('.redactor-selection-marker').contents().unwrap(); 19104 }, 19105 setAttr: function(block, attr, value, type) 19106 { 19107 if (typeof attr === 'undefined') 19108 { 19109 return block; 19110 } 19111 19112 var func = (typeof type === 'undefined') ? 'replace' : type; 19113 19114 if (attr === 'class') 19115 { 19116 block = this.block[func + 'Class'](value, block); 19117 } 19118 else 19119 { 19120 if (func === 'remove') 19121 { 19122 block = this.block[func + 'Attr'](attr, block); 19123 } 19124 else if (func === 'removeAll') 19125 { 19126 block = this.block[func + 'Attr'](attr, block); 19127 } 19128 else 19129 { 19130 block = this.block[func + 'Attr'](attr, value, block); 19131 } 19132 } 19133 19134 return block; 19135 19136 }, 19137 getBlocks: function(block) 19138 { 19139 block = (typeof block === 'undefined') ? this.selection.blocks() : block; 19140 19141 if ($(block).hasClass('redactor-box')) 19142 { 19143 var blocks = []; 19144 var nodes = this.core.editor().children(); 19145 $.each(nodes, $.proxy(function(i,node) 19146 { 19147 if (this.utils.isBlock(node)) 19148 { 19149 blocks.push(node); 19150 } 19151 19152 }, this)); 19153 19154 return blocks; 19155 } 19156 19157 return block 19158 }, 19159 replaceClass: function(value, block) 19160 { 19161 return $(this.block.getBlocks(block)).removeAttr('class').addClass(value)[0]; 19162 }, 19163 toggleClass: function(value, block) 19164 { 19165 return $(this.block.getBlocks(block)).toggleClass(value)[0]; 19166 }, 19167 addClass: function(value, block) 19168 { 19169 return $(this.block.getBlocks(block)).addClass(value)[0]; 19170 }, 19171 removeClass: function(value, block) 19172 { 19173 return $(this.block.getBlocks(block)).removeClass(value)[0]; 19174 }, 19175 removeAllClass: function(block) 19176 { 19177 return $(this.block.getBlocks(block)).removeAttr('class')[0]; 19178 }, 19179 replaceAttr: function(attr, value, block) 19180 { 19181 block = this.block.removeAttr(attr, block); 19182 19183 return $(block).attr(attr, value)[0]; 19184 }, 19185 toggleAttr: function(attr, value, block) 19186 { 19187 block = this.block.getBlocks(block); 19188 19189 var self = this; 19190 var returned = []; 19191 $.each(block, function(i,s) 19192 { 19193 var $el = $(s); 19194 if ($el.attr(attr)) 19195 { 19196 returned.push(self.block.removeAttr(attr, s)); 19197 } 19198 else 19199 { 19200 returned.push(self.block.addAttr(attr, value, s)); 19201 } 19202 }); 19203 19204 return returned; 19205 19206 }, 19207 addAttr: function(attr, value, block) 19208 { 19209 return $(this.block.getBlocks(block)).attr(attr, value)[0]; 19210 }, 19211 removeAttr: function(attr, block) 19212 { 19213 return $(this.block.getBlocks(block)).removeAttr(attr)[0]; 19214 }, 19215 removeAllAttr: function(block) 19216 { 19217 block = this.block.getBlocks(block); 19218 19219 var returned = []; 19220 $.each(block, function(i,s) 19221 { 19222 if (typeof s.attributes !== 'undefined') 19223 { 19224 while (s.attributes.length) 19225 { 19226 s.removeAttribute(s.attributes[0].name); 19227 } 19228 } 19229 19230 returned.push(s); 19231 }); 19232 19233 return returned; 19234 } 19235 }; 19236 }, 19237 19238 // buffer 19239 buffer: function() 19240 { 19241 return { 19242 set: function(type) 19243 { 19244 if (typeof type === 'undefined') 19245 { 19246 this.buffer.clear(); 19247 } 19248 19249 if (typeof type === 'undefined' || type === 'undo') 19250 { 19251 this.buffer.setUndo(); 19252 } 19253 else 19254 { 19255 this.buffer.setRedo(); 19256 } 19257 }, 19258 setUndo: function() 19259 { 19260 var saved = this.selection.saveInstant(); 19261 19262 var last = this.sBuffer[this.sBuffer.length-1]; 19263 var current = this.core.editor().html(); 19264 19265 var save = (typeof last !== 'undefined' && (last[0] === current)) ? false : true; 19266 if (save) 19267 { 19268 this.sBuffer.push([current, saved]); 19269 } 19270
19271 //this.selection.restore(); 19272 }, 19273 setRedo: function() 19274 { 19275 var saved = this.selection.saveInstant(); 19276 this.sRebuffer.push([this.core.editor().html(), saved]); 19277 //this.selection.restore(); 19278 }, 19279 add: function() 19280 { 19281 this.sBuffer.push([this.core.editor().html(), 0]); 19282 }, 19283 undo: function() 19284 { 19285 if (this.sBuffer.length === 0) 19286 { 19287 return; 19288 } 19289 19290 var buffer = this.sBuffer.pop(); 19291 19292 this.buffer.set('redo'); 19293 this.core.editor().html(buffer[0]); 19294 19295 this.selection.restoreInstant(buffer[1]); 19296 this.selection.restore(); 19297 this.observe.load(); 19298 }, 19299 redo: function() 19300 { 19301 if (this.sRebuffer.length === 0) 19302 { 19303 return; 19304 } 19305 19306 var buffer = this.sRebuffer.pop(); 19307 19308 this.buffer.set('undo'); 19309 this.core.editor().html(buffer[0]); 19310 19311 this.selection.restoreInstant(buffer[1]); 19312 this.selection.restore(); 19313 this.observe.load(); 19314 }, 19315 clear: function() 19316 { 19317 this.sRebuffer = []; 19318 } 19319 }; 19320 }, 19321 19322 // =build 19323 build: function() 19324 { 19325 return { 19326 start: function() 19327 { 19328 if (this.opts.type === 'inline') 19329 { 19330 this.opts.type = 'inline'; 19331 } 19332 else if (this.opts.type === 'div') 19333 { 19334 // empty 19335 var html = $.trim(this.$editor.html()); 19336 if (html === '') 19337 { 19338 this.$editor.html(this.opts.emptyHtml); 19339 } 19340 19341 this.build.buildTextarea(); 19342 } 19343 else if (this.opts.type === 'textarea') 19344 { 19345 this.build.startTextarea(); 19346 } 19347 19348 // set in 19349 this.build.setIn(); 19350 19351 // set id 19352 this.build.setId(); 19353 19354 // enable 19355 this.build.enableEditor(); 19356 19357 // options 19358 this.build.setOptions(); 19359 19360 // call 19361 this.build.callEditor(); 19362 19363 19364 }, 19365 createContainerBox: function() 19366 { 19367 this.$box = $('<div class="redactor-box" role="application" />'); 19368 }, 19369 setIn: function() 19370 { 19371 this.core.editor().addClass('redactor-in'); 19372 }, 19373 setId: function() 19374 { 19375 var id = (this.opts.type === 'textarea') ? 'redactor-uuid-' + this.uuid : this.$element.attr('id'); 19376 19377 this.core.editor().attr('id', (typeof id === 'undefined') ? 'redactor-uuid-' + this.uuid : id); 19378 }, 19379 getName: function() 19380 { 19381 var name = this.$element.attr('name'); 19382 19383 return (typeof name === 'undefined') ? 'content-' + this.uuid : n
19383ame; 19384 }, 19385 buildTextarea: function() 19386 { 19387 this.$textarea = $('<textarea>'); 19388 this.$textarea.attr('name', this.build.getName()); 19389 this.$textarea.hide(); 19390 this.$element.after(this.$textarea); 19391 19392 this.build.setStartAttrs(); 19393 }, 19394 loadFromTextarea: function() 19395 { 19396 this.$editor = $('<div />'); 19397 19398 // textarea 19399 this.$textarea = this.$element; 19400 this.$element.attr('name', this.build.getName()); 19401 19402 // place 19403 this.$box.insertAfter(this.$element).append(this.$editor).append(this.$element); 19404 19405 this.build.setStartAttrs(); 19406 19407 // styles 19408 this.$editor.addClass('redactor-layer'); 19409 if (this.opts.overrideStyles) this.$editor.addClass('redactor-styles'); 19410 19411 this.$element.hide(); 19412 19413 this.$box.prepend('<span class="redactor-voice-label" id="redactor-voice-' + this.uuid +'" aria-hidden="false">' + this.lang.get('accessibility-help-label') + '</span>'); 19414 19415 }, 19416 setStartAttrs: function() 19417 { 19418 this.$editor.attr({ 'aria-labelledby': 'redactor-voice-' + this.uuid, 'role': 'presentation' }); 19419 }, 19420 startTextarea: function() 19421 { 19422 this.build.createContainerBox(); 19423 19424 // load 19425 this.build.loadFromTextarea(); 19426 19427 // set code 19428 this.code.start(this.core.textarea().val()); 19429 19430 // set value 19431 this.core.textarea().val(this.clean.onSync(this.$editor.html())); 19432 }, 19433 isTag: function(tag) 19434 { 19435 return (this.$element[0].tagName === tag); 19436 }, 19437 isInline: function() 19438 { 19439 return (!this.build.isTag('TEXTAREA') && !this.build.isTag('DIV') && !this.build.isTag('PRE')); 19440 }, 19441 enableEditor: function() 19442 { 19443 this.core.editor().attr({ 'contenteditable': true }); 19444 }, 19445 setOptions: function() 19446 { 19447 // inline 19448 if (this.opts.type === 'inline') 19449 { 19450 this.opts.enterKey = false; 19451 } 19452 19453 // inline & pre 19454 if (this.opts.type === 'inline' || this.opts.type === 'pre') 19455 { 19456 this.opts.toolbarMobile = false; 19457 this.opts.toolbar = false; 19458 this.opts.air = false; 19459 this.opts.linkify = false; 19460 19461 } 19462 19463 // spellcheck 19464 this.core.editor().attr('spellcheck', this.opts.spellcheck); 19465 19466 // structure 19467 if (this.opts.structure) 19468 { 19469 this.core.editor().addClass('redactor-structure'); 19470 } 19471 19472 // styles class 19473 if (this.opts.stylesClass) 19474 { 19475 this.core.editor().addClass(this.opts.stylesClass); 19476 } 19477 19478 // options sets only in textarea mode 19479 if (this.opts.type !== 'textarea') 19480 { 19481 return; 19482 } 19483 19484 // direction 19485 this.core.box().attr('dir', this.opts.direction); 19486 this.core.editor().attr('dir', this.opts.direction); 19487 19488 // tabindex 19489 if (this.opts.tabindex) 19490 { 19491 this.core.editor().attr('tabindex', this.opts.tabindex); 19492 } 19493 19494 // min height 19495 if (this.opts.minHeight) 19496 { 19497 this.core.editor().css('min-height', this.opts.minHeight); 19498 } 19499 else 19500 { 19501 this.core.editor().css('min-height', '40px'); 19502 } 19503 19504 // max height 19505 if (this.opts.maxHeight) 19506 { 19507 this.core.editor().css('max-height', this.opts.maxHeight); 19508 } 19509 19510 // max width 19511 if (this.opts.maxWidth) 19512 { 19513 this.core.editor().css({ 'max-width': this.opts.maxWidth, 'margin': 'auto' }); 19514 } 19515 19516 }, 19517 callEditor: function() 19518 { 19519 this.build.disableBrowsersEditing(); 19520 19521 this.events.init(); 19522 this.build.setHelpers(); 19523 19524 // init buttons 19525 if (this.opts.toolbar || this.opts.air) 19526 { 19527 this.toolbarsButtons = this.button.init(); 19528 } 19529 19530 // load toolbar 19531 if (this.opts.air) 19532 { 19533 this.air.build(); 19534 } 19535 else if (this.opts.toolbar) 19536 { 19537 this.toolbar.build(); 19538 } 19539 19540 if (this.detect.isMobile() && this.opts.toolbarMobile && this.opts.air) 19541 { 19542 this.opts.toolbar = true; 19543 this.toolbar.build(); 19544 } 19545 19546 // observe dropdowns 19547 if (this.opts.air || this.opts.toolbar) 19548 { 19549 this.core.editor().on('mouseup.redactor-observe.' + this.uuid + ' keyup.redactor-observe.' + this.uuid + ' focus.redactor-observe.' + this.uuid + ' touchstart.redactor-observe.' + this.uuid, $.proxy(this.observe.toolbar, this)); 19550 this.core.element().on('blur.callback.redactor', $.proxy(function() 19551 { 19552 this.button.setInactiveAll(); 19553 19554 }, this)); 19555 } 19556 19557 // modal templates init 19558 this.modal.templates(); 19559 19560 // plugins 19561 this.build.plugins(); 19562 19563 // autosave 19564 this.autosave.init(); 19565 19566 // sync code
19567 this.code.html = this.code.cleaned(this.core.editor().html()); 19568 19569 // init callback 19570 this.core.callback('init'); 19571 this.core.callback('initToEdit'); 19572 19573 // get images & files list 19574 this.storage.observe(); 19575 19576 // started 19577 this.start = false; 19578 19579 }, 19580 setHelpers: function() 19581 { 19582 // linkify 19583 if (this.opts.linkify) 19584 { 19585 this.linkify.format(); 19586 } 19587 19588 // placeholder 19589 this.placeholder.init(); 19590 19591 // focus 19592 if (this.opts.focus) 19593 { 19594 setTimeout(this.focus.start, 100); 19595 } 19596 else if (this.opts.focusEnd) 19597 { 19598 setTimeout(this.focus.end, 100); 19599 } 19600 19601 }, 19602 disableBrowsersEditing: function() 19603 { 19604 try { 19605 // FF fix 19606 document.execCommand('enableObjectResizing', false, false); 19607 document.execCommand('enableInlineTableEditing', false, false); 19608 // IE prevent converting links 19609 document.execCommand("AutoUrlDetect", false, false); 19610 } catch (e) {} 19611 }, 19612 plugins: function() 19613 { 19614 if (!this.opts.plugins) 19615 { 19616 return; 19617 } 19618 19619 $.each(this.opts.plugins, $.proxy(function(i, s) 19620 { 19621 var func = (typeof RedactorPlugins !== 'undefined' && typeof RedactorPlugins[s] !== 'undefined') ? RedactorPlugins : Redactor.fn; 19622 19623 if (!$.isFunction(func[s])) 19624 { 19625 return; 19626 } 19627 19628 this[s] = func[s](); 19629 19630 // get methods 19631 var methods = this.getModuleMethods(this[s]); 19632 var len = methods.length; 19633 19634 // bind methods 19635 for (var z = 0; z < len; z++) 19636 { 19637 this[s][methods[z]] = this[s][methods[z]].bind(this); 19638 } 19639 19640 // append lang 19641 if (typeof this[s].langs !== 'undefined') 19642 { 19643 var lang = {}; 19644 if (typeof this[s].langs[this.opts.lang] !== 'undefined') 19645 { 19646 lang = this[s].langs[this.opts.lang]; 19647 } 19648 else if (typeof this[s].langs[this.opts.lang] === 'undefined' && typeof this[s].langs.en !== 'undefined') 19649 { 19650 lang = this[s].langs.en; 19651 } 19652 19653 // extend 19654 var self = this; 19655 $.each(lang, function(i,s) 19656 { 19657 if (typeof self.opts.curLang[i] === 'undefined') 19658 { 19659 self.opts.curLang[i] = s; 19660 } 19661 }); 19662 } 19663 19664 // init 19665 if ($.isFunction(this[s].init)) 19666 { 19667 this[s].init(); 19668 } 19669 19670 19671 }, this)); 19672 19673 } 19674 }; 19675 }, 19676 19677 // =button 19678 button: function() 19679 { 19680 return { 19681 toolbar: function() 19682 { 19683 return (typeof this.button.$toolbar === 'undefined' || !this.button.$toolbar) ? this.$toolbar : this.button.$toolbar; 19684 }, 19685 init: function() 19686 { 19687 return { 19688 format: 19689 { 19690 title: this.lang.get('format'), 19691 icon: true, 19692 dropdown: 19693 { 19694 p: 19695 { 19696 title: this.lang.get('paragraph'), 19697 func: 'block.format' 19698 }, 19699 blockquote: 19700 { 19701 title: this.lang.get('quote'), 19702 func: 'block.format' 19703 }, 19704 pre: 19705 { 19706 title: this.lang.get('code'), 19707 func: 'block.format' 19708 }, 19709 h1: 19710 { 19711 title: this.lang.get('heading1'), 19712 func: 'block.format' 19713 }, 19714 h2: 19715 { 19716 title: this.lang.get('heading2'), 19717 func: 'block.format' 19718 }, 19719 h3: 19720 { 19721 title: this.lang.get('heading3'), 19722 func: 'block.format' 19723 }, 19724 h4: 19725 { 19726 title: this.lang.get('heading4'), 19727 func: 'block.format' 19728 }, 19729 h5: 19730 { 19731 title: this.lang.get('heading5'), 19732 func: 'block.format' 19733 }, 19734 h6: 19735 { 19736 title: this.lang.get('heading6'), 19737 func: 'block.format' 19738 } 19739 } 19740 }, 19741 bold: 19742 { 19743 title: this.lang.get('bold-abbr'), 19744 icon: true, 19745 label: this.lang.get('bold'), 19746 func: 'inline.format' 19747 }, 19748 italic: 19749 { 19750 title: this.lang.get('italic-abbr'), 19751 icon: true, 19752 label: this.lang.get('italic'), 19753 func: 'inline.format' 19754 }, 19755 deleted: 19756 { 19757 title: this.lang.get('deleted-abbr'), 19758 icon: true, 19759 label: this.lang.get('deleted'), 19760 func: 'inline.format' 19761 }, 19762 underline: 19763 { 19764 title: this.lang.get('underline-abbr'), 19765 icon: true, 19766 label: this.lang.get('underline'), 19767 func: 'inline.format' 19768 }, 19769 lists: 19770 { 19771 title: this.lang.get('lists'), 19772 icon: true, 19773 dropdown: 19774 { 19775 unorderedlist: 19776 { 19777 title: '• ' + this.lang.get('unorderedlist'), 19778 func: 'list.toggle' 19779 }, 19780 orderedlist: 19781 { 19782 title: '1. ' + this.lang.get('orderedlist'), 19783 func: 'list.toggle' 19784 },
19785 outdent: 19786 { 19787 title: '< ' + this.lang.get('outdent'), 19788 func: 'indent.decrease', 19789 observe: { 19790 element: 'li', 19791 out: { 19792 attr: { 19793 'class': 'redactor-dropdown-link-inactive', 19794 'aria-disabled': true 19795 } 19796 } 19797 } 19798 }, 19799 indent: 19800 { 19801 title: '> ' + this.lang.get('indent'), 19802 func: 'indent.increase', 19803 observe: { 19804 element: 'li', 19805 out: { 19806 attr: { 19807 'class': 'redactor-dropdown-link-inactive', 19808 'aria-disabled': true 19809 } 19810 } 19811 } 19812 } 19813 } 19814 }, 19815 ul: 19816 { 19817 title: '• ' + this.lang.get('bulletslist'), 19818 icon: true, 19819 func: 'list.toggle' 19820 }, 19821 ol: 19822 { 19823 title: '1. ' + this.lang.get('numberslist'), 19824 icon: true, 19825 func: 'list.toggle' 19826 }, 19827 outdent: 19828 { 19829 title: this.lang.get('outdent'), 19830 icon: true, 19831 func: 'indent.decrease' 19832 }, 19833 indent: 19834 { 19835 title: this.lang.get('indent'), 19836 icon: true, 19837 func: 'indent.increase' 19838 }, 19839 image: 19840 { 19841 title: this.lang.get('image'), 19842 icon: true, 19843 func: 'image.show' 19844 }, 19845 file: 19846 { 19847 title: this.lang.get('file'), 19848 icon: true, 19849 func: 'file.show' 19850 }, 19851 link: 19852 { 19853 title: this.lang.get('link'), 19854 icon: true, 19855 dropdown: 19856 { 19857 link: 19858 { 19859 title: this.lang.get('link-insert'), 19860 func: 'link.show', 19861 observe: { 19862 element: 'a', 19863 'in': { 19864 title: this.lang.get('link-edit') 19865 }, 19866 out: { 19867 title: this.lang.get('link-insert') 19868 } 19869 } 19870 }, 19871 unlink: 19872 { 19873 title: this.lang.get('unlink'), 19874 func: 'link.unlink', 19875 observe: { 19876 element: 'a', 19877 out: { 19878 attr: { 19879 'class': 'redactor-dropdown-link-inactive', 19880 'aria-disabled': true 19881 } 19882 } 19883 } 19884 } 19885 } 19886 }, 19887 horizontalrule: 19888 { 19889 title: this.lang.get('horizontalrule'), 19890 icon: true, 19891 func: 'line.insert' 19892 } 19893 }; 19894 }, 19895 setFormatting: function() 19896 { 19897 $.each(this.toolbarsButtons.format.dropdown, $.proxy(function (i, s) 19898 { 19899 if ($.inArray(i, this.opts.formatting) === -1) 19900 { 19901 delete this.toolbarsButtons.format.dropdown[i]; 19902 } 19903 19904 }, this)); 19905 19906 }, 19907 hideButtons: function() 19908 { 19909 if (this.opts.buttonsHide.length !== 0) 19910 { 19911 this.button.hideButtonsSlicer(this.opts.buttonsHide); 19912 } 19913 }, 19914 hideButtonsOnMobile: function() 19915 { 19916 if (this.detect.isMobile() && this.opts.buttonsHideOnMobile.length !== 0) 19917 { 19918 this.button.hideButtonsSlicer(this.opts.buttonsHideOnMobile); 19919 } 19920 }, 19921 hideButtonsSlicer: function(buttons) 19922 { 19923 $.each(buttons, $.proxy(function(i, s) 19924 { 19925 var index = this.opts.buttons.indexOf(s); 19926 if (index !== -1) 19927 { 19928 this.opts.buttons.splice(index, 1); 19929 } 19930 19931 }, this)); 19932 }, 19933 load: function($toolbar) 19934 { 19935 this.button.buttons = []; 19936 19937 $.each(this.opts.buttons, $.proxy(function(i, btnName) 19938 { 19939 if (!this.toolbarsButtons[btnName] 19940 || (btnName === 'file' && !this.file.is()) 19941 || (btnName === 'image' && !this.image.is())) 19942 { 19943 return; 19944 } 19945 19946 $toolbar.append($('<li>').append(this.button.build(btnName, this.toolbarsButtons[btnName]))); 19947 19948 }, this)); 19949 }, 19950 buildButtonTooltip: function($btn, title) 19951 { 19952 if (typeof this.button.toolbar() === 'undefined') return; 19953 if (this.opts.air || this.detect.isMobile()) return; 19954 19955 var $tooltip = $('<span>'); 19956 $tooltip.addClass('re-button-tooltip'); 19957 $tooltip.html(title); 19958 19959 var self = this; 19960 var $toolbar = this.button.toolbar(); 19961 var $box = $toolbar.closest('.redactor-toolbar-box'); 19962 $box = ($box.length === 0) ? $toolbar : $box; 19963 $box.prepend($tooltip); 19964 $btn.on('mouseover', function() 19965 { 19966 if ($(this).hasClass('redactor-button-disabled')) 19967 { 19968 return; 19969 } 19970 19971 var pos = ($toolbar.hasClass('toolbar-fixed-box')) ? $btn.offset() : $btn.position(); 19972 pos = (self.opts.toolbarFixedTarget !== document) ? $btn.position() : pos; 19973 var top = ($toolbar.hasClass('toolbar-fixed-box')) ? $btn.position().top : pos.top; 19974 var height = $btn.innerHeight(); 19975 var width = $btn.innerWidth(); 19976 var posBox = ($toolbar.hasClass('toolbar-fixed-box')) ? 'fixed' : 'absolute'; 19977 posBox = (self.opts.toolbarFixedTarget !== document) ? 'absolute' : posBox; 19978 var scrollFix = (self.opts.toolbarFixedTarget !== document) ? $toolbar.position().top : 0; 19979 19980 $tooltip.show(); 19981 $tooltip.css({ 19982 top: (top + height + scrollFix) + 'px', 19983 left: (pos.left + width/2 - $tooltip.innerWidth()/2) + 'px', 19984 position: posBox 19985 }); 19986 19987 }).on('mouseout', function() 19988 { 19989 $tooltip.hide(); 19990 }); 19991 }, 19992 build: function(btnName, btnObject) 19993 { 19994 if (this.opts.toolbar === false) 19995 { 19996 return; 19997 } 19998 19999 var title = (typeof btnObject.label !== 'undefined') ? btnObject.label : btnObject.title; 20000 var $button = $('<a href="javascript:void(null);" alt="' + title + '" rel="' + btnName + '" />') 20001 20002 $button.addClass('re-button re-' + btnName); 20003 $button.attr({ 'role': 'button', 'aria-label': title, 'tabindex': '-1' }); 20004 20005 if (typeof btnObject.icon !== 'undefined' && !this.opts.buttonsTextLabeled) 20006 { 20007 var $icon = $('<i>'); 20008 $icon.addClass('re-icon-' + btnName); 20009 20010 $button.append($icon); 20011 $button.addClass('re-button-icon'); 20012 20013 this.button.buildButtonTooltip($button, title); 20014 } 20015 else 20016 { 20017 $button.html(btnObject.title); 20018 } 20019 20020 // click 20021 if (btnObject.func || btnObject.command || btnObject.dropdown) 20022 { 20023 this.button.setEvent($button, btnName, btnObject); 20024 } 20025 20026 // dropdown 20027 if (btnObject.dropdown) 20028 { 20029 $button.addClass('redactor-toolbar-link-dropdown').attr('aria-haspopup', true); 20030 20031 var $dropdown = $('<ul class="redactor-dropdown redactor-dropdown-' + this.uuid + ' redactor-dropdown-box-' + btnName + '" style="display: none;">'); 20032 $button.data('dropdown', $dropdown);
20033 this.dropdown.build(btnName, $dropdown, btnObject.dropdown); 20034 } 20035 20036 this.button.buttons.push($button); 20037 20038 return $button; 20039 }, 20040 getButtons: function() 20041 { 20042 return this.button.toolbar().find('a.re-button'); 20043 }, 20044 getButtonsKeys: function() 20045 { 20046 return this.button.buttons; 20047 }, 20048 setEvent: function($button, btnName, btnObject) 20049 { 20050 $button.on('mousedown', $.proxy(function(e) 20051 { 20052 e.preventDefault(); 20053 20054 if ($button.hasClass('redactor-button-disabled')) 20055 { 20056 return false; 20057 } 20058 20059 var type = 'func'; 20060 var callback = btnObject.func; 20061 20062 if (btnObject.command) 20063 { 20064 type = 'command'; 20065 callback = btnObject.command; 20066 } 20067 else if (btnObject.dropdown) 20068 { 20069 type = 'dropdown'; 20070 callback = false; 20071 } 20072 20073 this.button.toggle(e, btnName, type, callback); 20074 20075 return false; 20076 20077 }, this)); 20078 }, 20079 toggle: function(e, btnName, type, callback, args) 20080 { 20081 20082 if (this.detect.isIe() || !this.detect.isDesktop()) 20083 { 20084 this.utils.freezeScroll(); 20085 e.returnValue = false; 20086 } 20087 20088 if (type === 'command') 20089 { 20090 this.inline.format(callback); 20091 } 20092 else if (type === 'dropdown') 20093 { 20094 this.dropdown.show(e, btnName); 20095 } 20096 else 20097 { 20098 this.button.clickCallback(e, callback, btnName, args); 20099 } 20100 20101 if (type !== 'dropdown') 20102 { 20103 this.dropdown.hideAll(false); 20104 } 20105 20106 if (this.opts.air && type !== 'dropdown') 20107 { 20108 this.air.hide(e); 20109 } 20110 20111 if (this.detect.isIe() || !this.detect.isDesktop()) 20112 { 20113 this.utils.unfreezeScroll(); 20114 } 20115 }, 20116 clickCallback: function(e, callback, btnName, args) 20117 { 20118 var func; 20119 20120 args = (typeof args === 'undefined') ? btnName : args; 20121 20122 if ($.isFunction(callback)) 20123 { 20124 callback.call(this, btnName); 20125 } 20126 else if (callback.search(/\./) !== '-1') 20127 { 20128 func = callback.split('.'); 20129 if (typeof this[func[0]] === 'undefined') 20130 { 20131 return; 20132 } 20133 20134 if (typeof args === 'object') 20135 { 20136 this[func[0]][func[1]].apply(this, args); 20137 } 20138 else 20139 { 20140 this[func[0]][func[1]].call(this, args); 20141 } 20142 } 20143 else 20144 { 20145 20146 if (typeof args === 'object') 20147 { 20148 this[callback].apply(this, args); 20149 } 20150 else 20151 { 20152 this[callback].call(this, args); 20153 } 20154 } 20155 20156 this.observe.buttons(e, btnName); 20157 20158 }, 20159 all: function() 20160 { 20161 return this.button.buttons; 20162 }, 20163 get: function(key) 20164 { 20165 if (this.opts.toolbar === false) 20166 { 20167 return; 20168 } 20169 20170 return this.button.toolbar().find('a.re-' + key); 20171 }, 20172 set: function(key, title) 20173 { 20174 if (this.opts.toolbar === false) 20175 { 20176 return; 20177 } 20178 20179 var $btn = this.button.toolbar().find('a.re-' + key); 20180 20181 $btn.html(title).attr('aria-label', title); 20182 20183 return $btn; 20184 }, 20185 add: function(key, title) 20186 { 20187 if (this.button.isAdded(key) !== true) 20188 { 20189 return $(); 20190 } 20191 20192 var btn = this.button.build(key, { title: title }); 20193 20194 this.button.toolbar().append($('<li>').append(btn)); 20195 20196 return btn; 20197 }, 20198 addFirst: function(key, title) 20199 { 20200 if (this.button.isAdded(key) !== true) 20201 { 20202 return $(); 20203 } 20204 20205 var btn = this.button.build(key, { title: title }); 20206 20207 this.button.toolbar().prepend($('<li>').append(btn)); 20208 20209 return btn; 20210 }, 20211 addAfter: function(afterkey, key, title) 20212 { 20213 if (this.button.isAdded(key) !== true) 20214 { 20215 return $(); 20216 } 20217 20218 var btn = this.button.build(key, { title: title }); 20219 var $btn = this.button.get(afterkey); 20220 20221 if ($btn.length !== 0) 20222 { 20223 $btn.parent().after($('<li>').append(btn)); 20224 } 20225 else 20226 { 20227 this.button.toolbar().append($('<li>').append(btn)); 20228 } 20229 20230 return btn; 20231 }, 20232 addBefore: function(beforekey, key, title) 20233 { 20234 if (this.button.isAdded(key) !== true) 20235 { 20236 return $(); 20237 } 20238 20239 var btn = this.button.build(key, { title: title }); 20240 var $btn = this.button.get(beforekey); 20241 20242 if ($btn.length !== 0) 20243 { 20244 $btn.parent().before($('<li>').append(btn)); 20245 } 20246 else 20247 { 20248 this.button.toolbar().append($('<li>').append(btn)); 20249 } 20250 20251 return btn; 20252 }, 20253 isAdded: function(key) 20254 { 20255 var index = this.opts.buttonsHideOnMobile.indexOf(key); 20256 if (this.opts.toolbar === false || (index !== -1 && this.detect.isMobile())) 20257 { 20258 return false;
20259 } 20260 20261 return true; 20262 }, 20263 setIcon: function($btn, icon) 20264 { 20265 if (!this.opts.buttonsTextLabeled) 20266 { 20267 $btn.html(icon).addClass('re-button-icon'); 20268 this.button.buildButtonTooltip($btn, $btn.attr('alt')); 20269 } 20270 }, 20271 changeIcon: function(key, newIconClass) 20272 { 20273 var $btn = this.button.get(key); 20274 if ($btn.length !== 0) 20275 { 20276 $btn.find('i').removeAttr('class').addClass('re-icon-' + newIconClass); 20277 } 20278 }, 20279 addCallback: function($btn, callback) 20280 { 20281 if (typeof $btn === 'undefined' || this.opts.toolbar === false) 20282 { 20283 return; 20284 } 20285 20286 var type = (callback === 'dropdown') ? 'dropdown' : 'func'; 20287 var key = $btn.attr('rel'); 20288 $btn.on('mousedown', $.proxy(function(e) 20289 { 20290 if ($btn.hasClass('redactor-button-disabled')) 20291 { 20292 return false; 20293 } 20294 20295 this.button.toggle(e, key, type, callback); 20296 20297 }, this)); 20298 }, 20299 addDropdown: function($btn, dropdown) 20300 { 20301 if (this.opts.toolbar === false) 20302 { 20303 return; 20304 } 20305 20306 $btn.addClass('redactor-toolbar-link-dropdown').attr('aria-haspopup', true); 20307 20308 var key = $btn.attr('rel'); 20309 this.button.addCallback($btn, 'dropdown'); 20310 20311 var $dropdown = $('<div class="redactor-dropdown redactor-dropdown-' + this.uuid + ' redactor-dropdown-box-' + key + '" style="display: none;">'); 20312 $btn.data('dropdown', $dropdown); 20313 20314 // build dropdown 20315 if (dropdown) 20316 { 20317 this.dropdown.build(key, $dropdown, dropdown); 20318 } 20319 20320 return $dropdown; 20321 },
20322 setActive: function(key) 20323 { 20324 this.button.get(key).addClass('redactor-act'); 20325 }, 20326 setInactive: function(key) 20327 { 20328 this.button.get(key).removeClass('redactor-act'); 20329 }, 20330 setInactiveAll: function(key) 20331 { 20332 var $btns = this.button.toolbar().find('a.re-button'); 20333 20334 if (typeof key !== 'undefined') 20335 { 20336 $btns = $btns.not('.re-' + key); 20337 } 20338 20339 $btns.removeClass('redactor-act'); 20340 }, 20341 disable: function(key) 20342 { 20343 this.button.get(key).addClass('redactor-button-disabled'); 20344 }, 20345 enable: function(key) 20346 { 20347 this.button.get(key).removeClass('redactor-button-disabled'); 20348 }, 20349 disableAll: function(key) 20350 { 20351 var $btns = this.button.toolbar().find('a.re-button'); 20352 if (typeof key !== 'undefined') 20353 { 20354 $btns = $btns.not('.re-' + key); 20355 } 20356 20357 $btns.addClass('redactor-button-disabled'); 20358 }, 20359 enableAll: function() 20360 { 20361 this.button.toolbar().find('a.re-button').removeClass('redactor-button-disabled'); 20362 }, 20363 remove: function(key) 20364 { 20365 this.button.get(key).remove(); 20366 } 20367 }; 20368 }, 20369 20370 // =caret 20371 caret: function() 20372 { 20373 return { 20374 set: function(node1, node2, end) 20375 { 20376 var cs = this.core.editor().scrollTop(); 20377 this.core.editor().focus(); 20378 this.core.editor().scrollTop(cs); 20379 20380 end = (typeof end === 'undefined') ? 0 : 1; 20381 20382 node1 = node1[0] || node1; 20383 node2 = node2[0] || node2; 20384 20385 var sel = this.selection.get(); 20386 var range = this.selection.range(sel); 20387 20388 try 20389 { 20390 range.setStart(node1, 0); 20391 range.setEnd(node2, end); 20392 } 20393 catch (e) {} 20394 20395 this.selection.update(sel, range); 20396 }, 20397 prepare: function(node) 20398 { 20399 // firefox focus 20400 if (this.detect.isFirefox() && typeof this.start !== 'undefined') 20401 { 20402 this.core.editor().focus(); 20403 } 20404 20405 return node[0] || node; 20406 }, 20407 start: function(node) 20408 { 20409 var sel, range; 20410 node = this.caret.prepare(node); 20411 20412 if (!node) 20413 { 20414 return; 20415 } 20416 20417 if (node.tagName === 'BR') 20418 { 20419 return this.caret.before(node); 20420 } 20421 20422 var $first = $(node).children().first(); 20423 20424 // empty or inline tag 20425 var inline = this.utils.isInlineTag(node.tagName); 20426 if (node.innerHTML === '' || inline) 20427 { 20428 this.caret.setStartEmptyOrInline(node, inline); 20429 } 20430 // empty inline inside 20431 else if ($first && $first.length !== 0 && this.utils.isInlineTag($first[0].tagName) && $first.text() === '') 20432 { 20433 this.caret.setStartEmptyOrInline($first[0], true); 20434 } 20435 // block tag 20436 else 20437 { 20438 sel = window.getSelection(); 20439 sel.removeAllRanges(); 20440 20441 range = document.createRange(); 20442 range.selectNodeContents(node); 20443 range.collapse(true); 20444 sel.addRange(range); 20445 } 20446 20447 20448 }, 20449 setStartEmptyOrInline: function(node, inline) 20450 { 20451 var sel = window.getSelection(); 20452 var range = document.createRange(); 20453 var textNode = document.createTextNode('\u200B'); 20454 20455 range.setStart(node, 0); 20456 range.insertNode(textNode); 20457 range.setStartAfter(textNode); 20458 range.collapse(true); 20459 20460 sel.removeAllRanges(); 20461 sel.addRange(range); 20462 20463 // remove invisible text node 20464 if (!inline) 20465 { 20466 this.core.editor().on('keydown.redactor-remove-textnode', function() 20467 { 20468 $(textNode).remove(); 20469 $(this).off('keydown.redactor-remove-textnode'); 20470 }); 20471 } 20472 }, 20473 end: function(node) 20474 { 20475 var sel, range; 20476 node = this.caret.prepare(node); 20477 20478 if (!node) 20479 { 20480 return; 20481 } 20482 20483 // empty node 20484 if (node.tagName !== 'BR' && node.innerHTML === '') 20485 { 20486 return this.caret.start(node); 20487 } 20488 20489 // br 20490 if (node.tagName === 'BR') 20491 { 20492 var space = document.createElement('span'); 20493 space.className = 'redactor-invisible-space'; 20494 space.innerHTML = '​'; 20495 20496 $(node).after(space); 20497 20498 sel = window.getSelection(); 20499 sel.removeAllRanges(); 20500 20501 range = document.createRange(); 20502 20503 range.setStartBefore(space); 20504 range.setEndBefore(space); 20505 sel.addRange(range); 20506 20507 $(space).replaceWith(function() 20508 { 20509 return $(this).contents(); 20510 }); 20511 20512 return; 20513 } 20514 20515 if (node.lastChild && node.lastChild.nodeType === 1) 20516 { 20517 return this.caret.after(node.lastChild); 20518 } 20519 20520 var sel = window.getSelection(); 20521 if (sel.getRangeAt || sel.rangeCount) 20522 { 20523 try { 20524 var range = sel.getRangeAt(0); 20525 range.selectNodeContents(node); 20526 range.collapse(false); 20527 20528 sel.removeAllRanges(); 20529 sel.addRange(range); 20530 } 20531 catch(e) {} 20532 } 20533 }, 20534 after: function(node) 20535 { 20536 var sel, range; 20537 node = this.caret.prepare(node); 20538 20539 20540 if (!node) 20541 { 20542 return; 20543 } 20544 20545 if (node.tagName === 'BR') 20546 { 20547 return this.caret.end(node); 20548 } 20549 20550 // block tag 20551 if (this.utils.isBlockTag(node.tagName)) 20552 { 20553 var next = this.caret.next(node); 20554 20555 if (typeof next === 'undefined') 20556 { 20557 this.caret.end(node); 20558 } 20559 else 20560 { 20561 // table 20562 if (next.tagName === 'TABLE') 20563 { 20564 next = $(next).find('th, td').first()[0]; 20565 } 20566 // list 20567 else if (next.tagName === 'UL' || next.tagName === 'OL') 20568 { 20569 next = $(next).find('li').first()[0]; 20570 } 20571 20572 this.caret.start(next); 20573 } 20574 20575 return; 20576 } 20577 20578 // inline tag 20579 var textNode = document.createTextNode('\u200B'); 20580 20581 sel = window.getSelection(); 20582 sel.removeAllRanges(); 20583 20584 range = document.createRange(); 20585 range.setStartAfter(node);
20586 range.insertNode(textNode); 20587 range.setStartAfter(textNode); 20588 range.collapse(true); 20589 20590 sel.addRange(range); 20591 20592 }, 20593 before: function(node) 20594 { 20595 var sel, range; 20596 node = this.caret.prepare(node); 20597 20598 20599 if (!node) 20600 { 20601 return; 20602 } 20603 20604 // block tag 20605 if (this.utils.isBlockTag(node.tagName)) 20606 { 20607 var prev = this.caret.prev(node); 20608 20609 if (typeof prev === 'undefined') 20610 { 20611 this.caret.start(node); 20612 } 20613 else 20614 { 20615 // table 20616 if (prev.tagName === 'TABLE') 20617 { 20618 prev = $(prev).find('th, td').last()[0]; 20619 } 20620 // list 20621 else if (prev.tagName === 'UL' || prev.tagName === 'OL') 20622 { 20623 prev = $(prev).find('li').last()[0]; 20624 } 20625 20626 this.caret.end(prev); 20627 } 20628 20629 return; 20630 } 20631 20632 // inline tag 20633 sel = window.getSelection(); 20634 sel.removeAllRanges(); 20635 20636 range = document.createRange(); 20637 20638 range.setStartBefore(node); 20639 range.collapse(true); 20640 20641 sel.addRange(range); 20642 }, 20643 next: function(node) 20644 { 20645 var $next = $(node).next(); 20646 if ($next.hasClass('redactor-script-tag, redactor-selection-marker')) 20647 { 20648 return $next.next()[0]; 20649 } 20650 else 20651 { 20652 return $next[0]; 20653 } 20654 }, 20655 prev: function(node) 20656 { 20657 var $prev = $(node).prev(); 20658 if ($prev.hasClass('redactor-script-tag, redactor-selection-marker')) 20659 { 20660 return $prev.prev()[0]; 20661 } 20662 else 20663 { 20664 return $prev[0]; 20665 } 20666 }, 20667 20668 // #backward 20669 offset: function(node) 20670 { 20671 return this.offset.get(node); 20672 } 20673 20674 }; 20675 }, 20676 20677 // =clean 20678 clean: function() 20679 { 20680 return { 20681 onSet: function(html) 20682 { 20683 html = this.clean.savePreCode(html); 20684 html = this.clean.saveFormTags(html); 20685 20686 // convert script tag 20687 if (this.opts.script) 20688 { 20689 html = html.replace(/<script(.*?[^>]?)>([\w\W]*?)<\/script>/gi, '<pre class="redactor-script-tag" $1>$2</pre>'); 20690 } 20691 20692 // converting entity 20693 html = html.replace(/\$/g, '$'); 20694 html = html.replace(/&/g, '&'); 20695 20696 // replace special characters in links 20697 html = html.replace(/<a href="(.*?[^>]?)®(.*?[^>]?)">/gi, '<a href="$1®$2">'); 20698 20699 // save markers 20700 html = html.replace(/<span id="selection-marker-1"(.*?[^>]?)>â<\/span>/gi, '###marker1###'); 20701 html = html.replace(/<span id="selection-marker-2"(.*?[^>]?)>â<\/span>/gi, '###marker2###'); 20702 20703 // replace tags 20704 var self = this; 20705 var $div = $("<div/>").html($.parseHTML(html, document, true)); 20706 20707 var replacement = this.opts.replaceTags; 20708 if (replacement) 20709 { 20710 var keys = Object.keys(this.opts.replaceTags); 20711 $div.find(keys.join(',')).each(function(i,s) 20712 { 20713 self.utils.replaceToTag(s, replacement[s.tagName.toLowerCase()]); 20714 }); 20715 } 20716 20717 // add span marker 20718 $div.find('span, a').attr('data-redactor-span', true); 20719 20720 // add style cache 20721 $div.find(this.opts.inlineTags.join(',')).each(function() 20722 { 20723 // add style cache 20724 var $el = $(this); 20725 20726 if ($el.attr('style')) 20727 { 20728 $el.attr('data-redactor-style-cache', $el.attr('style')); 20729 } 20730 }); 20731 20732 html = $div.html(); 20733 20734 // remove tags 20735 var tags = ['font', 'html', 'head', 'link', 'body', 'meta', 'applet']; 20736 if (!this.opts.script) 20737 { 20738 tags.push('script'); 20739 } 20740 20741 html = this.clean.stripTags(html, tags); 20742 20743 // remove html comments 20744 if (this.opts.removeComments) 20745 { 20746 html = html.replace(/<!--[\s\S]*?-->/gi, ''); 20747 } 20748 20749 // paragraphize 20750 html = this.paragraphize.load(html); 20751 20752 // restore markers 20753 html = html.replace('###marker1###', '<span id="selection-marker-1" class="redactor-selection-marker">â</span>'); 20754 html = html.replace('###marker2###', '<span id="selection-marker-2" class="redactor-selection-marker">â</span>'); 20755 20756 // empty 20757 if (html.search(/^(||\s||<br\s?\/?>|| )$/i) !== -1) 20758 { 20759 return this.opts.emptyHtml; 20760 } 20761 20762 return html; 20763 }, 20764 onGet: function(html) 20765 { 20766 return this.clean.onSync(html); 20767 }, 20768 onSync: function(html) 20769 {
20770 // remove invisible spaces 20771 html = html.replace(/\u200B/g, ''); 20772 html = html.replace(/​/gi, ''); 20773 //html = html.replace(/ /gi, ' '); 20774 20775 if (html.search(/^<p>(||\s||<br\s?\/?>|| )<\/p>$/i) !== -1) 20776 { 20777 return ''; 20778 } 20779 20780 // remove image resize 20781 html = html.replace(/<span(.*?)id="redactor-image-box"(.*?[^>])>([\w\W]*?)<img(.*?)><\/span>/gi, '$3<img$4>'); 20782 html = html.replace(/<span(.*?)id="redactor-image-resizer"(.*?[^>])>(.*?)<\/span>/gi, ''); 20783 html = html.replace(/<span(.*?)id="redactor-image-editter"(.*?[^>])>(.*?)<\/span>/gi, ''); 20784 html = html.replace(/<img(.*?)style="(.*?)opacity: 0\.5;(.*?)"(.*?)>/gi, '<img$1style="$2$3"$4>'); 20785 20786 var $div = $("<div/>").html($.parseHTML(html, document, true)); 20787 20788 // remove empty atributes 20789 $div.find('*[style=""]').removeAttr('style'); 20790 $div.find('*[class=""]').removeAttr('class'); 20791 $div.find('*[rel=""]').removeAttr('rel'); 20792 $div.find('*[data-image=""]').removeAttr('data-image'); 20793 $div.find('*[alt=""]').removeAttr('alt'); 20794 $div.find('*[title=""]').removeAttr('title'); 20795 $div.find('*[data-redactor-style-cache]').removeAttr('data-redactor-style-cache'); 20796 20797 // remove markers 20798 $div.find('.redactor-invisible-space, .redactor-unlink').each(function() 20799 { 20800 $(this).contents().unwrap(); 20801 }); 20802 20803 // remove span without attributes & span marker 20804 $div.find('span, a').removeAttr('data-redactor-span data-redactor-style-cache').each(function() 20805 { 20806 if (this.attributes.length === 0) 20807 { 20808 $(this).contents().unwrap(); 20809 } 20810 }); 20811 20812 // remove rel attribute from img 20813 $div.find('img').removeAttr('rel'); 20814 20815 $div.find('.redactor-selection-marker, #redactor-insert-marker').remove(); 20816 20817 html = $div.html(); 20818 20819 // reconvert script tag 20820 if (this.opts.script) 20821 { 20822 html = html.replace(/<pre class="redactor-script-tag"(.*?[^>]?)>([\w\W]*?)<\/pre>/gi, '<script$1>$2</script>'); 20823 } 20824 20825 // restore form tag 20826 html = this.clean.restoreFormTags(html); 20827 20828 // remove br in|of li/header tags 20829 html = html.replace(new RegExp('<br\\s?/?></h', 'gi'), '</h'); 20830 html = html.replace(new RegExp('<br\\s?/?></li>', 'gi'), '</li>'); 20831 html = html.replace(new RegExp('</li><br\\s?/?>', 'gi'), '</li>'); 20832 20833 // pre class 20834 html = html.replace(/<pre>/gi, "<pre>\n"); 20835 if (this.opts.preClass) 20836 { 20837 html = html.replace(/<pre>/gi, '<pre class="' + this.opts.preClass + '">'); 20838 } 20839 20840 // link nofollow 20841 if (this.opts.linkNofollow) 20842 { 20843 html = html.replace(/<a(.*?)rel="nofollow"(.*?[^>])>/gi, '<a$1$2>'); 20844 html = html.replace(/<a(.*?[^>])>/gi, '<a$1 rel="nofollow">'); 20845 } 20846 20847 // replace special characters 20848 var chars = { 20849 '\u2122': '™', 20850 '\u00a9': '©', 20851 '\u2026': '…', 20852 '\u2014': '—', 20853 '\u2010': '‐' 20854 }; 20855 20856 $.each(chars, function(i,s) 20857 { 20858 html = html.replace(new RegExp(i, 'g'), s); 20859 }); 20860 20861 html = html.replace(/&/g, '&'); 20862 20863 // remove empty paragpraphs 20864 //html = html.replace(/<p><\/p>/gi, ""); 20865 20866 // remove new lines 20867 html = html.replace(/\n{2,}/g, "\n"); 20868 20869 // remove all newlines 20870 if (this.opts.removeNewlines) 20871 { 20872 html = html.replace(/\r?\n/g, ""); 20873 } 20874 20875 return html; 20876 }, 20877 onPaste: function(html, data, insert) 20878 { 20879 // if paste event 20880 if (insert !== true) 20881 { 20882 // remove google docs markers 20883 html = html.replace(/<b\sid="internal-source-marker(.*?)">([\w\W]*?)<\/b>/gi, "$2"); 20884 html = html.replace(/<b(.*?)id="docs-internal-guid(.*?)">([\w\W]*?)<\/b>/gi, "$3"); 20885 20886 // google docs styles 20887 html = html.replace(/<span[^>]*(font-style: italic; font-weight: bold|font-weight: bold; font-style: italic)[^>]*>([\w\W]*?)<\/span>/gi, '<b><i>$2</i></b>'); 20888 html = html.replace(/<span[^>]*(font-style: italic; font-weight: 700|font-weight: 700; font-style: italic)[^>]*>([\w\W]*?)<\/span>/gi, '<b><i>$2</i></b>'); 20889 html = html.replace(/<span[^>]*font-style: italic[^>]*>([\w\W]*?)<\/span>/gi, '<i>$1</i>'); 20890 html = html.replace(/<span[^>
20890]*font-weight: bold[^>]*>([\w\W]*?)<\/span>/gi, '<b>$1</b>'); 20891 html = html.replace(/<span[^>]*font-weight: 700[^>]*>([\w\W]*?)<\/span>/gi, '<b>$1</b>'); 20892 20893 // op tag 20894 html = html.replace(/<o:p[^>]*>/gi, ''); 20895 html = html.replace(/<\/o:p>/gi, ''); 20896 20897 var msword = this.clean.isHtmlMsWord(html); 20898 if (msword) 20899 { 20900 html = this.clean.cleanMsWord(html); 20901 } 20902 } 20903 20904 html = $.trim(html); 20905 20906 if (data.pre) 20907 { 20908 if (this.opts.preSpaces) 20909 { 20910 html = html.replace(/\t/g, new Array(this.opts.preSpaces + 1).join(' ')); 20911 } 20912 } 20913 else 20914 { 20915 20916 html = this.clean.replaceBrToNl(html); 20917 html = this.clean.removeTagsInsidePre(html); 20918 } 20919 20920 // if paste event 20921 if (insert !== true) 20922 { 20923 html = this.clean.removeEmptyInlineTags(html); 20924 20925 if (data.encode === false) 20926 { 20927 html = html.replace(/&/g, '&'); 20928 html = this.clean.convertTags(html, data); 20929 html = this.clean.getPlainText(html); 20930 html = this.clean.reconvertTags(html, data); 20931 } 20932 20933 } 20934 20935 if (data.text) 20936 { 20937 html = this.clean.replaceNbspToSpaces(html); 20938 html = this.clean.getPlainText(html); 20939 } 20940 20941 if (data.lists) 20942 { 20943 html = html.replace("\n", '<br>'); 20944 } 20945 20946 if (data.encode) 20947 { 20948 html = this.clean.encodeHtml(html); 20949 } 20950 20951 if (data.paragraphize) 20952 { 20953 // ff bugfix 20954 html = html.replace(/ \n/g, ' '); 20955 html = html.replace(/\n /g, ' '); 20956 20957 html = this.paragraphize.load(html); 20958 20959 // remove empty p 20960 html = html.replace(/<p><\/p>/g, ''); 20961 } 20962 20963 // remove paragraphs form lists (google docs bug) 20964 html = html.replace(/<li><p>/g, '<li>'); 20965 html = html.replace(/<\/p><\/li>/g, '</li>'); 20966 20967 return html; 20968 20969 }, 20970 getCurrentType: function(html, insert) 20971 { 20972 var blocks = this.selection.blocks(); 20973 20974 var data = { 20975 text: false, 20976 encode: false, 20977 paragraphize: true, 20978 line: this.clean.isHtmlLine(html), 20979 blocks: this.clean.isHtmlBlocked(html), 20980 pre: false, 20981 lists: false, 20982 block: true, 20983 inline: true, 20984 links: true, 20985 images: true 20986 }; 20987 20988 if (blocks.length === 1 && this.utils.isCurrentOrParent(['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'a', 'figcaption'])) 20989 { 20990 data.text = true; 20991 data.paragraphize = false; 20992 data.inline = false; 20993 data.images = false; 20994 data.links = false; 20995 data.line = true; 20996 } 20997 else if (this.opts.type === 'inline' || this.opts.enterKey === false) 20998 { 20999 data.paragraphize = false; 21000 data.block = false; 21001 data.line = true; 21002 } 21003 else if (blocks.length === 1 && this.utils.isCurrentOrParent(['li'])) 21004 { 21005 data.lists = true; 21006 data.block = false; 21007 data.paragraphize = false; 21008 data.images = false; 21009 } 21010 else if (blocks.length === 1 && this.utils.isCurrentOrParent(['th', 'td', 'blockquote'])) 21011 { 21012 data.block = false; 21013 data.paragraphize = false; 21014 21015 } 21016 else if (this.opts.type === 'pre' || (blocks.length === 1 && this.utils.isCurrentOrParent('pre'))) 21017 { 21018 data.inline = false; 21019 data.block = false; 21020 data.encode = true; 21021 data.pre = true; 21022 data.paragraphize = false; 21023 data.images = false; 21024 data.links = false; 21025 } 21026 21027 if (data.line === true) 21028 { 21029 data.paragraphize = false; 21030 } 21031 21032 if (insert === true) 21033 { 21034 data.text = false; 21035 } 21036 21037 return data; 21038 21039 }, 21040 isHtmlBlocked: function(html) 21041 { 21042 var match1 = html.match(new RegExp('</(' + this.opts.blockTags.join('|' ).toUpperCase() + ')>', 'gi')); 21043 var match2 = html.match(new RegExp('<hr(.*?[^>])>', 'gi')); 21044 21045 return (match1 === null && match2 === null) ? false : true; 21046 }, 21047 isHtmlLine: function(html) 21048 { 21049 if (this.clean.isHtmlBlocked(html)) 21050 { 21051 return false; 21052 } 21053 21054 var matchBR = html.match(/<br\s?\/?>/gi); 21055 var matchNL = html.match(/\n/gi); 21056 21057 return (!matchBR && !matchNL) ? true : false;
21058 }, 21059 isHtmlMsWord: function(html) 21060 { 21061 return html.match(/class="?Mso|style="[^"]*\bmso-|style='[^'']*\bmso-|w:WordDocument/i); 21062 }, 21063 removeEmptyInlineTags: function(html) 21064 { 21065 var tags = this.opts.inlineTags; 21066 var $div = $("<div/>").html($.parseHTML(html, document, true)); 21067 var self = this; 21068 21069 var $spans = $div.find('span'); 21070 var $tags = $div.find(tags.join(',')); 21071 21072 $tags.removeAttr('style'); 21073 21074 $tags.each(function() 21075 { 21076 var tagHtml = $(this).html(); 21077 if (this.attributes.length === 0 && self.utils.isEmpty(tagHtml)) 21078 { 21079 $(this).replaceWith(function() 21080 { 21081 return $(this).contents(); 21082 }); 21083 } 21084 }); 21085 21086 $spans.each(function() 21087 { 21088 var tagHtml = $(this).html(); 21089 if (this.attributes.length === 0) 21090 { 21091 $(this).replaceWith(function() 21092 { 21093 return $(this).contents(); 21094 }); 21095 } 21096 }); 21097 21098 html = $div.html(); 21099 21100 // convert php tags 21101 html = html.replace('<!--?php', '<?php'); 21102 html = html.replace('<!--?', '<?'); 21103 html = html.replace('?-->', '?>'); 21104 21105 $div.remove(); 21106 21107 return html; 21108 }, 21109 cleanMsWord: function(html) 21110 { 21111 html = html.replace(/<!--[\s\S]*?-->/g, ""); 21112 html = html.replace(/<o:p>[\s\S]*?<\/o:p>/gi, ''); 21113 html = html.replace(/\n/g, " "); 21114 html = html.replace(/<br\s?\/?>|<\/p>|<\/div>|<\/li>|<\/td>/gi, '\n\n'); 21115 21116 // lists 21117 var $div = $("<div/>").html(html); 21118 21119 var lastList = false; 21120 var lastLevel = 1; 21121 var listsIds = []; 21122 21123 $div.find("p[style]").each(function() 21124 { 21125 var matches = $(this).attr('style').match(/mso\-list\:l([0-9]+)\slevel([0-9]+)/); 21126 21127 if (matches) 21128 { 21129 var currentList = parseInt(matches[1]); 21130 var currentLevel = parseInt(matches[2]); 21131 var listType = $(this).html().match(/^[\w]+\./) ? "ol" : "ul"; 21132 21133 var $li = $("<li/>").html($(this).html()); 21134 21135 $li.html($li.html().replace(/^([\w\.]+)</, '<')); 21136 $li.find("span:first").remove(); 21137 21138 if (currentLevel == 1 && $.inArray(currentList, listsIds) == -1) 21139 { 21140 var $list = $("<" + listType + "/>").attr({"data-level": currentLevel, "data-list": currentList}).html($li); 21141 $(this).replaceWith($list); 21142 21143 lastList = currentList; 21144 listsIds.push(currentList); 21145 } 21146 else 21147 { 21148 if (currentLevel > lastLevel) 21149 { 21150 var $prevList = $div.find('[data-level="' + lastLevel + '"][data-list="' + lastList + '"]'); 21151 var $lastList = $prevList; 21152 21153 for(var i = lastLevel; i < currentLevel; i++) 21154 { 21155 $list = $("<" + listType + "/>"); 21156 $list.appendTo($lastList.find("li").last()); 21157 21158 $lastList = $list; 21159 } 21160 21161 $lastList.attr({"data-level": currentLevel, "data-list": currentList}).html($li); 21162 21163 } 21164 else 21165 { 21166 var $prevList = $div.find('[data-level="' + currentLevel + '"][data-list="' + currentList + '"]').last(); 21167 21168 $prevList.append($li); 21169 } 21170 21171 lastLevel = currentLevel; 21172 lastList = currentList; 21173 21174 $(this).remove(); 21175 } 21176 } 21177 }); 21178 21179 $div.find('[data-level][data-list]').removeAttr('data-level data-list'); 21180 html = $div.html(); 21181 21182 return html; 21183 }, 21184 replaceNbspToSpaces: function(html) 21185 { 21186 return html.replace(' ', ' '); 21187 }, 21188 replaceBrToNl: function(html) 21189 { 21190 return html.replace(/<br\s?\/?>/gi, '\n'); 21191 }, 21192 replaceNlToBr: function(html) 21193 { 21194 return html.replace(/\n/g, '<br />'); 21195 }, 21196 convertTags: function(html, data) 21197 { 21198 var $div = $('<div>').html(html); 21199 21200 // remove iframe 21201 $div.find('iframe').remove(); 21202 21203 // link target & attrs 21204 var $links = $div.find('a'); 21205 $links.removeAttr('style'); 21206 if (this.opts.pasteLinkTarget !== false) 21207 { 21208 $links.attr('target', this.opts.pasteLinkTarget); 21209 } 21210 21211 // links 21212 if (data.links && this.opts.pasteLinks) 21213 { 21214 $div.find('a').each(function(i, link) 21215 { 21216 if (link.href) 21217 { 21218 var tmp = '#####[a href="' + link.href + '"'; 21219 var attr; 21220 for (var j = 0, length = link.attributes.length; j < length; j++) 21221 { 21222 attr = link.attributes.item(j); 21223 if (attr.name !== 'href') 21224 { 21225 tmp += ' ' + attr.name + '="' + attr.value + '"'; 21226 } 21227 } 21228 21229 link.outerHTML = tmp + ']#####' + link.innerHTML + '#####[/a]#####'; 21230 } 21231 }); 21232 } 21233 21234 html = $div.html(); 21235 21236 // images 21237 if (data.images && this.opts.pasteImages) 21238 { 21239 html = html.replace(/<img(.*?)src="(.*?)"(.*?[^>])>/gi, '#####[img$1src="$2"$3]#####'); 21240 } 21241 21242 // plain text 21243 if (this.opts.pastePlainText) 21244 { 21245 return html; 21246 } 21247 21248 // all tags 21249 var blockTags = (data.lists) ? ['ul', 'ol', 'li'] : this.opts.pasteBlockTags; 21250 21251 var tags; 21252 if (data.block || data.lists) 21253 { 21254 tags = (data.inline) ? blockTags.concat(this.opts.pasteInlineTags) : blockTags; 21255 } 21256 else 21257 { 21258 tags = (data.inline) ? this.opts.pasteInlineTags : []; 21259 } 21260 21261 var len = tags.length; 21262 for (var i = 0; i < len; i++) 21263 { 21264 html = html.replace(new RegExp('<\/' + tags[i] + '>', 'gi'), '###/' + tags[i] + '###'); 21265 21266 if (tags[i] === 'td' || tags[i] === 'th') 21267 { 21268 html = html.replace(new RegExp('<' + tags[i] + '(.*?[^>])((colspan|rowspan)="(.*?[^>])")?(.*?[^>])>
21268', 'gi'), '###' + tags[i] + ' $2###'); 21269 } 21270 else if (this.utils.isInlineTag(tags[i])) 21271 { 21272 html = html.replace(new RegExp('<' + tags[i] + '([^>]*)class="([^>]*)"[^>]*>', 'gi'), '###' + tags[i] + ' class="$2"###'); 21273 html = html.replace(new RegExp('<' + tags[i] + '([^>]*)data-redactor-style-cache="([^>]*)"[^>]*>', 'gi'), '###' + tags[i] + ' cache="$2"###'); 21274 html = html.replace(new RegExp('<' + tags[i] + '[^>]*>', 'gi'), '###' + tags[i] + '###'); 21275 } 21276 else 21277 { 21278 html = html.replace(new RegExp('<' + tags[i] + '[^>]*>', 'gi'), '###' + tags[i] + '###'); 21279 } 21280 } 21281 21282 return html; 21283 21284 }, 21285 reconvertTags: function(html, data) 21286 { 21287 // links & images 21288 if ((data.links && this.opts.pasteLinks) || (data.images && this.opts.pasteImages)) 21289 { 21290 html = html.replace(new RegExp('#####\\[', 'gi'), '<'); 21291 html = html.replace(new RegExp('\\]#####', 'gi'), '>'); 21292 } 21293 21294 // plain text 21295 if (this.opts.pastePlainText) 21296 { 21297 return html; 21298 } 21299 21300 var blockTags = (data.lists) ? ['ul', 'ol', 'li'] : this.opts.pasteBlockTags; 21301 21302 var tags; 21303 if (data.block || data.lists) 21304 { 21305 tags = (data.inline) ? blockTags.concat(this.opts.pasteInlineTags) : blockTags; 21306 } 21307 else 21308 { 21309 tags = (data.inline) ? this.opts.pasteInlineTags : []; 21310 } 21311 21312 var len = tags.length; 21313 for (var i = 0; i < len; i++) 21314 { 21315 html = html.replace(new RegExp('###\/' + tags[i] + '###', 'gi'), '</' + tags[i] + '>'); 21316 } 21317 21318 for (var i = 0; i < len; i++) 21319 { 21320 html = html.replace(new RegExp('###' + tags[i] + '###', 'gi'), '<' + tags[i] + '>'); 21321 } 21322 21323 for (var i = 0; i < len; i++) 21324 { 21325 if (tags[i] === 'td' || tags[i] === 'th') 21326 { 21327 html = html.replace(new RegExp('###' + tags[i] + '\s?(.*?[^#])###', 'gi'), '<' + tags[i] + '$1>'); 21328 } 21329 else if (this.utils.isInlineTag(tags[i])) 21330 { 21331 21332 var spanMarker = (tags[i] === 'span') ? ' data-redactor-span="true"' : ''; 21333 21334 html = html.replace(new RegExp('###' + tags[i] + ' cache="(.*?[^#])"###', 'gi'), '<' + tags[i] + ' style="$1"' + spanMarker + ' data-redactor-style-cache="$1">'); 21335 html = html.replace(new RegExp('###' + tags[i] + '\s?(.*?[^#])###', 'gi'), '<' + tags[i] + '$1>'); 21336 } 21337 } 21338 21339 return html; 21340 21341 }, 21342 cleanPre: function(block) 21343 { 21344 block = (typeof block === 'undefined') ? $(this.selection.block()).closest('pre', this.core.editor()[0]) : block; 21345 21346 $(block).find('br').replaceWith(function() 21347 { 21348 return document.createTextNode('\n'); 21349 }); 21350 21351 $(block).find('p').replaceWith(function() 21352 { 21353 return $(this).contents(); 21354 }); 21355 21356 }, 21357 removeTagsInsidePre: function(html) 21358 { 21359 var $div = $('<div />').append(html); 21360 $div.find('pre').replaceWith(function() 21361 { 21362 var str = $(this).html(); 21363 str = str.replace(/<br\s?\/?>|<\/p>|<\/div>|<\/li>|<\/td>/gi, '\n'); 21364 str = str.replace(/(<([^>]+)>)/gi, ''); 21365 21366 return $('<pre />').append(str); 21367 }); 21368 21369 html = $div.html(); 21370 $div.remove(); 21371 21372 return html; 21373 21374 }, 21375 getPlainText: function(html) 21376 { 21377 html = html.replace(/<!--[\s\S]*?-->/gi, ''); 21378 html = html.replace(/<style[\s\S]*?style>/gi, ''); 21379 html = html.replace(/<p><\/p>/g, ''); 21380 html = html.replace(/<\/div>|<\/li>|<\/td>/gi, '\n'); 21381 html = html.replace(/<\/p>/gi, '\n\n'); 21382 html = html.replace(/<\/H[1-6]>/gi, '\n\n'); 21383 21384 var tmp = document.createElement('div'); 21385 tmp.innerHTML = html; 21386 html = tmp.textContent || tmp.innerText; 21387 21388 return $.trim(html); 21389 }, 21390 savePreCode: function(html) 21391 { 21392 html = this.clean.savePreFormatting(html); 21393 html = this.clean.saveCodeFormatting(html); 21394 html = this.clean.restoreSelectionMarkers(html); 21395 21396 return html; 21397 }, 21398 savePreFormatting: function(html) 21399 { 21400 var pre = html.match(/<pre(.*?)>([\w\W]*?)<\/pre>/gi); 21401 if (pre === null) 21402 { 21403 return html; 21404 } 21405 21406 $.each(pre, $.proxy(function(i,s) 21407 { 21408 var arr = []; 21409 var codeTag = false;
21410 var contents, attr1, attr2; 21411 21412 if (s.match(/<pre(.*?)>(([\n\r\s]+)?)<code(.*?)>/i)) 21413 { 21414 arr = s.match(/<pre(.*?)>(([\n\r\s]+)?)<code(.*?)>([\w\W]*?)<\/code>(([\n\r\s]+)?)<\/pre>/i); 21415 codeTag = true; 21416 21417 contents = arr[5]; 21418 attr1 = arr[1]; 21419 attr2 = arr[4]; 21420 } 21421 else 21422 { 21423 arr = s.match(/<pre(.*?)>([\w\W]*?)<\/pre>/i); 21424 21425 contents = arr[2]; 21426 attr1 = arr[1]; 21427 } 21428 21429 contents = contents.replace(/<br\s?\/?>/g, '\n'); 21430 contents = contents.replace(/ /g, ' '); 21431 21432 if (this.opts.preSpaces) 21433 { 21434 contents = contents.replace(/\t/g, new Array(this.opts.preSpaces + 1).join(' ')); 21435 } 21436 21437 contents = this.clean.encodeEntities(contents); 21438 21439 // $ fix 21440 contents = contents.replace(/\$/g, '$'); 21441 21442 if (codeTag) 21443 { 21444 html = html.replace(s, '<pre' + attr1 + '><code' + attr2 + '>' + contents + '</code></pre>'); 21445 } 21446 else 21447 { 21448 html = html.replace(s, '<pre' + attr1 + '>' + contents + '</pre>'); 21449 } 21450 21451 21452 }, this)); 21453 21454 return html; 21455 }, 21456 saveCodeFormatting: function(html) 21457 { 21458 var code = html.match(/<code(.*?)>([\w\W]*?)<\/code>/gi); 21459 if (code === null) 21460 { 21461 return html; 21462 } 21463 21464 $.each(code, $.proxy(function(i,s) 21465 { 21466 var arr = s.match(/<code(.*?)>([\w\W]*?)<\/code>/i); 21467 21468 arr[2] = arr[2].replace(/ /g, ' '); 21469 arr[2] = this.clean.encodeEntities(arr[2]); 21470 arr[2] = arr[2].replace(/\$/g, '$'); 21471 21472 html = html.replace(s, '<code' + arr[1] + '>' + arr[2] + '</code>'); 21473 21474 }, this)); 21475 21476 return html; 21477 }, 21478 restoreSelectionMarkers: function(html) 21479 { 21480 html = html.replace(/<span id="selection-marker-([0-9])" class="redactor-selection-marker">â<\/span>/g, '<span id="selection-marker-$1" class="redactor-selection-marker">â</span>'); 21481 21482 return html; 21483 }, 21484 saveFormTags: function(html) 21485 { 21486 return html.replace(/<form(.*?)>([\w\W]*?)<\/form>/gi, '<section$1 rel="redactor-form-tag">$2</section>'); 21487 }, 21488 restoreFormTags: function(html) 21489 { 21490 return html.replace(/<section(.*?) rel="redactor-form-tag"(.*?)>([\w\W]*?)<\/section>/gi, '<form$1$2>$3</form>'); 21491 }, 21492 encodeHtml: function(html) 21493 { 21494 html = html.replace(/â/g, '"'); 21495 html = html.replace(/â/g, '"'); 21496 html = html.replace(/â/g, '\''); 21497 html = html.replace(/â/g, '\''); 21498 html = this.clean.encodeEntities(html); 21499 21500 return html; 21501 }, 21502 encodeEntities: function(str) 21503 { 21504 str = String(str).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"'); 21505 str = str.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"'); 21506 21507 return str; 21508 }, 21509 stripTags: function(input, denied) 21510 { 21511 if (typeof denied === 'undefined') 21512 { 21513 return input.replace(/(<([^>]+)>)/gi, ''); 21514 } 21515 21516 var tags = /<\/?([a-z][a-z0-9]*)\b[^>]*>/gi; 21517 21518 return input.replace(tags, function ($0, $1) 21519 { 21520 return denied.indexOf($1.toLowerCase()) === -1 ? $0 : ''; 21521 }); 21522 }, 21523 removeMarkers: function(html) 21524 { 21525 return html.replace(/<span(.*?[^>]?)class="redactor-selection-marker"(.*?[^>]?)>([\w\W]*?)<\/span>/gi, ''); 21526 }, 21527 removeSpaces: function(html) 21528 { 21529 html = $.trim(html); 21530 html = html.replace(/\n/g, ''); 21531 html = html.replace(/[\t]*/g, ''); 21532 html = html.replace(/\n\s*\n/g, "\n"); 21533 html = html.replace(/^[\s\n]*/g, ' '); 21534 html = html.replace(/[\s\n]*$/g, ' '); 21535 html = html.replace( />\s{2,}</g, '> <'); // between inline tags can be only one space 21536 html = html.replace(/\n\n/g, "\n"); 21537 html = html.replace(/\u200B/g, ''); 21538 21539 return html; 21540 }, 21541 removeSpacesHard: function(html) 21542 { 21543 html = $.trim(html); 21544 html = html.replace(/\n/g, ''); 21545 html = html.replace(/[\t]*/g, ''); 21546 html = html.replace(/\n\s*\n/g, "\n"); 21547 html = html.replace(/^[\s\n]*/g, ''); 21548 html = html.replace(/[\s\n]*$/g, ''); 21549 html = html.replace( />\s{2,}</g, '><'); 21550 html = html.replace(/\n\n/g, "\n"); 21551 html = html.replace(/\u200B/g, ''); 21552 21553 return html; 21554 }, 21555 normalizeCurrentHeading: function() 21556 { 21557 var heading = this.selection.block(); 21558 if (this.utils.isCurrentOrParentHeader() && heading) 21559 { 21560 heading.normalize(); 21561 } 21562 } 21563 }; 21564 }, 21565 21566 // =code 21567 code: function() 21568 { 21569 return { 21570 syncFire: true, 21571 html: false, 21572 start: function(html) 21573 { 21574 html = $.trim(html); 21575 html = html.replace(/^(<span id="selection-marker-1" class="redactor-selection-marker">â<\/span>)/, ''); 21576 21577 // clean 21578 if (this.opts.type === 'textarea') 21579 { 21580 html = this.clean.onSet(html); 21581 } 21582 else if (this.opts.type === 'div' && html === '') 21583 { 21584 html = this.opts.emptyHtml; 21585 } 21586 21587 html = html.replace(/<p><span id="selection-marker-1" class="redactor-selection-marker">â<\/span><\/p>/, ''); 21588 21589 this.events.stopDetectChanges(); 21590 this.core.editor().html(html); 21591 this.observe.load(); 21592 this.events.startDetectChanges(); 21593 }, 21594 set: function(html, options) 21595 { 21596 html = $.trim(html); 21597 21598 options = options || {}; 21599 21600 // start 21601 if (options.start) 21602 { 21603 this.start = options.start; 21604 } 21605 21606 // clean 21607 if (this.opts.type === 'textarea') 21608 { 21609 html = this.clean.onSet(html); 21610 } 21611 else if (this.opts.type === 'div' && html === '') 21612 { 21613 html = this.opts.emptyHtml; 21614 } 21615 21616 this.core.editor().html(html); 21617 21618 if (this.opts.type === 'textarea') 21619 { 21620 this.code.sync(); 21621 } 21622 21623 this.placeholder.enable(); 21624 }, 21625 get: function() 21626 { 21627 if (this.opts.type === 'textarea') 21628 { 21629 return this.core.textarea().val(); 21630 } 21631 else 21632 { 21633 var html = this.core.editor().html(); 21634 21635 // clean 21636 html = this.clean.onGet(html); 21637 21638 return html; 21639 } 21640 }, 21641 sync: function() 21642 { 21643 if (!this.code.syncFire) 21644 { 21645 return; 21646 } 21647 21648 var html = this.core.editor().html();
21649 var htmlCleaned = this.code.cleaned(html); 21650 21651 // is there a need to synchronize 21652 if (this.code.isSync(htmlCleaned)) 21653 { 21654 // do not sync 21655 return; 21656 } 21657 21658 // save code 21659 this.code.html = htmlCleaned; 21660 21661 if (this.opts.type !== 'textarea') 21662 { 21663 this.core.callback('sync', html); 21664 this.core.callback('change', html); 21665 return; 21666 } 21667 21668 if (this.opts.type === 'textarea') 21669 { 21670 setTimeout($.proxy(function() 21671 { 21672 this.code.startSync(html); 21673 21674 }, this), 10); 21675 } 21676 }, 21677 startSync: function(html) 21678 { 21679 // before clean callback 21680 html = this.core.callback('syncBefore', html); 21681 21682 // clean 21683 html = this.clean.onSync(html); 21684 21685 // set code 21686 this.core.textarea().val(html); 21687 21688 // after sync callback 21689 this.core.callback('sync', html); 21690 21691 // change callback 21692 if (this.start === false) 21693 { 21694 this.core.callback('change', html); 21695 } 21696 21697 this.start = false; 21698 }, 21699 isSync: function(htmlCleaned) 21700 { 21701 var html = (this.code.html !== false) ? this.code.html : false; 21702 21703 return (html !== false && html === htmlCleaned); 21704 }, 21705 cleaned: function(html) 21706 { 21707 html = html.replace(/\u200B/g, ''); 21708 return this.clean.removeMarkers(html); 21709 } 21710 }; 21711 }, 21712 21713 // =core 21714 core: function() 21715 { 21716 return { 21717 21718 id: function() 21719 { 21720 return this.$editor.attr('id'); 21721 }, 21722 element: function() 21723 { 21724 return this.$element; 21725 }, 21726 editor: function() 21727 { 21728 return (typeof this.$editor === 'undefined') ? $() : this.$editor; 21729 }, 21730 textarea: function() 21731 { 21732 return this.$textarea; 21733 }, 21734 box: function() 21735 { 21736 return (this.opts.type === 'textarea') ? this.$box : this.$element; 21737 }, 21738 toolbar: function() 21739 { 21740 return (this.$toolbar) ? this.$toolbar : false; 21741 }, 21742 air: function() 21743 { 21744 return (this.$air) ? this.$air : false; 21745 }, 21746 object: function() 21747 { 21748 return $.extend({}, this); 21749 }, 21750 structure: function() 21751 { 21752 this.core.editor().toggleClass('redactor-structure'); 21753 }, 21754 addEvent: function(name) 21755 { 21756 this.core.event = name; 21757 }, 21758 getEvent: function() 21759 { 21760 return this.core.event; 21761 }, 21762 callback: function(type, e, data) 21763 { 21764 var eventNamespace = 'redactor'; 21765 var returnValue = false; 21766 var events = $._data(this.core.element()[0], 'events'); 21767 21768 // on callback 21769 if (typeof events !== 'undefined' && typeof events[type] !== 'undefined') 21770 { 21771 var len = events[type].length; 21772 for (var i = 0; i < len; i++) 21773 { 21774 var namespace = events[type][i].namespace; 21775 if (namespace === 'callback.' + eventNamespace) 21776 { 21777 var handler = events[type][i].handler; 21778 var args = (typeof data === 'undefined') ? [e] : [e, data]; 21779 returnValue = (typeof args === 'undefined') ? handler.call(this, e) : handler.call(this, e, args); 21780 } 21781 } 21782 } 21783 21784 if (returnValue) 21785 { 21786 return returnValue; 21787 } 21788 21789 // no callback 21790 if (typeof this.opts.callbacks[type] === 'undefined') 21791 { 21792 return (typeof data === 'undefined') ? e : data; 21793 } 21794 21795 // callback 21796 var callback = this.opts.callbacks[type]; 21797 21798 if ($.isFunction(callback)) 21799 { 21800 return (typeof data === 'undefined') ? callback.call(this, e) : callback.call(this, e, data); 21801 } 21802 else 21803 { 21804 return (typeof data === 'undefined') ? e : data; 21805 } 21806 }, 21807 destroy: function() 21808 { 21809 this.opts.destroyed = true; 21810 21811 this.core.callback('destroy'); 21812 21813 // placeholder 21814 this.placeholder.destroy(); 21815 21816 // progress 21817 this.progress.destroy(); 21818 21819 // help label 21820 $('#redactor-voice-' + this.uuid).remove(); 21821 21822 this.core.editor().removeClass('redactor-in redactor-styles redactor-structure redactor-layer-img-edit'); 21823 21824 // caret service 21825 this.core.editor().off('keydown.redactor-remove-textnode'); 21826 21827 // observer 21828 this.core.editor().off('.redactor-observe.' + this.uuid); 21829 21830 // off events and remove data 21831 this.$element.off('.redactor').removeData('redactor'); 21832 this.core.editor().off('.redactor'); 21833 21834 $(document).off('.redactor-dropdown'); 21835 $(document).off('.redactor-air.' + this.uuid); 21836 $(document).off('mousedown.redactor-blur.' + this.uuid); 21837 $(document).off('mousedown.redactor.' + this.uuid); 21838 $(document).off('touchstart.redactor.' + this.uuid + ' click.redactor.' + this.uuid); 21839 $(window).off('.redactor-toolbar.' + this.uuid); 21840 $(window).off('touchmove.redactor.' + this.uuid); 21841 $("body").off('scroll.redactor.' + this.uuid); 21842 21843 $(this.opts.toolbarFixedTarget).off('scroll.redactor.' + this.uuid); 21844 21845 // plugins events 21846 var self = this; 21847 if (this.opts.plugins !== false) 21848 { 21849 $.each(this.opts.plugins, function(i,s) 21850 { 21851 $(window).off('.redactor-plugin-' + s); 21852 $(document).off('.redactor-plugin-' + s); 21853 $("body").off('.redactor-plugin-' + s); 21854 self.core.editor().off('.redactor-plugin-' + s); 21855 }); 21856 } 21857 21858 // click to edit 21859 this.$element.off('click.redactor-click-to-edit'); 21860 this.$element.removeClass('redactor-click-to-edit'); 21861 21862 // common 21863 this.core.editor().removeClass('redactor-layer'); 21864 this.core.editor().removeAttr('contenteditable'); 21865
21866 var html = this.code.get(); 21867 21868 if (this.opts.toolbar && this.$toolbar) 21869 { 21870 // dropdowns off 21871 this.$toolbar.find('a').each(function() 21872 { 21873 var $el = $(this); 21874 if ($el.data('dropdown')) 21875 { 21876 $el.data('dropdown').remove(); 21877 $el.data('dropdown', {}); 21878 } 21879 }); 21880 } 21881 21882 if (this.opts.type === 'textarea') 21883 { 21884 this.$box.after(this.$element); 21885 this.$box.remove(); 21886 this.$element.val(html).show(); 21887 } 21888 21889 // air 21890 if (this.opts.air) 21891 { 21892 this.$air.remove(); 21893 } 21894 21895 if (this.opts.toolbar && this.$toolbar) 21896 { 21897 this.$toolbar.remove(); 21898 } 21899 21900 // modal 21901 if (this.$modalBox) 21902 { 21903 this.$modalBox.remove(); 21904 } 21905 21906 if (this.$modalOverlay) 21907 { 21908 this.$modalOverlay.remove(); 21909 } 21910 21911 // hide link's tooltip 21912 $('.redactor-link-tooltip').remove(); 21913 21914 // autosave 21915 clearInterval(this.autosaveTimeout); 21916 } 21917 }; 21918 }, 21919 21920 // =detect 21921 detect: function() 21922 { 21923 return { 21924 21925 // public 21926 isWebkit: function() 21927 { 21928 return /webkit/.test(this.opts.userAgent); 21929 }, 21930 isFirefox: function() 21931 { 21932 return this.opts.userAgent.indexOf('firefox') > -1; 21933 }, 21934 isIe: function(v) 21935 { 21936 if (document.documentMode || /Edge/.test(navigator.userAgent)) 21937 { 21938 return 'edge'; 21939 } 21940 21941 var ie; 21942 ie = RegExp('msie' + (!isNaN(v)?('\\s'+v):''), 'i').test(navigator.userAgent); 21943 21944 if (!ie) 21945 { 21946 ie = !!navigator.userAgent.match(/Trident.*rv[ :]*11\./); 21947 } 21948 21949 return ie; 21950 }, 21951 isMobile: function() 21952 { 21953 return /(iPhone|iPod|BlackBerry|Android)/.test(navigator.userAgent); 21954 }, 21955 isDesktop: function() 21956 { 21957 return !/(iPhone|iPod|iPad|BlackBerry|Android)/.test(navigator.userAgent); 21958 }, 21959 isIpad: function() 21960 { 21961 return /iPad/.test(navigator.userAgent); 21962 } 21963 21964 }; 21965 }, 21966 21967 // =dropdown 21968 dropdown: function() 21969 { 21970 return { 21971 active: false, 21972 button: false, 21973 key: false, 21974 position: [], 21975 getDropdown: function() 21976 { 21977 return this.dropdown.active; 21978 }, 21979 build: function(name, $dropdown, dropdownObject) 21980 { 21981 dropdownObject = this.dropdown.buildFormatting(name, dropdownObject); 21982 21983 $.each(dropdownObject, $.proxy(function(btnName, btnObject) 21984 { 21985 var $item = this.dropdown.buildItem(btnName, btnObject); 21986 21987 this.observe.addDropdown($item, btnName, btnObject); 21988 $dropdown.attr('rel', name).append($item); 21989 21990 }, this)); 21991 }, 21992 buildFormatting: function(name, dropdownObject) 21993 { 21994 if (name !== 'format' || this.opts.formattingAdd === false) 21995 { 21996 return dropdownObject; 21997 } 21998 21999 $.each(this.opts.formattingAdd, $.proxy(function(i,s) 22000 { 22001 var type = (this.utils.isBlockTag(s.args[0])) ? 'block' : 'inline'; 22002 22003 dropdownObject[i] = { 22004 func: (type === 'block') ? 'block.format' : 'inline.format', 22005 args: s.args, 22006 title: s.title 22007 }; 22008 22009 }, this)); 22010 22011 return dropdownObject; 22012 }, 22013 buildItem: function(btnName, btnObject) 22014 { 22015 var $itemContainer = $('<li />'); 22016 if (typeof btnObject.classname !== 'undefined') 22017 { 22018 $itemContainer.addClass(btnObject.classname); 22019 } 22020 22021 if (btnName.search(/^divider/i) !== -1) 22022 { 22023 $itemContainer.addClass('redactor-dropdown-divider'); 22024 22025 return $itemContainer; 22026 } 22027 22028 var $item = $('<a href="#" class="redactor-dropdown-' + btnName + '" role="button" />'); 22029 var $itemSpan = $('<span />').html(btnObject.title); 22030 22031 $item.append($itemSpan); 22032 $item.on('mousedown', $.proxy(function(e) 22033 { 22034 e.preventDefault(); 22035 22036 this.dropdown.buildClick(e, btnName, btnObject); 22037 22038 }, this)); 22039 22040 $itemContainer.append($item); 22041 22042 return $itemContainer; 22043 22044 }, 22045 buildClick: function(e, btnName, btnObject) 22046 { 22047 if ($(e.target).hasClass('redactor-dropdown-link-inactive')) 22048 { 22049 return; 22050 } 22051 22052 var command = this.dropdown.buildCommand(btnObject); 22053 22054 if (typeof btnObject.args !== 'undefined') 22055 { 22056 this.button.toggle(e, btnName, command.type, command.callback, btnObject.args); 22057 } 22058 else 22059 { 22060 this.button.toggle(e, btnName, command.type, command.callback); 22061 } 22062 }, 22063 buildCommand: function(btnObject) 22064 { 22065 var command = {}; 22066 command.type = 'func'; 22067 command.callback = btnObject.func; 22068 22069 if (btnObject.command) 22070 { 22071 command.type = 'command'; 22072 command.callback = btnObject.command; 22073 } 22074 else if (btnObject.dropdown) 22075 { 22076 command.type = 'dropdown'; 22077 command.callback = btnObject.dropdown; 22078 } 22079 22080 return command; 22081 }, 22082 show: function(e, key) 22083 { 22084 if (this.detect.isDesktop()) 22085 { 22086 this.core.editor().focus(); 22087 } 22088 22089 this.dropdown.hideAll(false, key); 22090 22091 this.dropdown.key = key; 22092 this.dropdown.button = this.button.get(this.dropdown.key); 22093 22094 if (this.dropdown.button.hasClass('dropact')) 22095 { 22096 this.dropdown.hide(); 22097 return; 22098 } 22099 22100 // re append 22101 this.dropdown.active = this.dropdown.button.data('dropdown').appendTo(document.body); 22102 22103 // callback 22104 this.core.callback('dropdownShow', { dropdown: this.dropdown.active, key: this.dropdown.key, button: this.dropdown.button }); 22105 22106 // set button 22107 this.button.setActive(this.dropdown.key); 22108 this.dropdown.button.addClass('dropact'); 22109 22110 // position 22111 this.dropdown.getButtonPosition(); 22112 22113 // show 22114 if (this.button.toolbar().hasClass('toolbar-fixed-box') && this.detect.isDesktop()) 22115 { 22116 this.dropdown.showIsFixedToolbar(); 22117 } 22118 else 22119 { 22120 this.dropdown.showIsUnFixedToolbar(); 22121 } 22122 22123 // disable scroll whan dropdown scroll 22124 if (this.detect.isDesktop() && !this.detect.isFirefox()) 22125 { 22126 this.dropdown.active.on('mouseover.redactor-dropdown', $.proxy(this.utils.disableBodyScroll, this)); 22127 this.dropdown.active.on('mouseout.redactor-dropdown mousedown.redactor-dropdown', $.proxy(this.utils.enableBodyScroll, this)); 22128 } 22129 22130 e.stopPropagation(); 22131 22132 }, 22133 showIsFixedToolbar: function() 22134 { 22135 var top = this.dropdown.button.position().top + this.dropdown.button.innerHeight() + this.opts.toolbarFixedTo
22135pOffset; 22136 22137 var position = 'fixed'; 22138 if (this.opts.toolbarFixedTarget !== document) 22139 { 22140 top = (this.dropdown.button.innerHeight() + this.$toolbar.offset().top) + this.opts.toolbarFixedTopOffset; 22141 position = 'absolute'; 22142 } 22143 22144 this.dropdown.active.css({ 22145 22146 position: position, 22147 left: this.dropdown.position.left + 'px', 22148 top: top + 'px' 22149 22150 }).show(); 22151 22152 // animate 22153 this.dropdown.active.redactorAnimation('slideDown', { duration: 0.2 }, $.proxy(function() 22154 { 22155 this.dropdown.enableCallback(); 22156 this.dropdown.enableEvents(); 22157 22158 }, this)); 22159 }, 22160 showIsUnFixedToolbar: function() 22161 { 22162 this.dropdown.active.css({ 22163 22164 position: 'absolute', 22165 left: this.dropdown.position.left + 'px', 22166 top: (this.dropdown.button.innerHeight() + this.dropdown.position.top) + 'px' 22167 22168 }).show(); 22169 22170 // animate 22171 this.dropdown.active.redactorAnimation(((this.opts.animation) ? 'slideDown' : 'show'), { duration: 0.2 }, $.proxy(function() 22172 { 22173 this.dropdown.enableCallback(); 22174 this.dropdown.enableEvents(); 22175 22176 }, this)); 22177 }, 22178 enableEvents: function() 22179 { 22180 $(document).on('mousedown.redactor-dropdown', $.proxy(this.dropdown.hideAll, this)); 22181 this.core.editor().on('touchstart.redactor-dropdown', $.proxy(this.dropdown.hideAll, this)); 22182 $(document).on('keyup.redactor-dropdown', $.proxy(this.dropdown.closeHandler, this)); 22183 }, 22184 enableCallback: function() 22185 { 22186 this.core.callback('dropdownShown', { dropdown: this.dropdown.active, key: this.dropdown.key, button: this.dropdown.button }); 22187 }, 22188 getButtonPosition: function() 22189 { 22190 this.dropdown.position = this.dropdown.button.offset(); 22191 22192 // fix right placement 22193 var dropdownWidth = this.dropdown.active.width(); 22194 if ((this.dropdown.position.left + dropdownWidth) > $(document).width()) 22195 { 22196 this.dropdown.position.left = Math.max(0, this.dropdown.position.left - dropdownWidth + parseInt(this.dropdown.button.innerWidth())); 22197 } 22198 22199 }, 22200 closeHandler: function(e) 22201 { 22202 if (e.which !== this.keyCode.ESC) 22203 { 22204 return; 22205 } 22206 22207 this.dropdown.hideAll(e); 22208 this.core.editor().focus(); 22209 }, 22210 hideAll: function(e, key) 22211 { 22212 if (this.detect.isDesktop()) 22213 { 22214 this.utils.enableBodyScroll(); 22215 } 22216 22217 if (e !== false && $(e.target).closest('.redactor-dropdown').length !== 0) 22218 { 22219 return; 22220 } 22221 22222 var $buttons = (typeof key === 'undefined') ? this.button.toolbar().find('a.dropact') : this.button.toolbar().find('a.dropact').not('.re-' + key); 22223 var $elements = (typeof key === 'undefined') ? $('.redactor-dropdown-' + this.uuid) : $('.redactor-dropdown-' + this.uuid).not('.redactor-dropdown-box-' + key); 22224 22225 if ($elements.length !== 0) 22226 { 22227 $(document).off('.redactor-dropdown'); 22228 this.core.editor().off('.redactor-dropdown'); 22229 22230 $.each($elements, $.proxy(function(i,s) 22231 { 22232 var $el = $(s); 22233 22234 this.core.callback('dropdownHide', $el); 22235 22236 $el.hide(); 22237 $el.off('mouseover mouseout').off('.redactor-dropdown'); 22238 22239 }, this)); 22240 22241 $buttons .removeClass('redactor-act dropact'); 22242 } 22243 22244 }, 22245 hide: function () 22246 { 22247 if (this.dropdown.active === false) 22248 { 22249 return; 22250 } 22251 22252 if (this.detect.isDesktop()) 22253 { 22254 this.utils.enableBodyScroll(); 22255 } 22256 22257 this.dropdown.active.redactorAnimation(((this.opts.animation) ? 'slideUp' : 'hide'), { duration: 0.2 }, $.proxy(function() 22258 { 22259 $(document).off('.redactor-dropdown'); 22260 this.core.editor().off('.redactor-dropdown'); 22261 22262 this.dropdown.hideOut(); 22263 22264 22265 }, this)); 22266 }, 22267 hideOut: function() 22268 { 22269 this.core.callback('dropdownHide', this.dropdown.active); 22270 22271 this.dropdown.button.removeClass('redactor-act dropact'); 22272 this.dropdown.active.off('mouseover mouseout').off('.redactor-dropdown'); 22273 this.dropdown.button = false; 22274 this.dropdown.key = false; 22275 this.dropdown.active = false; 22276 } 22277 }; 22278 }, 22279 22280 // =events 22281 events: function() 22282 { 22283 return { 22284 focused: false, 22285 blured: true, 22286 dropImage: false, 22287 stopChanges: false, 22288 stopDetectChanges: function() 22289 { 22290 this.events.stopChanges = true; 22291 }, 22292 startDetectChanges: function() 22293 { 22294 var self = this; 22295 setTimeout(function() 22296 { 22297 self.events.stopChanges = false;
22298 }, 1); 22299 }, 22300 dragover: function(e) 22301 { 22302 e.preventDefault(); 22303 e.stopPropagation(); 22304 22305 if (e.target.tagName === 'IMG') 22306 { 22307 $(e.target).addClass('redactor-image-dragover'); 22308 } 22309 22310 }, 22311 dragleave: function(e) 22312 { 22313 // remove image dragover 22314 this.core.editor().find('img').removeClass('redactor-image-dragover'); 22315 }, 22316 drop: function(e) 22317 { 22318 e = e.originalEvent || e; 22319 22320 // remove image dragover 22321 this.core.editor().find('img').removeClass('redactor-image-dragover'); 22322 22323 if (this.opts.type === 'inline' || this.opts.type === 'pre') 22324 { 22325 e.preventDefault(); 22326 return false; 22327 } 22328 22329 if (window.FormData === undefined || !e.dataTransfer) 22330 { 22331 return true; 22332 } 22333 22334 if (e.dataTransfer.files.length === 0) 22335 { 22336 return this.events.onDrop(e); 22337 } 22338 else 22339 { 22340 this.events.onDropUpload(e); 22341 } 22342 22343 this.core.callback('drop', e); 22344 22345 }, 22346 click: function(e) 22347 { 22348 var event = this.core.getEvent(); 22349 var type = (event === 'click' || event === 'arrow') ? false : 'click'; 22350 22351 this.core.addEvent(type); 22352 this.utils.disableSelectAll(); 22353 this.core.callback('click', e); 22354 }, 22355 focus: function(e) 22356 { 22357 if (this.rtePaste) 22358 { 22359 return; 22360 } 22361 22362 if (this.events.isCallback('focus')) 22363 { 22364 this.core.callback('focus', e); 22365 } 22366 22367 this.events.focused = true; 22368 this.events.blured = false; 22369 22370 // tab 22371 if (this.selection.current() === false) 22372 { 22373 var sel = this.selection.get(); 22374 var range = this.selection.range(sel); 22375 22376 range.setStart(this.core.editor()[0], 0); 22377 range.setEnd(this.core.editor()[0], 0); 22378 this.selection.update(sel, range); 22379 } 22380 22381 }, 22382 blur: function(e) 22383 { 22384 if (this.start || this.rtePaste) 22385 { 22386 return; 22387 } 22388 22389 if ($(e.target).closest('#' + this.core.id() + ', .redactor-toolbar, .redactor-dropdown, #redactor-modal-box').length !== 0) 22390 { 22391 return; 22392 } 22393 22394 if (!this.events.blured && this.events.isCallback('blur')) 22395 { 22396 this.core.callback('blur', e); 22397 } 22398 22399 this.events.focused = false; 22400 this.events.blured = true; 22401 }, 22402 touchImageEditing: function() 22403 { 22404 var scrollTimer = -1; 22405 this.events.imageEditing = false; 22406 $(window).on('touchmove.redactor.' + this.uuid, $.proxy(function() 22407 { 22408 this.events.imageEditing = true; 22409 if (scrollTimer !== -1) 22410 { 22411 clearTimeout(scrollTimer); 22412 } 22413 22414 scrollTimer = setTimeout($.proxy(function() 22415 { 22416 this.events.imageEditing = false; 22417 22418 }, this), 500); 22419 22420 }, this)); 22421 }, 22422 init: function() 22423 { 22424 this.core.editor().on('dragover.redactor dragenter.redactor', $.proxy(this.events.dragover, this)); 22425 this.core.editor().on('dragleave.redactor', $.proxy(this.events.dragleave, this)); 22426 this.core.editor().on('drop.redactor', $.proxy(this.events.drop, this)); 22427 this.core.editor().on('click.redactor', $.proxy(this.events.click, this)); 22428 this.core.editor().on('paste.redactor', $.proxy(this.paste.init, this)); 22429 this.core.editor().on('keydown.redactor', $.proxy(this.keydown.init, this)); 22430 this.core.editor().on('keyup.redactor', $.proxy(this.keyup.init, this)); 22431 this.core.editor().on('focus.redactor', $.proxy(this.events.focus, this)); 22432 22433 $(document).on('mousedown.redactor-blur.' + this.uuid, $.proxy(this.events.blur, this)); 22434 22435 this.events.touchImageEditing(); 22436 22437 this.events.createObserver(); 22438 this.events.setupObserver(); 22439 22440 }, 22441 createObserver: function() 22442 { 22443 var self = this; 22444 this.events.observer = new MutationObserver(function(mutations) 22445 { 22446 mutations.forEach($.proxy(self.events.iterateObserver, self)); 22447 }); 22448 22449 }, 22450 iterateObserver: function(mutation) 22451 { 22452 22453 var stop = false; 22454 22455 // target 22456 if (((this.opts.type === 'textarea' || this.opts.type === 'div') 22457 && (!this.detect.isFirefox() && mutation.target === this.core.editor()[0])) 22458 || (mutation.attributeName === 'class' && mutation.target === this.core.editor()[0]) 22459 || (mutation.attributeName == 'data-vivaldi-spatnav-clickable') 22460 ) 22461 { 22462 stop = true; 22463 } 22464 22465 if (!stop) 22466 { 22467 this.observe.load(); 22468 this.events.changeHandler(); 22469 } 22470 }, 22471 setupObserver: function() 22472 { 22473 this.events.observer.observe(this.core.editor()[0], { 22474 attributes: true, 22475 subtree: true, 22476 childList: true, 22477 characterData: true, 22478 characterDataOldValue: true 22479 }); 22480 }, 22481 changeHandler: function() 22482 { 22483 if (this.events.stopChanges) 22484 { 22485 return; 22486 } 22487 22488 this.code.sync(); 22489 22490 // autosave 22491 if (this.autosave.is()) 22492 { 22493 22494 clearTimeout(this.autosaveTimeout); 22495 this.autosaveTimeout = setTimeout($.proxy(this.autosave.send, this), 300); 22496 } 22497 22498 }, 22499 onDropUpload: function(e) 22500 { 22501 e.preventDefault(); 22502 e.stopPropagation(); 22503 22504 if ((!this.opts.dragImageUpload && !this.opts.dragFileUpload) || (this.opts.imageUpload === null && this.opts.fileUpload === null)) 22505 { 22506 return; 22507 } 22508 22509 if (e.target.tagName === 'IMG') 22510 { 22511 this.events.dropImage = e.target; 22512 } 22513 22514 var files = e.dataTransfer.files; 22515 var len = files.length; 22516 for (var i = 0; i < len; i++) 22517 { 22518 this.upload.directUpload(files[i], e); 22519 } 22520 }, 22521 onDrop: function(e) 22522 { 22523 this.core.callback('drop', e); 22524 }, 22525 isCallback: function(name) 22526 { 22527 return (typeof this.opts.callbacks[name] !== 'undefined' && $.isFunction(this.opts.callbacks[name])); 22528 }, 22529 22530 // #backward 22531 stopDetect: function() 22532 { 22533 this.events.stopDetectChanges(); 22534 }, 22535 startDetect: function() 22536 { 22537 this.events.startDetectChanges(); 22538 } 22539 22540 }; 22541 }, 22542 22543 // =file 22544 file: function() 22545 { 22546 return { 22547 is: function() 22548 { 22549 return !(!this.opts.fileUpload || !this.opts.fileUpload && !this.opts.s3); 22550 }, 22551 show: function() 22552 { 22553 // build modal 22554 this.modal.load('file', this.lang.get('file'), 700); 22555 22556 // build upload 22557 this.upload.init('#redactor-modal-file-upload', this.opts.fileUpload, this.file.insert); 22558 22559 // set selected text 22560 $('#redactor-filename').val(this.selection.get().toString()); 22561 22562 // show 22563 this.modal.show(); 22564 }, 22565 insert: function(json, direct, e) 22566 { 22567 // error callback 22568 if (typeof json.error !== 'undefined') 22569 { 22570 this.modal.close(); 22571 this.core.callback('fileUploadError', json); 22572 return; 22573 } 22574 22575 this.file.release(e, direct); 22576 22577 // prepare 22578 this.buffer.set(); 22579 this.air.collapsed(); 22580 22581 // get 22582 var text = this.file.text(json); 22583 var $link = $('<a />').attr('href', json.url).text(text); 22584 var id = (typeof json.id === 'undefined') ? '' : json.id; 22585 var type = (typeof json.s3 === 'undefined') ? 'file' : 's3'; 22586 22587 // set id 22588 $link.attr('data-' + type, id); 22589 22590 // insert 22591 $link = $(this.insert.node($link)); 22592 22593 // focus 22594 this.caret.after($link); 22595 22596 // callback 22597 this.storage.add({ type: type, node: $link[0], url: json.url, id: id }); 22598 22599 if (direct !== null) 22600 { 22601 this.core.callback('fileUpload', $link, json); 22602 } 22603 22604 }, 22605 release: function(e, direct) 22606 { 22607 if (direct) 22608 { 22609 // drag and drop upload 22610 this.marker.remove(); 22611 this.insert.nodeToPoint(e, this.marker.get());
22612 this.selection.restore(); 22613 } 22614 else 22615 { 22616 // upload from modal 22617 this.modal.close(); 22618 } 22619 }, 22620 text: function(json) 22621 { 22622 var text = $('#redactor-filename').val(); 22623 22624 return (typeof text === 'undefined' || text === '') ? json.name : text; 22625 } 22626 }; 22627 }, 22628 22629 // =focus 22630 focus: function() 22631 { 22632 return { 22633 start: function() 22634 { 22635 this.core.editor().focus(); 22636 22637 if (this.opts.type === 'inline') 22638 { 22639 return; 22640 } 22641 22642 var $first = this.focus.first(); 22643 if ($first !== false) 22644 { 22645 this.caret.start($first); 22646 } 22647 }, 22648 end: function() 22649 { 22650 this.core.editor().focus(); 22651 22652 var last = (this.opts.inline) ? this.core.editor() : this.focus.last(); 22653 if (last.length === 0) 22654 { 22655 return; 22656 } 22657 22658 // get inline last node 22659 var lastNode = this.focus.lastChild(last); 22660 if (!this.detect.isWebkit() && lastNode !== false) 22661 { 22662 this.caret.end(lastNode); 22663 } 22664 else 22665 { 22666 var sel = this.selection.get(); 22667 var range = this.selection.range(sel); 22668 22669 if (range !== null) 22670 { 22671 range.selectNodeContents(last[0]); 22672 range.collapse(false); 22673 22674 this.selection.update(sel, range); 22675 } 22676 else 22677 { 22678 this.caret.end(last); 22679 } 22680 } 22681 22682 }, 22683 first: function() 22684 { 22685 var $first = this.core.editor().children().first(); 22686 if ($first.length === 0 && ($first[0].length === 0 || $first[0].tagName === 'BR' || $first[0].tagName === 'HR' || $first[0].nodeType === 3)) 22687 { 22688 return false; 22689 } 22690 22691 if ($first[0].tagName === 'UL' || $first[0].tagName === 'OL') 22692 { 22693 return $first.find('li').first(); 22694 } 22695 22696 return $first; 22697 22698 }, 22699 last: function() 22700 { 22701 return this.core.editor().children().last(); 22702 }, 22703 lastChild: function(last) 22704 { 22705 var lastNode = last[0].lastChild; 22706 22707 return (lastNode !== null && this.utils.isInlineTag(lastNode.tagName)) ? lastNode : false; 22708 }, 22709 is: function() 22710 { 22711 return (this.core.editor()[0] === document.activeElement); 22712 } 22713 }; 22714 }, 22715 22716 // =image 22717 image: function() 22718 { 22719 return { 22720 is: function() 22721 { 22722 return !(!this.opts.imageUpload || !this.opts.imageUpload && !this.opts.s3); 22723 }, 22724 show: function() 22725 { 22726 // build modal 22727 this.modal.load('image', this.lang.get('image'), 700); 22728 22729 // build upload 22730 this.upload.init('#redactor-modal-image-droparea', this.opts.imageUpload, this.image.insert); 22731 this.modal.show(); 22732 22733 }, 22734 insert: function(json, direct, e) 22735 { 22736 var $img; 22737 22738 // error callback 22739 if (typeof json.error !== 'undefined') 22740 { 22741 this.modal.close(); 22742 this.events.dropImage = false; 22743 this.core.callback('imageUploadError', json, e); 22744 return; 22745 } 22746 22747 // change image 22748 if (this.events.dropImage !== false) 22749 { 22750 $img = $(this.events.dropImage); 22751 22752 this.core.callback('imageDelete', $img[0].src, $img); 22753 22754 $img.attr('src', json.url); 22755 22756 this.events.dropImage = false; 22757 this.core.callback('imageUpload', $img, json); 22758 return; 22759 } 22760 22761 this.placeholder.hide(); 22762 var $figure = $('<' + this.opts.imageTag + '>'); 22763 22764 $img = $('<img>'); 22765 $img.attr('src', json.url); 22766 22767 // set id 22768 var id = (typeof json.id === 'undefined') ? '' : json.id; 22769 var type = (typeof json.s3 === 'undefined') ? 'image' : 's3'; 22770 $img.attr('data-' + type, id); 22771 22772 $figure.append($img); 22773 22774 var pre = this.utils.isTag(this.selection.current(), 'pre'); 22775 22776 if (direct) 22777 { 22778 this.air.collapsed(); 22779 this.marker.remove(); 22780 22781 var node = this.insert.nodeToPoint(e, this.marker.get()); 22782 var $next = $(node).next(); 22783 22784 this.selection.restore(); 22785 22786 // buffer 22787 this.buffer.set(); 22788 22789 // insert 22790 if (typeof $next !== 'undefined' && $next.length !== 0 && $next[0].tagName === 'IMG') 22791 { 22792 // delete callback 22793 this.core.callback('imageDelete', $next[0].src, $next); 22794 22795 // replace 22796 $next.closest('figure, p', this.core.editor()[0]).replaceWith($figure); 22797 this.caret.after($figure); 22798 } 22799 else 22800 { 22801 if (pre) 22802 { 22803 $(pre).after($figure); 22804 } 22805 else 22806 { 22807 this.insert.node($figure); 22808 } 22809 22810 this.caret.after($figure); 22811 } 22812 22813 } 22814 else 22815 { 22816 this.modal.close(); 22817 22818 // buffer 22819 this.buffer.set(); 22820 22821 // insert 22822 this.air.collapsed(); 22823 22824 if (pre) 22825 { 22826 $(pre).after($figure); 22827 } 22828 else 22829 { 22830 this.insert.node($figure); 22831 } 22832 22833 this.caret.after($figure); 22834 } 22835 22836 this.events.dropImage = false;
22837 this.storage.add({ type: type, node: $img[0], url: json.url, id: id }); 22838 22839 var nextNode = $img[0].nextSibling; 22840 var $nextFigure = $figure.next(); 22841 var isNextEmpty = $(nextNode).text().replace(/\u200B/g, ''); 22842 var isNextFigureEmpty = $nextFigure.text().replace(/\u200B/g, ''); 22843 22844 if (isNextEmpty === '') 22845 { 22846 $(nextNode).remove(); 22847 } 22848 22849 if ($nextFigure.length === 1 && $nextFigure[0].tagName === 'FIGURE' && isNextFigureEmpty === '') 22850 { 22851 $nextFigure.remove(); 22852 } 22853 22854 if (direct !== null) 22855 { 22856 this.core.callback('imageUpload', $img, json); 22857 } 22858 else 22859 { 22860 this.core.callback('imageInserted', $img, json); 22861 } 22862 }, 22863 setEditable: function($image) 22864 { 22865 $image.on('dragstart', function(e) 22866 { 22867 e.preventDefault(); 22868 }); 22869 22870 if (this.opts.imageResizable) 22871 { 22872 var handler = $.proxy(function(e) 22873 { 22874 this.observe.image = $image; 22875 this.image.resizer = this.image.loadEditableControls($image); 22876 22877 $(document).on('mousedown.redactor-image-resize-hide.' + this.uuid, $.proxy(this.image.hideResize, this)); 22878 22879 if (this.image.resizer) 22880 { 22881 this.image.resizer.on('mousedown.redactor touchstart.redactor', $.proxy(function(e) 22882 { 22883 this.image.setResizable(e, $image); 22884 }, this)); 22885 } 22886 22887 }, this); 22888 22889 $image.off('mousedown.redactor').on('mousedown.redactor', $.proxy(this.image.hideResize, this)); 22890 $image.off('click.redactor touchstart.redactor').on('click.redactor touchstart.redactor', handler); 22891 } 22892 else 22893 { 22894 $image.off('click.redactor touchstart.redactor').on('click.redactor touchstart.redactor', $.proxy(function(e) 22895 { 22896 setTimeout($.proxy(function() 22897 { 22898 this.image.showEdit($image); 22899 22900 }, this), 200); 22901 22902 }, this)); 22903 } 22904 22905 }, 22906 setResizable: function(e, $image) 22907 { 22908 e.preventDefault(); 22909 22910 this.image.resizeHandle = { 22911 x : e.pageX, 22912 y : e.pageY, 22913 el : $image, 22914 ratio: $image.width() / $image.height(), 22915 h: $image.height() 22916 }; 22917 22918 e = e.originalEvent || e; 22919 22920 if (e.targetTouches) 22921 { 22922 this.image.resizeHandle.x = e.targetTouches[0].pageX; 22923 this.image.resizeHandle.y = e.targetTouches[0].pageY; 22924 } 22925 22926 this.image.startResize(); 22927 }, 22928 startResize: function() 22929 { 22930 $(document).on('mousemove.redactor-image-resize touchmove.redactor-image-resize', $.proxy(this.image.moveResize, this)); 22931 $(document).on('mouseup.redactor-image-resize touchend.redactor-image-resize', $.proxy(this.image.stopResize, this)); 22932 }, 22933 moveResize: function(e) 22934 { 22935 e.preventDefault(); 22936 22937 e = e.originalEvent || e; 22938 22939 var height = this.image.resizeHandle.h; 22940 22941 if (e.targetTouches) height += (e.targetTouches[0].pageY - this.image.resizeHandle.y); 22942 else height += (e.pageY - this.image.resizeHandle.y); 22943 22944 var width = Math.round(height * this.image.resizeHandle.ratio); 22945 22946 if (height < 50 || width < 100) return; 22947 if (this.core.editor().width() <= width) return; 22948 22949 this.image.resizeHandle.el.attr({width: width, height: height}); 22950 this.image.resizeHandle.el.width(width); 22951 this.image.resizeHandle.el.height(height); 22952 22953 this.code.sync(); 22954 }, 22955 stopResize: function() 22956 { 22957 this.handle = false; 22958 $(document).off('.redactor-image-resize'); 22959 22960 this.image.hideResize(); 22961 }, 22962 hideResize: function(e) 22963 { 22964 if (e && $(e.target).closest('#redactor-image-box', this.$editor[0]).length !== 0) return; 22965 if (e && e.target.tagName == 'IMG') 22966 { 22967 var $image = $(e.target); 22968 } 22969 22970 var imageBox = this.$editor.find('#redactor-image-box'); 22971 if (imageBox.length === 0) return; 22972 22973 $('#redactor-image-editter').remove(); 22974 $('#redactor-image-resizer').remove(); 22975 22976 imageBox.find('img').css({ 22977 marginTop: imageBox[0].style.marginTop, 22978 marginBottom: imageBox[0].style.marginBottom, 22979 marginLeft: imageBox[0].style.marginLeft, 22980 marginRight: imageBox[0].style.marginRight 22981 }); 22982 22983 imageBox.css('margin', ''); 22984 imageBox.find('img').css('opacity', ''); 22985 imageBox.replaceWith(function() 22986 { 22987 return $(this).contents(); 22988 }); 22989 22990 $(document).off('mousedown.redactor-image-resize-hide.' + this.uuid); 22991 22992 if (typeof this.image.resizeHandle !== 'undefined') 22993 { 22994 this.image.resizeHandle.el.attr('rel', this.image.resizeHandle.el.attr('style')); 22995 } 22996 }, 22997 loadResizableControls: function($image, imageBox) 22998 { 22999 if (this.opts.imageResizable && !this.detect.isMobile()) 23000 { 23001 var imageResizer = $('<span id="redactor-image-resizer" data-redactor="verified"></span>'); 23002 23003 if (!this.detect.isDesktop()) 23004 { 23005 imageResizer.css({ width: '15px', height: '15px' }); 23006 } 23007 23008 imageResizer.attr('contenteditable', false); 23009 imageBox.append(imageResizer); 23010 imageBox.append($image); 23011 23012 return imageResizer; 23013 } 23014 else 23015 { 23016 imageBox.append($image); 23017 return false;
23018 } 23019 }, 23020 loadEditableControls: function($image) 23021 { 23022 if ($('#redactor-image-box').length !== 0) 23023 { 23024 return; 23025 } 23026 23027 var imageBox = $('<span id="redactor-image-box" data-redactor="verified">'); 23028 imageBox.css('float', $image.css('float')).attr('contenteditable', false); 23029 23030 if ($image[0].style.margin != 'auto') 23031 { 23032 imageBox.css({ 23033 marginTop: $image[0].style.marginTop, 23034 marginBottom: $image[0].style.marginBottom, 23035 marginLeft: $image[0].style.marginLeft, 23036 marginRight: $image[0].style.marginRight 23037 }); 23038 23039 $image.css('margin', ''); 23040 } 23041 else 23042 { 23043 imageBox.css({ 'display': 'block', 'margin': 'auto' }); 23044 } 23045 23046 $image.css('opacity', '.5').after(imageBox); 23047 23048 23049 if (this.opts.imageEditable) 23050 { 23051 // editter 23052 this.image.editter = $('<span id="redactor-image-editter" data-redactor="verified">' + this.lang.get('edit') + '</span>'); 23053 this.image.editter.attr('contenteditable', false); 23054 this.image.editter.on('click', $.proxy(function() 23055 { 23056 this.image.showEdit($image); 23057 }, this)); 23058 23059 imageBox.append(this.image.editter); 23060 23061 // position correction 23062 var editerWidth = this.image.editter.innerWidth(); 23063 this.image.editter.css('margin-left', '-' + editerWidth/2 + 'px'); 23064 } 23065 23066 return this.image.loadResizableControls($image, imageBox); 23067 23068 }, 23069 showEdit: function($image) 23070 { 23071 if (this.events.imageEditing) 23072 { 23073 return; 23074 } 23075 23076 this.observe.image = $image; 23077 23078 var $link = $image.closest('a', this.$editor[0]); 23079 var $figure = $image.closest('figure', this.$editor[0]); 23080 var $container = ($figure.length !== 0) ? $figure : $image; 23081 23082 this.modal.load('image-edit', this.lang.get('edit'), 705); 23083 23084 this.image.buttonDelete = this.modal.getDeleteButton().text(this.lang.get('delete')); 23085 this.image.buttonSave = this.modal.getActionButton().text(this.lang.get('save')); 23086 23087 this.image.buttonDelete.on('click', $.proxy(this.image.remove, this)); 23088 this.image.buttonSave.on('click', $.proxy(this.image.update, this)); 23089 23090 if (this.opts.imageCaption === false) 23091 { 23092 $('#redactor-image-caption').val('').hide().prev().hide(); 23093 } 23094 else 23095 { 23096 var $parent = $image.closest(this.opts.imageTag, this.$editor[0]); 23097 var $ficaption = $parent.find('figcaption'); 23098 if ($ficaption !== 0) 23099 { 23100 23101 $('#redactor-image-caption').val($ficaption.text()).show(); 23102 } 23103 } 23104 23105 if (!this.opts.imagePosition) 23106 { 23107 $('.redactor-image-position-option').hide(); 23108 } 23109 else 23110 { 23111 var isCentered = ($figure.length !== 0) ? ($container.css('text-align') === 'center') : ($container.css('display') == 'block' && $container.css('float') == 'none'); 23112 var floatValue = (isCentered) ? 'center' : $container.css('float'); 23113 $('#redactor-image-align').val(floatValue); 23114 } 23115 23116 $('#redactor-image-preview').html($('<img src="' + $image.attr('src') + '" style="max-width: 100%;">')); 23117 $('#redactor-image-title').val($image.attr('alt')); 23118 23119 if ($link.length !== 0) 23120 { 23121 $('#redactor-image-link').val($link.attr('href')); 23122 if ($link.attr('target') === '_blank') 23123 { 23124 $('#redactor-image-link-blank').prop('checked', true); 23125 } 23126 } 23127 23128 // hide link's tooltip 23129 $('.redactor-link-tooltip').remove(); 23130 23131 this.modal.show(); 23132 23133 // focus 23134 if (this.detect.isDesktop()) 23135 { 23136 $('#redactor-image-title').focus(); 23137 } 23138 23139 }, 23140 update: function() 23141 { 23142 var $image = this.observe.image; 23143 var $link = $image.closest('a', this.core.editor()[0]); 23144 23145 var title = $('#redactor-image-title').val().replace(/(<([^>]+)>)/ig,""); 23146 $image.attr('alt', title).attr('title', title); 23147 23148 this.image.setFloating($image); 23149 23150 // as link 23151 var link = $.trim($('#redactor-image-link').val()).replace(/(<([^>]+)>)/ig,""); 23152 if (link !== '') 23153 { 23154 // test url (add protocol) 23155 var pattern = '((xn--)?[a-z0-9]+(-[a-z0-9]+)*\\.)+[a-z]{2,}'; 23156 var re = new RegExp('^(http|ftp|https)://' + pattern, 'i'); 23157 var re2 = new RegExp('^' + pattern, 'i'); 23158 23159 if (link.search(re) === -1 && link.search(re2) === 0 && this.opts.linkProtocol) 23160 { 23161 link = this.opts.linkProtocol + '://' + link; 23162 } 23163 23164 var target = ($('#redactor-image-link-blank').prop('checked')) ? true : false;
23165 23166 if ($link.length === 0) 23167 { 23168 var a = $('<a href="' + link + '" id="redactor-img-tmp">' + this.utils.getOuterHtml($image) + '</a>'); 23169 if (target) 23170 { 23171 a.attr('target', '_blank'); 23172 } 23173 23174 $image = $image.replaceWith(a); 23175 $link = this.core.editor().find('#redactor-img-tmp'); 23176 $link.removeAttr('id'); 23177 } 23178 else 23179 { 23180 $link.attr('href', link); 23181 if (target) 23182 { 23183 $link.attr('target', '_blank'); 23184 } 23185 else 23186 { 23187 $link.removeAttr('target'); 23188 } 23189 } 23190 } 23191 else if ($link.length !== 0) 23192 { 23193 $link.replaceWith(this.utils.getOuterHtml($image)); 23194 } 23195 23196 this.image.addCaption($image, $link); 23197 this.modal.close(); 23198 23199 // buffer 23200 this.buffer.set(); 23201 23202 }, 23203 setFloating: function($image) 23204 { 23205 var $figure = $image.closest('figure', this.$editor[0]); 23206 var $container = ($figure.length !== 0) ? $figure : $image; 23207 var floating = $('#redactor-image-align').val(); 23208 23209 var imageFloat = ''; 23210 var imageDisplay = ''; 23211 var imageMargin = ''; 23212 var textAlign = ''; 23213 23214 switch (floating) 23215 { 23216 case 'left': 23217 imageFloat = 'left'; 23218 imageMargin = '0 ' + this.opts.imageFloatMargin + ' ' + this.opts.imageFloatMargin + ' 0'; 23219 break; 23220 case 'right': 23221 imageFloat = 'right'; 23222 imageMargin = '0 0 ' + this.opts.imageFloatMargin + ' ' + this.opts.imageFloatMargin; 23223 break; 23224 case 'center': 23225 23226 if ($figure.length !== 0) 23227 { 23228 textAlign = 'center'; 23229 } 23230 else 23231 { 23232 imageDisplay = 'block'; 23233 imageMargin = 'auto'; 23234 } 23235 23236 break; 23237 } 23238 23239 $container.css({ 'float': imageFloat, 'display': imageDisplay, 'margin': imageMargin, 'text-align': textAlign }); 23240 $container.attr('rel', $image.attr('style')); 23241 }, 23242 addCaption: function($image, $link) 23243 { 23244 var caption = $('#redactor-image-caption').val(); 23245 23246 var $target = ($link.length !== 0) ? $link : $image; 23247 var $figcaption = $target.next(); 23248 23249 if ($figcaption.length === 0 || $figcaption[0].tagName !== 'FIGCAPTION') 23250 { 23251 $figcaption = false; 23252 } 23253 23254 if (caption !== '') 23255 { 23256 if ($figcaption === false) 23257 { 23258 $figcaption = $('<figcaption />').text(caption); 23259 $target.after($figcaption); 23260 } 23261 else 23262 { 23263 $figcaption.text(caption); 23264 } 23265 } 23266 else if ($figcaption !== false) 23267 { 23268 $figcaption.remove(); 23269 } 23270 }, 23271 remove: function(e, $image, index) 23272 { 23273 $image = (typeof $image === 'undefined') ? $(this.observe.image) : $image; 23274 23275 // delete from modal 23276 if (typeof e !== 'boolean') 23277 { 23278 this.buffer.set(); 23279 } 23280 23281 this.events.stopDetectChanges(); 23282 23283 var $link = $image.closest('a', this.core.editor()[0]); 23284 var $figure = $image.closest(this.opts.imageTag, this.core.editor()[0]); 23285 var $parent = $image.parent(); 23286 23287 // callback 23288 var imageDeleteStop = this.core.callback('imageDelete', e, $image[0]); 23289 if (imageDeleteStop === false) 23290 { 23291 if (e) e.preventDefault(); 23292 return false; 23293 } 23294 23295 if ($('#redactor-image-box').length !== 0) 23296 { 23297 $parent = $('#redactor-image-box').parent(); 23298 } 23299 23300 var $next, $prev; 23301 if ($figure.length !== 0) 23302 { 23303 $prev = $figure.prev(); 23304 $next = $figure.next(); 23305 $figure.remove(); 23306 } 23307 else if ($link.length !== 0) 23308 { 23309 $parent = $link.parent(); 23310 $link.remove(); 23311 } 23312 else 23313 { 23314 $image.remove(); 23315 } 23316 23317 $('#redactor-image-box').remove(); 23318 23319 if (e !== false) 23320 { 23321 if ($next && $next.length !== 0) 23322 { 23323 this.caret.start($next); 23324 } 23325 else if ($prev && $prev.length !== 0) 23326 { 23327 this.caret.end($prev); 23328 } 23329 } 23330 23331 if (typeof e !== 'boolean') 23332 { 23333 this.modal.close(); 23334 } 23335 23336 this.utils.restoreScroll(); 23337 this.observe.image = false;
23338 this.events.startDetectChanges(); 23339 this.placeholder.enable(); 23340 this.code.sync(); 23341 23342 } 23343 }; 23344 }, 23345 23346 // =indent 23347 indent: function() 23348 { 23349 return { 23350 increase: function() 23351 { 23352 if (!this.list.get()) 23353 { 23354 return; 23355 } 23356 23357 var $current = $(this.selection.current()).closest('li'); 23358 var $list = $current.closest('ul, ol', this.core.editor()[0]); 23359 23360 var $li = $current.closest('li'); 23361 var $prev = $li.prev(); 23362 if ($prev.length === 0 || $prev[0].tagName !== 'LI') 23363 { 23364 return; 23365 } 23366 23367 this.buffer.set(); 23368 23369 23370 if (this.utils.isCollapsed()) 23371 { 23372 var listTag = $list[0].tagName; 23373 var $newList = $('<' + listTag + ' />'); 23374 23375 this.selection.save(); 23376 23377 var $ol = $prev.find('ol').first(); 23378 if ($ol.length === 1) 23379 { 23380 $ol.append($current); 23381 } 23382 else 23383 { 23384 var listTag = $list[0].tagName; 23385 var $newList = $('<' + listTag + ' />'); 23386 $newList.append($current); 23387 $prev.append($newList); 23388 } 23389 23390 this.selection.restore(); 23391 } 23392 else 23393 { 23394 document.execCommand('indent'); 23395 23396 // normalize 23397 this.selection.save(); 23398 this.indent.removeEmpty(); 23399 this.indent.normalize(); 23400 this.selection.restore(); 23401 } 23402 }, 23403 decrease: function() 23404 { 23405 if (!this.list.get()) 23406 { 23407 return; 23408 } 23409 23410 var $current = $(this.selection.current()).closest('li'); 23411 var $list = $current.closest('ul, ol', this.core.editor()[0]); 23412 23413 this.buffer.set(); 23414 23415 document.execCommand('outdent'); 23416 23417 var $item = $(this.selection.current()).closest('li', this.core.editor()[0]); 23418 23419 if (this.utils.isCollapsed()) 23420 { 23421 this.indent.repositionItem($item); 23422 } 23423 23424 if ($item.length === 0) 23425 { 23426 document.execCommand('formatblock', false, 'p'); 23427 $item = $(this.selection.current()); 23428 var $next = $item.next(); 23429 if ($next.length !== 0 && $next[0].tagName === 'BR') 23430 { 23431 $next.remove(); 23432 } 23433 } 23434 23435 // normalize 23436 this.selection.save(); 23437 this.indent.removeEmpty(); 23438 this.indent.normalize(); 23439 this.selection.restore(); 23440 23441 }, 23442 repositionItem: function($item) 23443 { 23444 var $next = $item.next(); 23445 if ($next.length !== 0 && ($next[0].tagName !== 'UL' || $next[0].tagName !== 'OL')) 23446 { 23447 $item.append($next); 23448 } 23449 23450 var $prev = $item.prev(); 23451 if ($prev.length !== 0 && $prev[0].tagName !== 'LI') 23452 { 23453 this.selection.save(); 23454 var $li = $item.parents('li', this.core.editor()[0]); 23455 $li.after($item); 23456 this.selection.restore(); 23457 } 23458 }, 23459 normalize: function() 23460 { 23461 this.core.editor().find('li').each($.proxy(function(i,s) 23462 { 23463 var $el = $(s); 23464 23465 // remove style 23466 var filter = ''; 23467 if (this.opts.keepStyleAttr.length !== 0) 23468 { 23469 filter = ',' + this.opts.keepStyleAttr.join(','); 23470 } 23471 23472 $el.find(this.opts.inlineTags.join(',')).not('img' + filter).removeAttr('style'); 23473 23474 var $parent = $el.parent(); 23475 if ($parent.length !== 0 && $parent[0].tagName === 'LI') 23476 { 23477 $parent.after($el); 23478 return; 23479 } 23480 23481 var $next = $el.next(); 23482 if ($next.length !== 0 && ($next[0].tagName === 'UL' || $next[0].tagName === 'OL')) 23483 { 23484 $el.append($next); 23485 } 23486 23487 }, this)); 23488 23489 }, 23490 removeEmpty: function($list) 23491 { 23492 var $lists = this.core.editor().find('ul, ol'); 23493 var $items = this.core.editor().find('li'); 23494 23495 $items.each($.proxy(function(i, s) 23496 { 23497 this.indent.removeItemEmpty(s); 23498 23499 }, this)); 23500 23501 $lists.each($.proxy(function(i, s) 23502 { 23503 this.indent.removeItemEmpty(s); 23504 23505 }, this)); 23506 23507 $items.each($.proxy(function(i, s) 23508 { 23509 this.indent.removeItemEmpty(s); 23510 23511 }, this)); 23512 }, 23513 removeItemEmpty: function(s) 23514 { 23515 var html = s.innerHTML.replace(/[\t\s\n]/g, ''); 23516 html = html.replace(/<span><\/span>/g, ''); 23517 23518 if (html === '') 23519 { 23520 $(s).remove(); 23521 } 23522 } 23523 }; 23524 }, 23525 23526 // =inline 23527 inline: function() 23528 { 23529 return { 23530 format: function(tag, attr, value, type) 23531 { 23532 // Stop formatting pre/code 23533 if (this.utils.isCurrentOrParent(['PRE', 'CODE'])) return; 23534 23535 // Get params 23536 var params = this.inline.getParams(attr, value, type); 23537 23538 // Arrange tag 23539 tag = this.inline.arrangeTag(tag); 23540 23541 this.placeholder.hide(); 23542 this.buffer.set(); 23543 23544 (this.utils.isCollapsed()) ? this.inline.formatCollapsed(tag, params) : this.inline.formatUncollapsed(tag, params); 23545 }, 23546 formatCollapsed: function(tag, params) 23547 { 23548 var newInline; 23549 var inline = this.selection.inline(); 23550 23551 if (inline) 23552 { 23553 var currentTag = inline.tagName.toLowerCase(); 23554 if (currentTag === tag) 23555 { 23556 // empty = remove 23557 if (this.utils.isEmpty(inline.innerHTML)) 23558 { 23559 this.caret.after(inline); 23560 $(inline).remove(); 23561 } 23562 // not empty = break 23563 else 23564 {
23565 var $first = this.inline.insertBreakpoint(inline, currentTag); 23566 this.caret.after($first); 23567 } 23568 } 23569 else if ($(inline).closest(tag).length === 0) 23570 { 23571 newInline = this.inline.insertInline(tag); 23572 newInline = this.inline.setParams(newInline, params); 23573 } 23574 else 23575 { 23576 var $first = this.inline.insertBreakpoint(inline, currentTag); 23577 this.caret.after($first); 23578 } 23579 } 23580 else 23581 { 23582 newInline = this.inline.insertInline(tag); 23583 newInline = this.inline.setParams(newInline, params); 23584 } 23585 }, 23586 formatUncollapsed: function(tag, params) 23587 { 23588 this.selection.save(); 23589 23590 var nodes = this.inline.getClearedNodes(); 23591 this.inline.setNodesStriked(nodes, tag, params); 23592 23593 this.selection.restore(); 23594 23595 document.execCommand('strikethrough'); 23596 23597 this.selection.saveInstant(); 23598 23599 var self = this; 23600 this.core.editor().find('strike').each(function() 23601 { 23602 var $el = self.utils.replaceToTag(this, tag); 23603 self.inline.setParams($el[0], params); 23604 23605 var $inside = $el.find(tag); 23606 var $parent = $el.parent(); 23607 var $parentAround = $parent.parent(); 23608 23609 // revert formatting (safari bug) 23610 if ($parentAround.length !== 0 && $parentAround[0].tagName.toLowerCase() === tag && $parentAround.html() == $parent[0].outerHTML) 23611 { 23612 $el.replaceWith(function() { return $(this).contents(); }); 23613 $parentAround.replaceWith(function() { return $(this).contents(); }); 23614 23615 return; 23616 } 23617 23618 // remove inside 23619 if ($inside.length !== 0) self.inline.cleanInsideOrParent($inside, params); 23620 23621 // same parent 23622 if ($parent.html() == $el[0].outerHTML) self.inline.cleanInsideOrParent($parent, params); 23623 23624 // bugfix: remove empty inline tags after selection 23625 if (self.detect.isFirefox()) 23626 { 23627 self.core.editor().find(tag + ':empty').remove(); 23628 } 23629 }); 23630 23631 this.selection.restoreInstant(); 23632 }, 23633 cleanInsideOrParent: function($el, params) 23634 { 23635 if (params) 23636 { 23637 for (var key in params.data) 23638 { 23639 this.inline.removeSpecificAttr($el, key, params.data[key]); 23640 } 23641 } 23642 }, 23643 getClearedNodes: function() 23644 { 23645 var nodes = this.selection.nodes(); 23646 var newNodes = []; 23647 var len = nodes.length; 23648 var started = 0; 23649 23650 // find array slice 23651 for (var i = 0; i < len; i++) 23652 { 23653 if ($(nodes[i]).hasClass('redactor-selection-marker')) 23654 { 23655 started = i + 2; 23656 break; 23657 } 23658 } 23659 23660 // find selected inline & text nodes 23661 for (var i = 0; i < len; i++) 23662 { 23663 if (i >= started && !this.utils.isBlockTag(nodes[i].tagName)) 23664 { 23665 newNodes.push(nodes[i]); 23666 } 23667 } 23668 23669 return newNodes; 23670 }, 23671 isConvertableAttr: function(node, name, value) 23672 { 23673 var nodeAttrValue = $(node).attr(name); 23674 if (nodeAttrValue) 23675 { 23676 if (name === 'style') 23677 { 23678 value = $.trim(value).replace(/;$/, '') 23679 23680 var rules = value.split(';'); 23681 var count = 0; 23682 for (var i = 0; i < rules.length; i++) 23683 { 23684 var arr = rules[i].split(':'); 23685 var ruleName = $.trim(arr[0]); 23686 var ruleValue = $.trim(arr[1]); 23687 23688 if (ruleName.search(/color/) !== -1) 23689 { 23690 var val = $(node).css(ruleName); 23691 if (val && (val === ruleValue || this.utils.rgb2hex(val) === ruleValue)) 23692 { 23693 count++; 23694 } 23695 } 23696 else if ($(node).css(ruleName) === ruleValue) 23697 { 23698 count++; 23699 } 23700 } 23701 23702 if (count === rules.length) 23703 { 23704 return 1; 23705 } 23706 } 23707 else if (nodeAttrValue === value) 23708 { 23709 return 1; 23710 } 23711 } 23712 23713 return 0; 23714 23715 }, 23716 isConvertable: function(node, nodeTag, tag, params) 23717 { 23718 if (nodeTag === tag) 23719 { 23720 if (params) 23721 { 23722 var count = 0; 23723 for (var key in params.data) 23724 { 23725 count += this.inline.isConvertableAttr(node, key, params.data[key]); 23726 } 23727 23728 if (count === Object.keys(params.data).length) 23729 { 23730 return true; 23731 } 23732 } 23733 else 23734 { 23735 return true; 23736 } 23737 } 23738 23739 return false;
23740 }, 23741 setNodesStriked: function(nodes, tag, params) 23742 { 23743 for (var i = 0; i < nodes.length; i++) 23744 { 23745 var nodeTag = (nodes[i].tagName) ? nodes[i].tagName.toLowerCase() : undefined; 23746 23747 var parent = nodes[i].parentNode; 23748 var parentTag = (parent && parent.tagName) ? parent.tagName.toLowerCase() : undefined; 23749 23750 var convertable = this.inline.isConvertable(parent, parentTag, tag, params); 23751 if (convertable) 23752 { 23753 var $el = $(parent).replaceWith(function() 23754 { 23755 return $('<strike>').append($(this).contents()); 23756 }); 23757 23758 $el.attr('data-redactor-inline-converted'); 23759 } 23760 23761 var convertable = this.inline.isConvertable(nodes[i], nodeTag, tag, params); 23762 if (convertable) 23763 { 23764 var $el = $(nodes[i]).replaceWith(function() 23765 { 23766 return $('<strike>').append($(this).contents()); 23767 }); 23768 } 23769 } 23770 }, 23771 insertBreakpoint: function(inline, currentTag) 23772 { 23773 var breakpoint = document.createElement('span'); 23774 breakpoint.id = 'redactor-inline-breakpoint'; 23775 breakpoint = this.insert.node(breakpoint); 23776 23777 var end = this.utils.isEndOfElement(inline); 23778 var code = this.utils.getOuterHtml(inline); 23779 var endTag = (end) ? '' : '<' + currentTag + '>'; 23780 23781 code = code.replace(/<span id="redactor-inline-breakpoint"><\/span>/i, "</" + currentTag + ">" + endTag); 23782 23783 var $code = $(code); 23784 $(inline).replaceWith($code); 23785 23786 if (endTag !== '') 23787 { 23788 this.utils.cloneAttributes(inline, $code.last()); 23789 } 23790 23791 return $code.first(); 23792 }, 23793 insertInline: function(tag) 23794 { 23795 var node = document.createElement(tag); 23796 23797 this.insert.node(node); 23798 this.caret.start(node); 23799 23800 return node; 23801 }, 23802 arrangeTag: function(tag) 23803 { 23804 var tags = ['b', 'bold', 'i', 'italic', 'underline', 'strikethrough', 'deleted', 'superscript', 'subscript']; 23805 var replaced = ['strong', 'strong', 'em', 'em', 'u', 'del', 'del', 'sup', 'sub']; 23806 23807 tag = tag.toLowerCase(); 23808 23809 for (var i = 0; i < tags.length; i++) 23810 { 23811 if (tag === tags[i]) 23812 { 23813 tag = replaced[i]; 23814 } 23815 } 23816 23817 return tag; 23818 }, 23819 getStyleParams: function(params) 23820 { 23821 var result = {}; 23822 var rules = params.trim().replace(/;$/, '').split(';'); 23823 for (var i = 0; i < rules.length; i++) 23824 { 23825 var rule = rules[i].split(':'); 23826 if (rule) 23827 { 23828 result[rule[0].trim()] = rule[1].trim(); 23829 } 23830 } 23831 23832 return result; 23833 }, 23834 getParams: function(attr, value, type) 23835 { 23836 var data = false; 23837 var func = 'toggle'; 23838 if (typeof attr === 'object') 23839 { 23840 data = attr; 23841 func = (value !== undefined) ? value : func; 23842 } 23843 else if (attr !== undefined && value !== undefined) 23844 { 23845 data = {}; 23846 data[attr] = value; 23847 func = (type !== undefined) ? type : func; 23848 } 23849 23850 return (data) ? { 'func': func, 'data': data } : false; 23851 }, 23852 setParams: function(node, params) 23853 { 23854 if (params) 23855 { 23856 for (var key in params.data) 23857 { 23858 var $node = $(node); 23859 if (key === 'style') 23860 { 23861 node = this.inline[params.func + 'Style'](params.data[key], node); 23862 $node.attr('data-redactor-style-cache', $node.attr('style')); 23863 } 23864 else if (key === 'class') 23865 { 23866 node = this.inline[params.func + 'Class'](params.data[key], node); 23867 } 23868 // attr 23869 else 23870 { 23871 node = (params.func === 'remove') ? this.inline[params.func + 'Attr'](key, node) : this.inline[params.func + 'Attr'](key, params.data[key], node); 23872 } 23873 23874 if (key === 'style' && node.tagName === 'SPAN') 23875 { 23876 $node.attr('data-redactor-span', true); 23877 } 23878 } 23879 } 23880 23881 return node; 23882 }, 23883 23884 // Each 23885 eachInline: function(node, callback) 23886 { 23887 var lastNode; 23888 var nodes = (node === undefined) ? this.selection.inlines() : [
23888node]; 23889 if (nodes) 23890 { 23891 for (var i = 0; i < nodes.length; i++) 23892 { 23893 lastNode = callback(nodes[i])[0]; 23894 } 23895 } 23896 23897 return lastNode; 23898 }, 23899 23900 // Class 23901 replaceClass: function(value, node) 23902 { 23903 return this.inline.eachInline(node, function(el) 23904 { 23905 return $(el).removeAttr('class').addClass(value); 23906 }); 23907 }, 23908 toggleClass: function(value, node) 23909 { 23910 return this.inline.eachInline(node, function(el) 23911 { 23912 return $(el).toggleClass(value); 23913 }); 23914 }, 23915 addClass: function(value, node) 23916 { 23917 return this.inline.eachInline(node, function(el) 23918 { 23919 return $(el).addClass(value); 23920 }); 23921 }, 23922 removeClass: function(value, node) 23923 { 23924 return this.inline.eachInline(node, function(el) 23925 { 23926 return $(el).removeClass(value); 23927 }); 23928 }, 23929 removeAllClass: function(node) 23930 { 23931 return this.inline.eachInline(node, function(el) 23932 { 23933 return $(el).removeAttr('class'); 23934 }); 23935 }, 23936 23937 // Attr 23938 replaceAttr: function(name, value, node) 23939 { 23940 return this.inline.eachInline(node, function(el) 23941 { 23942 return $(el).removeAttr(name).attr(name. value); 23943 }); 23944 }, 23945 toggleAttr: function(name, value, node) 23946 { 23947 return this.inline.eachInline(node, function(el) 23948 { 23949 var attr = $(el).attr(name); 23950 23951 return (attr) ? $(el).removeAttr(name) : $(el).attr(name. value); 23952 }); 23953 }, 23954 addAttr: function(name, value, node) 23955 { 23956 return this.inline.eachInline(node, function(el) 23957 { 23958 return $(el).attr(name, value); 23959 }); 23960 }, 23961 removeAttr: function(name, node) 23962 { 23963 return this.inline.eachInline(node, function(el) 23964 { 23965 var $el = $(el); 23966 23967 $el.removeAttr(name); 23968 if (name === 'style') 23969 { 23970 $el.removeAttr('data-redactor-style-cache'); 23971 } 23972 23973 return $el; 23974 }); 23975 }, 23976 removeAllAttr: function(node) 23977 { 23978 return this.inline.eachInline(node, function(el) 23979 { 23980 var $el = $(el); 23981 var len = el.attributes.length; 23982 for (var z = 0; z < len; z++) 23983 { 23984 $el.removeAttr(el.attributes[z].name); 23985 } 23986 23987 return $el; 23988 }); 23989 }, 23990 removeSpecificAttr: function(node, key, value) 23991 { 23992 var $el = $(node); 23993 if (key === 'style') 23994 { 23995 var arr = value.split(':'); 23996 var name = arr[0].trim(); 23997 $el.css(name, ''); 23998 23999 if (this.utils.removeEmptyAttr(node, 'style')) 24000 { 24001 $el.removeAttr('data-redactor-style-cache'); 24002 } 24003 } 24004 else 24005 { 24006 $el.removeAttr(key)[0]; 24007 } 24008 }, 24009 24010 // Style 24011 hasParentStyle: function($el) 24012 { 24013 var $parent = $el.parent(); 24014 24015 return ($parent.length === 1 && $parent[0].tagName === $el[0].tagName && $parent.html() === $el[0].outerHTML) ? $parent : false; 24016 }, 24017 addParentStyle: function($el) 24018 { 24019 var $parent = this.inline.hasParentStyle($el); 24020 if ($parent) 24021 { 24022 var style = this.inline.getStyleParams($el.attr('style')); 24023 $parent.css(style); 24024 $parent.attr('data-redactor-style-cache', $parent.attr('style')); 24025 24026 $el.replaceWith(function() 24027 { 24028 return $(this).contents(); 24029 }); 24030 } 24031 else 24032 { 24033 $el.attr('data-redactor-style-cache', $el.attr('style')); 24034 } 24035 24036 return $el; 24037 }, 24038 replaceStyle: function(params, node) 24039 { 24040 params = this.inline.getStyleParams(params); 24041 24042 var self = this; 24043 return this.inline.eachInline(node, function(el) 24044 { 24045 var $el = $(el); 24046 $el.removeAttr('style').css(params); 24047 24048 var style = $el.attr('style'); 24049 if (style) $el.attr('style', style.replace(/"/g, '\'')); 24050 24051 $el = self.inline.addParentStyle($el); 24052 24053 return $el; 24054 }); 24055 }, 24056 toggleStyle: function(params, node) 24057 { 24058 params = this.inline.getStyleParams(params); 24059 24060 var self = this; 24061 return this.inline.eachInline(node, function(el) 24062 { 24063 var $el = $(el); 24064 24065 for (var key in params) 24066 { 24067 var newVal = params[key]; 24068 var oldVal = $el.css(key); 24069 24070 oldVal = (self.utils.isRgb(oldVal)) ? self.utils.rgb2hex(oldVal) : oldVal.replace(/"/g, '');
24071 newVal = (self.utils.isRgb(newVal)) ? self.utils.rgb2hex(newVal) : newVal.replace(/"/g, ''); 24072 24073 if (oldVal === newVal) 24074 { 24075 $el.css(key, ''); 24076 } 24077 else 24078 { 24079 $el.css(key, newVal); 24080 } 24081 } 24082 24083 var style = $el.attr('style'); 24084 if (style) $el.attr('style', style.replace(/"/g, '\'')); 24085 24086 if (!self.utils.removeEmptyAttr(el, 'style')) 24087 { 24088 $el = self.inline.addParentStyle($el); 24089 } 24090 else 24091 { 24092 $el.removeAttr('data-redactor-style-cache'); 24093 } 24094 24095 24096 return $el; 24097 }); 24098 }, 24099 addStyle: function(params, node) 24100 { 24101 params = this.inline.getStyleParams(params); 24102 24103 var self = this; 24104 return this.inline.eachInline(node, function(el) 24105 { 24106 var $el = $(el); 24107 24108 $el.css(params); 24109 24110 var style = $el.attr('style'); 24111 if (style) $el.attr('style', style.replace(/"/g, '\'')); 24112 24113 $el = self.inline.addParentStyle($el); 24114 24115 return $el; 24116 }); 24117 }, 24118 removeStyle: function(params, node) 24119 { 24120 params = this.inline.getStyleParams(params); 24121 24122 var self = this; 24123 return this.inline.eachInline(node, function(el) 24124 { 24125 var $el = $(el); 24126 24127 for (var key in params) 24128 { 24129 $el.css(key, ''); 24130 } 24131 24132 if (self.utils.removeEmptyAttr(el, 'style')) 24133 { 24134 $el.removeAttr('data-redactor-style-cache'); 24135 } 24136 else 24137 { 24138 $el.attr('data-redactor-style-cache', $el.attr('style')); 24139 } 24140 24141 return $el; 24142 }); 24143 }, 24144 removeAllStyle: function(node) 24145 { 24146 return this.inline.eachInline(node, function(el) 24147 { 24148 return $(el).removeAttr('style').removeAttr('data-redactor-style-cache'); 24149 }); 24150 }, 24151 removeStyleRule: function(name) 24152 { 24153 var parent = this.selection.parent(); 24154 var nodes = this.selection.inlines(); 24155 24156 this.buffer.set(); 24157 24158 if (parent && parent.tagName === 'SPAN') 24159 { 24160 this.inline.removeStyleRuleAttr($(parent), name); 24161 } 24162 24163 for (var i = 0; i < nodes.length; i++) 24164 { 24165 var el = nodes[i]; 24166 var $el = $(el); 24167 if ($.inArray(el.tagName.toLowerCase(), this.opts.inlineTags) != -1 && !$el.hasClass('redactor-selection-marker')) 24168 { 24169 this.inline.removeStyleRuleAttr($el, name); 24170 } 24171 } 24172 24173 }, 24174 removeStyleRuleAttr: function($el, name) 24175 { 24176 $el.css(name, ''); 24177 if (this.utils.removeEmptyAttr($el, 'style')) 24178 { 24179 $el.removeAttr('data-redactor-style-cache'); 24180 } 24181 else 24182 { 24183 $el.attr('data-redactor-style-cache', $el.attr('style')); 24184 } 24185 }, 24186 24187 // Update 24188 update: function(tag, attr, value, type) 24189 { 24190 tag = this.inline.arrangeTag(tag); 24191 24192 var params = this.inline.getParams(attr, value, type); 24193 var nodes = this.selection.inlines(); 24194 var result = []; 24195 24196 if (nodes) 24197 { 24198 for (var i = 0; i < nodes.length; i++) 24199 { 24200 var el = nodes[i]; 24201 if (tag === '*' || el.tagName.toLowerCase() === tag) 24202 { 24203 result.push(this.inline.setParams(el, params)); 24204 } 24205 } 24206 } 24207 24208 return result; 24209 }, 24210 24211 // All 24212 removeFormat: function() 24213 { 24214 this.selection.save(); 24215 24216 var nodes = this.inline.getClearedNodes(); 24217 for (var i = 0; i < nodes.length; i++) 24218 { 24219 if (nodes[i].nodeType === 1) 24220 { 24221 $(nodes[i]).replaceWith(function() 24222 { 24223 return $(this).contents(); 24224 }); 24225 } 24226 } 24227
24228 this.selection.restore(); 24229 } 24230 24231 }; 24232 }, 24233 24234 // =insert 24235 insert: function() 24236 { 24237 return { 24238 set: function(html) 24239 { 24240 this.placeholder.hide(); 24241 24242 this.code.set(html); 24243 this.focus.end(); 24244 24245 this.placeholder.enable(); 24246 }, 24247 html: function(html, data) 24248 { 24249 this.placeholder.hide(); 24250 this.core.editor().focus(); 24251 24252 var block = this.selection.block(); 24253 var inline = this.selection.inline(); 24254 24255 // clean 24256 if (typeof data === 'undefined') 24257 { 24258 data = this.clean.getCurrentType(html, true); 24259 html = this.clean.onPaste(html, data, true); 24260 } 24261 24262 html = $.parseHTML(html); 24263 24264 // end node 24265 var endNode = $(html).last(); 24266 24267 // delete selected content 24268 var sel = this.selection.get(); 24269 var range = this.selection.range(sel); 24270 range.deleteContents(); 24271 24272 this.selection.update(sel, range); 24273 24274 // insert list in list 24275 if (data.lists) 24276 { 24277 var $list = $(html); 24278 if ($list.length !== 0 && ($list[0].tagName === 'UL' || $list[0].tagName === 'OL')) 24279 { 24280 24281 this.insert.appendLists(block, $list); 24282 return; 24283 } 24284 } 24285 24286 if (data.blocks && block) 24287 { 24288 if (this.utils.isSelectAll()) 24289 { 24290 this.core.editor().html(html); 24291 this.focus.end(); 24292 } 24293 else 24294 { 24295 var breaked = this.utils.breakBlockTag(); 24296 if (breaked === false) 24297 { 24298 this.insert.placeHtml(html); 24299 } 24300 else 24301 { 24302 var $last = $(html).children().last(); 24303 $last.append(this.marker.get()); 24304 24305 if (breaked.type === 'start') 24306 { 24307 breaked.$block.before(html); 24308 } 24309 else 24310 { 24311 breaked.$block.after(html); 24312 } 24313 24314 this.selection.restore(); 24315 this.core.editor().find('p').each(function() 24316 { 24317 if ($.trim(this.innerHTML) === '') 24318 { 24319 $(this).remove(); 24320 } 24321 }); 24322 } 24323 } 24324 } 24325 else 24326 { 24327 if (inline) 24328 { 24329 // remove same tag inside 24330 var $div = $("<div/>").html(html); 24331 $div.find(inline.tagName.toLowerCase()).each(function() 24332 { 24333 $(this).contents().unwrap(); 24334 }); 24335 24336 html = $div.html(); 24337 html = $.parseHTML(html); 24338 24339 endNode = $(html).last(); 24340 24341 24342 } 24343 24344 if (this.utils.isSelectAll()) 24345 { 24346 var $node = $(this.opts.emptyHtml); 24347 this.core.editor().html('').append($node); 24348 $node.html(html); 24349 this.caret.end($node); 24350 } 24351 else 24352 { 24353 this.insert.placeHtml(html); 24354 } 24355 } 24356 24357 this.utils.disableSelectAll(); 24358 24359 if (data.pre) this.clean.cleanPre(); 24360 24361 this.caret.end(endNode); 24362 this.linkify.format(); 24363 }, 24364 text: function(text) 24365 { 24366 text = text.toString(); 24367 text = $.trim(text); 24368 24369 var tmp = document.createElement('div'); 24370 tmp.innerHTML = text; 24371 text = tmp.textContent || tmp.innerText; 24372 24373 if (typeof text === 'undefined') 24374 { 24375 return; 24376 } 24377 24378 this.placeholder.hide(); 24379 this.core.editor().focus(); 24380 24381 // blocks 24382 var blocks = this.selection.blocks(); 24383 24384 // nl to spaces 24385 text = text.replace(/\n/g, ' '); 24386 24387 // select all 24388 if (this.utils.isSelectAll()) 24389 { 24390 var $node = $(this.opts.emptyHtml); 24391 this.core.editor().html('').append($node); 24392 $node.html(text); 24393 this.caret.end($node); 24394 } 24395 else 24396 { 24397 // insert 24398 var sel = this.selection.get(); 24399 var node = document.createTextNode(text); 24400 24401 if (sel.getRangeAt && sel.rangeCount) 24402 { 24403 var range = sel.getRangeAt(0); 24404 range.deleteContents(); 24405 range.insertNode(node); 24406 range.setStartAfter(node); 24407 range.collapse(true); 24408 24409 this.selection.update(sel, range); 24410 } 24411 24412 // wrap node if selected two or more block tags 24413 if (blocks.length > 1) 24414 { 24415 $(node).wrap('<p>'); 24416 this.caret.after(node); 24417 } 24418 } 24419 24420 this.utils.disableSelectAll(); 24421 this.linkify.format(); 24422 this.clean.normalizeCurrentHeading(); 24423 24424 }, 24425 raw: function(html) 24426 { 24427 this.placeholder.hide(); 24428 this.core.editor().focus(); 24429 24430 var sel = this.selection.get(); 24431 24432 var range = this.selection.range(sel); 24433 range.deleteContents(); 24434 24435 var el = document.createElement("div"); 24436 el.innerHTML = html; 24437 24438 var frag = document.createDocumentFragment(), node, lastNode; 24439 while ((node = el.firstChild)) 24440 { 24441 lastNode = frag.appendChild(node); 24442 } 24443
24444 range.insertNode(frag); 24445 24446 if (lastNode) 24447 { 24448 range = range.cloneRange(); 24449 range.setStartAfter(lastNode); 24450 range.collapse(true); 24451 sel.removeAllRanges(); 24452 sel.addRange(range); 24453 } 24454 }, 24455 node: function(node, deleteContent) 24456 { 24457 this.placeholder.hide(); 24458 24459 if (typeof this.start !== 'undefined') 24460 { 24461 this.core.editor().focus(); 24462 } 24463 24464 node = node[0] || node; 24465 24466 var block = this.selection.block(); 24467 var gap = this.utils.isBlockTag(node.tagName); 24468 var result = true; 24469 24470 if (this.utils.isSelectAll()) 24471 { 24472 if (gap) 24473 { 24474 this.core.editor().html(node); 24475 } 24476 else 24477 { 24478 this.core.editor().html($('<p>').html(node)); 24479 } 24480 24481 this.code.sync(); 24482 } 24483 else if (gap && block) 24484 { 24485 var breaked = this.utils.breakBlockTag(); 24486 if (breaked === false) 24487 { 24488 this.insert.placeNode(node, deleteContent); 24489 } 24490 else 24491 { 24492 if (breaked.type === 'start') 24493 { 24494 breaked.$block.before(node); 24495 } 24496 else 24497 { 24498 breaked.$block.after(node); 24499 } 24500 24501 this.core.editor().find('p:empty').remove(); 24502 } 24503 } 24504 else 24505 { 24506 result = this.insert.placeNode(node, deleteContent); 24507 } 24508 24509 this.utils.disableSelectAll(); 24510 24511 if (result) 24512 { 24513 this.caret.end(node); 24514 } 24515 24516 return node; 24517 24518 }, 24519 appendLists: function(block, $list) 24520 { 24521 var $block = $(block); 24522 var last; 24523 var isEmpty = this.utils.isEmpty(block.innerHTML); 24524 24525 if (isEmpty || this.utils.isEndOfElement(block)) 24526 { 24527 last = $block; 24528 $list.find('li').each(function() 24529 { 24530 last.after(this); 24531 last = $(this); 24532 }); 24533 24534 if (isEmpty) 24535 { 24536 $block.remove(); 24537 } 24538 } 24539 else if (this.utils.isStartOfElement(block)) 24540 { 24541 $list.find('li').each(function() 24542 { 24543 $block.before(this); 24544 last = $(this); 24545 }); 24546 } 24547 else 24548 { 24549 var endOfNode = this.selection.extractEndOfNode(block); 24550 24551 $block.after($('<li>').append(endOfNode)); 24552 $block.append($list); 24553 last = $list; 24554 } 24555 24556 this.marker.remove(); 24557 24558 if (last) 24559 { 24560 this.caret.end(last); 24561 } 24562 24563 this.linkify.format(); 24564 }, 24565 placeHtml: function(html) 24566 { 24567 var marker = document.createElement('span'); 24568 marker.id = 'redactor-insert-marker'; 24569 marker = this.insert.node(marker); 24570 24571 $(marker).before(html); 24572 this.selection.restore(); 24573 this.caret.after(marker); 24574 $(marker).remove(); 24575 }, 24576 placeNode: function(node, deleteContent) 24577 { 24578 var sel = this.selection.get(); 24579 var range = this.selection.range(sel); 24580 if (range == null) 24581 { 24582 return false; 24583 } 24584 24585 if (deleteContent !== false) 24586 { 24587 range.deleteContents(); 24588 } 24589 24590 range.insertNode(node); 24591 range.collapse(false); 24592 24593 this.selection.update(sel, range); 24594 }, 24595 nodeToPoint: function(e, node) 24596 { 24597 this.placeholder.hide(); 24598 24599 node = node[0] || node; 24600 24601 if (this.utils.isEmpty()) 24602 { 24603 node = (this.utils.isBlock(node)) ? node : $('<p />').append(node); 24604 24605 this.core.editor().html(node); 24606 24607 return node; 24608 } 24609 24610 var range; 24611 var x = e.clientX, y = e.clientY; 24612 if (document.caretPositionFromPoint) 24613 { 24614 var pos = document.caretPositionFromPoint(x, y); 24615 var sel = document.getSelection(); 24616 range = sel.getRangeAt(0); 24617 range.setStart(pos.offsetNode, pos.offset); 24618 range.collapse(true); 24619 range.insertNode(node); 24620 } 24621 else if (document.caretRangeFromPoint) 24622 { 24623 range = document.caretRangeFromPoint(x, y); 24624 range.insertNode(node); 24625 } 24626 else if (typeof document.body.createTextRange !== "undefined") 24627 { 24628 range = document.body.createTextRange(); 24629 range.moveToPoint(x, y); 24630 var endRange = range.duplicate(); 24631 endRange.moveToPoint(x, y); 24632 range.setEndPoint("EndToEnd", endRange); 24633 range.select(); 24634 } 24635 24636 return node; 24637 24638 }, 24639 24640 // #backward 24641 nodeToCaretPositionFromPoint: function(e, node) 24642 { 24643 this.insert.nodeToPoint(e, node); 24644 }, 24645 marker: function() 24646 { 24647 this.marker.insert(); 24648 } 24649 }; 24650 }, 24651 24652 // =keydown 24653 keydown: function() 24654 { 24655 return { 24656 init: function(e) 24657 { 24658 if (this.rtePaste) 24659 { 24660 return; 24661 } 24662 24663 var key = e.which; 24664 var arrow = (key >= 37 && key <= 40); 24665 24666 this.keydown.ctrl = e.ctrlKey || e.metaKey; 24667 this.keydown.parent = this.selection.parent(); 24668 this.keydown.current = this.selection.current(); 24669 this.keydown.block = this.selection.block(); 24670 24671 // detect tags 24672 this.keydown.pre = this.utils.isTag(this.keydown.current, 'pre'); 24673 this.keydown.blockquote = this.utils.isTag(this.keydown.current, 'blockquote'); 24674 this.keydown.figcaption = this.utils.isTag(this.keydown.current, 'figcaption'); 24675 this.keydown.figure = this.utils.isTag(this.keydown.current, 'figure'); 24676 24677 // callback
24678 var keydownStop = this.core.callback('keydown', e); 24679 if (keydownStop === false) 24680 { 24681 e.preventDefault(); 24682 return false; 24683 } 24684 24685 // shortcuts setup 24686 this.shortcuts.init(e, key); 24687 24688 // buffer 24689 this.keydown.checkEvents(arrow, key); 24690 this.keydown.setupBuffer(e, key); 24691 24692 if (this.utils.isSelectAll() && ( key === this.keyCode.ENTER || key === this.keyCode.BACKSPACE || key === this.keyCode.DELETE)) 24693 { 24694 e.preventDefault(); 24695 24696 this.code.set(this.opts.emptyHtml); 24697 this.events.changeHandler(); 24698 return; 24699 } 24700 24701 this.keydown.addArrowsEvent(arrow); 24702 this.keydown.setupSelectAll(e, key); 24703 24704 // turn off enter key 24705 if (!this.opts.enterKey && key === this.keyCode.ENTER) 24706 { 24707 e.preventDefault(); 24708 24709 // remove selected 24710 var sel = this.selection.get(); 24711 var range = this.selection.range(sel); 24712 24713 if (!range.collapsed) 24714 { 24715 range.deleteContents(); 24716 } 24717 24718 return; 24719 } 24720 24721 // down 24722 if (this.opts.enterKey && key === this.keyCode.DOWN) 24723 { 24724 this.keydown.onArrowDown(); 24725 } 24726 24727 // up 24728 if (this.opts.enterKey && key === this.keyCode.UP) 24729 { 24730 this.keydown.onArrowUp(); 24731 } 24732 24733 24734 // replace to p before / after the table or into body 24735 if ((this.opts.type === 'textarea' || this.opts.type === 'div') && this.keydown.current && this.keydown.current.nodeType === 3 && $(this.keydown.parent).hasClass('redactor-in')) 24736 { 24737 this.keydown.wrapToParagraph(); 24738 } 24739 24740 // on Shift+Space or Ctrl+Space 24741 if (!this.keyup.lastShiftKey && key === this.keyCode.SPACE && (e.ctrlKey || e.shiftKey)) 24742 { 24743 e.preventDefault(); 24744 24745 return this.keydown.onShiftSpace(); 24746 } 24747 24748 // on Shift+Enter or Ctrl+Enter 24749 if (key === this.keyCode.ENTER && (e.ctrlKey || e.shiftKey)) 24750 { 24751 e.preventDefault(); 24752 24753 return this.keydown.onShiftEnter(e); 24754 } 24755 24756 // on enter 24757 if (key === this.keyCode.ENTER && !e.shiftKey && !e.ctrlKey && !e.metaKey) 24758 { 24759 return this.keydown.onEnter(e); 24760 } 24761 24762 // tab or cmd + [ 24763 if (key === this.keyCode.TAB || e.metaKey && key === 221 || e.metaKey && key === 219) 24764 { 24765 return this.keydown.onTab(e, key); 24766 } 24767 24768 // firefox bugfix 24769 if (this.detect.isFirefox() && key === this.keyCode.BACKSPACE && this.keydown.block && this.keydown.block.tagName === 'P' && this.utils.isStartOfElement(this.keydown.block)) 24770 { 24771 var $prev = $(this.keydown.block).prev(); 24772 if ($prev.length !== 0) 24773 { 24774 e.preventDefault(); 24775 24776 $prev.append(this.marker.get()); 24777 $prev.append($(this.keydown.block).html()); 24778 $(this.keydown.block).remove(); 24779 24780 this.selection.restore(); 24781 24782 return; 24783 } 24784 } 24785 24786 // backspace & delete 24787 if (key === this.keyCode.BACKSPACE || key === this.keyCode.DELETE) 24788 { 24789 if (this.observe.image && typeof this.observe.image !== 'undefined' && $('#redactor-image-box').length !== 0) 24790 { 24791 e.preventDefault(); 24792 24793 var $prev = this.observe.image.closest('figure, p').prev() 24794 this.image.remove(false); 24795 this.observe.image = false; 24796 24797 if ($prev && $prev.length !== 0) 24798 { 24799 this.caret.end($prev); 24800 } 24801 else 24802 { 24803 this.core.editor().focus(); 24804 } 24805 24806 return; 24807 } 24808 24809 this.keydown.onBackspaceAndDeleteBefore(); 24810 } 24811 24812 if (key === this.keyCode.DELETE) 24813 { 24814 var $next = $(this.keydown.block).next(); 24815 24816 // delete figure 24817 if (this.utils.isEndOfElement(this.keydown.block) && $next.length !== 0 && $next[0].tagName === 'FIGURE') 24818 { 24819 $next.remove(); 24820 return false; 24821 } 24822 24823 // append list (safari bug) 24824 var tagLi = (this.keydown.block && this.keydown.block.tagName === 'LI') ? this.keydown.block : false; 24825 if (tagLi) 24826 { 24827 var $list = $(this.keydown.block).parents('ul, ol').last(); 24828 var $nextList = $list.next(); 24829 24830 if (this.utils.isRedactorParent($list) && this.utils.isEndOfElement($list) && $nextList.length !== 0 24831 && ($nextList[0].tagName === 'UL' || $nextList[0].tagName === 'OL')) 24832 { 24833 e.preventDefault(); 24834 24835 $list.append($nextList.contents()); 24836 $nextList.remove(); 24837 24838 return false;
24839 } 24840 } 24841 24842 // append pre 24843 if (this.utils.isEndOfElement(this.keydown.block) && $next.length !== 0 && $next[0].tagName === 'PRE') 24844 { 24845 $(this.keydown.block).append($next.text()); 24846 $next.remove(); 24847 return false; 24848 } 24849 24850 } 24851 24852 // image delete 24853 if (key === this.keyCode.DELETE && $('#redactor-image-box').length !== 0) 24854 { 24855 this.image.remove(); 24856 } 24857 24858 // backspace 24859 if (key === this.keyCode.BACKSPACE) 24860 { 24861 if (this.detect.isFirefox()) 24862 { 24863 this.line.removeOnBackspace(e); 24864 } 24865 24866 // combine list after and before if paragraph is empty 24867 if (this.list.combineAfterAndBefore(this.keydown.block)) 24868 { 24869 e.preventDefault(); 24870 return; 24871 } 24872 24873 // backspace as outdent 24874 var block = this.selection.block(); 24875 if (block && block.tagName === 'LI' && this.utils.isCollapsed() && this.utils.isStartOfElement()) 24876 { 24877 this.indent.decrease(); 24878 e.preventDefault(); 24879 return; 24880 } 24881 24882 this.keydown.removeInvisibleSpace(); 24883 this.keydown.removeEmptyListInTable(e); 24884 24885 } 24886 24887 if (key === this.keyCode.BACKSPACE || key === this.keyCode.DELETE) 24888 { 24889 this.keydown.onBackspaceAndDeleteAfter(e); 24890 } 24891 24892 }, 24893 onShiftSpace: function() 24894 { 24895 this.buffer.set(); 24896 this.insert.raw(' '); 24897 24898 return false; 24899 }, 24900 onShiftEnter: function(e) 24901 { 24902 this.buffer.set(); 24903 24904 return (this.keydown.pre) ? this.keydown.insertNewLine(e) : this.insert.raw('<br>'); 24905 }, 24906 onBackspaceAndDeleteBefore: function() 24907 { 24908 this.utils.saveScroll(); 24909 }, 24910 onBackspaceAndDeleteAfter: function(e) 24911 { 24912 // remove style tag 24913 setTimeout($.proxy(function() 24914 { 24915 this.code.syncFire = false; 24916 this.keydown.removeEmptyLists(); 24917 24918 var filter = ''; 24919 if (this.opts.keepStyleAttr.length !== 0) 24920 { 24921 filter = ',' + this.opts.keepStyleAttr.join(','); 24922 } 24923 24924 var $styleTags = this.core.editor().find('*[style]'); 24925 $styleTags.not('img, figure, iframe, #redactor-image-box, #redactor-image-editter, [data-redactor-style-cache], [data-redactor-span]' + filter).removeAttr('style'); 24926 24927 this.keydown.formatEmpty(e); 24928 this.code.syncFire = true; 24929 24930 }, this), 1); 24931 }, 24932 onEnter: function(e) 24933 { 24934 var stop = this.core.callback('enter', e); 24935 if (stop === false) 24936 { 24937 e.preventDefault(); 24938 return false; 24939 } 24940 24941 // blockquote exit 24942 if (this.keydown.blockquote && this.keydown.exitFromBlockquote(e) === true) 24943 { 24944 return false; 24945 } 24946 24947 // pre 24948 if (this.keydown.pre) 24949 { 24950 return this.keydown.insertNewLine(e); 24951 } 24952 // blockquote & figcaption 24953 else if (this.keydown.blockquote || this.keydown.figcaption) 24954 { 24955 return this.keydown.insertBreakLine(e); 24956 } 24957 // figure 24958 else if (this.keydown.figure) 24959 { 24960 setTimeout($.proxy(function() 24961 { 24962 this.keydown.replaceToParagraph('FIGURE'); 24963 24964 }, this), 1); 24965 } 24966 // paragraphs 24967 else if (this.keydown.block) 24968 { 24969 setTimeout($.proxy(function() 24970 { 24971 this.keydown.replaceToParagraph('DIV'); 24972 24973 }, this), 1); 24974 24975 // empty list exit 24976 if (this.keydown.block.tagName === 'LI') 24977 { 24978 var current = this.selection.current(); 24979 var $parent = $(current).closest('li', this.$editor[0]); 24980 var $list = $parent.parents('ul,ol', this.$editor[0]).last(); 24981 24982 if ($parent.length !== 0 && this.utils.isEmpty($parent.html()) && $list.next().length === 0 && this.utils.isEmpty($list.find("li").last().html())) 24983 { 24984 $list.find("li").last().remove(); 24985 24986 var node = $(this.opts.emptyHtml); 24987 $list.after(node); 24988 this.caret.start(node); 24989 24990 return false; 24991 } 24992 } 24993 24994 } 24995 // outside 24996 else if (!this.keydown.block) 24997 { 24998 return this.keydown.insertParagraph(e); 24999 } 25000 25001 // firefox enter into inline element 25002 if (this.detect.isFirefox() && this.utils.isInline(this.keydown.parent)) 25003 { 25004 this.keydown.insertBreakLine(e); 25005 return; 25006 } 25007 25008 // remove inline tags in new-empty paragraph 25009 if (!this.opts.keepInlineOnEnter) 25010 { 25011 setTimeout($.proxy(function() 25012 { 25013 var inline = this.selection.inline(); 25014 if (inline && this.utils.isEmpty(inline.innerHTML)) 25015 { 25016 var parent = this.selection.block(); 25017 $(inline).remove(); 25018 //this.caret.start(parent); 25019 25020 var range = document.createRange(); 25021 range.setStart(parent, 0); 25022 25023 var textNode = document.createTextNode('\u200B'); 25024
25025 range.insertNode(textNode); 25026 range.setStartAfter(textNode); 25027 range.collapse(true); 25028 25029 var sel = window.getSelection(); 25030 sel.removeAllRanges(); 25031 sel.addRange(range); 25032 } 25033 25034 25035 }, this), 1); 25036 } 25037 }, 25038 checkEvents: function(arrow, key) 25039 { 25040 if (!arrow && (this.core.getEvent() === 'click' || this.core.getEvent() === 'arrow')) 25041 { 25042 this.core.addEvent(false); 25043 25044 if (this.keydown.checkKeyEvents(key)) 25045 { 25046 this.buffer.set(); 25047 } 25048 } 25049 }, 25050 checkKeyEvents: function(key) 25051 { 25052 var k = this.keyCode; 25053 var keys = [k.BACKSPACE, k.DELETE, k.ENTER, k.ESC, k.TAB, k.CTRL, k.META, k.ALT, k.SHIFT]; 25054 25055 return ($.inArray(key, keys) === -1) ? true : false; 25056 25057 }, 25058 addArrowsEvent: function(arrow) 25059 { 25060 if (!arrow) 25061 { 25062 return; 25063 } 25064 25065 if ((this.core.getEvent() === 'click' || this.core.getEvent() === 'arrow')) 25066 { 25067 this.core.addEvent(false); 25068 return; 25069 } 25070 25071 this.core.addEvent('arrow'); 25072 }, 25073 setupBuffer: function(e, key) 25074 { 25075 if (this.keydown.ctrl && key === 90 && !e.shiftKey && !e.altKey && this.sBuffer.length) // z key 25076 { 25077 e.preventDefault(); 25078 this.buffer.undo(); 25079 return; 25080 } 25081 // redo 25082 else if (this.keydown.ctrl && key === 90 && e.shiftKey && !e.altKey && this.sRebuffer.length !== 0) 25083 { 25084 e.preventDefault(); 25085 this.buffer.redo(); 25086 return; 25087 } 25088 else if (!this.keydown.ctrl) 25089 { 25090 if (key === this.keyCode.SPACE || key === this.keyCode.BACKSPACE || key === this.keyCode.DELETE || (key === this.keyCode.ENTER && !e.ctrlKey && !e.shiftKey)) 25091 { 25092 this.buffer.set(); 25093 } 25094 } 25095 }, 25096 exitFromBlockquote: function(e) 25097 { 25098 if (!this.utils.isEndOfElement(this.keydown.blockquote)) 25099 { 25100 return; 25101 } 25102 25103 var tmp = this.clean.removeSpacesHard($(this.keydown.blockquote).html()); 25104 if (tmp.search(/(<br\s?\/?>){1}$/i) !== -1) 25105 { 25106 e.preventDefault(); 25107 25108 var $last = $(this.keydown.blockquote).children().last(); 25109 25110 $last.filter('br').remove(); 25111 $(this.keydown.blockquote).children().last().filter('span').remove(); 25112 25113 var node = $(this.opts.emptyHtml); 25114 $(this.keydown.blockquote).after(node); 25115 this.caret.start(node); 25116 25117 return true; 25118 25119 } 25120 25121 return; 25122 }, 25123 onArrowDown: function() 25124 { 25125 var tags = [this.keydown.blockquote, this.keydown.pre, this.keydown.figcaption]; 25126 25127 for (var i = 0; i < tags.length; i++) 25128 { 25129 if (tags[i]) 25130 { 25131 this.keydown.insertAfterLastElement(tags[i]); 25132 return false; 25133 } 25134 } 25135 }, 25136 onArrowUp: function() 25137 { 25138 var tags = [this.keydown.blockquote, this.keydown.pre, this.keydown.figcaption]; 25139 25140 for (var i = 0; i < tags.length; i++) 25141 { 25142 if (tags[i]) 25143 { 25144 this.keydown.insertBeforeFirstElement(tags[i]); 25145 return false; 25146 } 25147 } 25148 }, 25149 insertAfterLastElement: function(element) 25150 { 25151 if (!this.utils.isEndOfElement(element)) 25152 { 25153 return; 25154 } 25155 25156 var last = this.core.editor().contents().last(); 25157 var $next = (element.tagName === 'FIGCAPTION') ? $(this.keydown.block).parent().next() : $(this.keydown.block).next(); 25158 25159 if ($next.length !== 0) 25160 { 25161 return; 25162 } 25163 else if (last.length === 0 && last[0] !== element) 25164 { 25165 this.caret.start(last); 25166 return; 25167 } 25168 else 25169 { 25170 var node = $(this.opts.emptyHtml); 25171 25172 if (element.tagName === 'FIGCAPTION') 25173 { 25174 $(element).parent().after(node); 25175 } 25176 else 25177 { 25178 $(element).after(node); 25179 } 25180 25181 this.caret.start(node); 25182 } 25183 25184 }, 25185 insertBeforeFirstElement: function(element) 25186 { 25187 if (!this.utils.isStartOfElement()) 25188 { 25189 return; 25190 } 25191 25192 if (this.core.editor().contents().length > 1 && this.core.editor().contents().first()[0] !== element) 25193 { 25194 return; 25195 } 25196 25197 var node = $(this.opts.emptyHtml); 25198 $(element).before(node); 25199 this.caret.start(node); 25200 25201 }, 25202 onTab: function(e, key) 25203 { 25204 if (!this.opts.tabKey) 25205 { 25206 return true; 25207 } 25208 25209 var isList = (this.keydown.block && this.keydown.block.tagName === 'LI') 25210 if (this.utils.isEmpty(this.code.get()) || (!isList && !this.keydown.pre && this.opts.tabAsSpaces === false)) 25211 { 25212 return true; 25213 } 25214 25215 e.preventDefault(); 25216 this.buffer.set(); 25217 25218 var isListStart = (isList && this.utils.isStartOfElement(this.keydown.block)); 25219 var node; 25220 25221 if (this.keydown.pre && !e.shiftKey) 25222 { 25223 node = (this.opts.preSpaces) ? document.createTextNode(Array(this.opts.preSpaces + 1).join('\u00a0')) : document.createTextNode('\t'); 25224 this.insert.node(node); 25225 } 25226 else if (this.opts.tabAsSpaces !== false && !isListStart) 25227 { 25228 node = document.createTextNode(Array(this.opts.tabAsSpaces + 1).join('\u00a0')); 25229 this.insert.node(node); 25230 } 25231 else 25232 { 25233 if (e.metaKey && key === 219) 25234 { 25235 this.indent.decrease(); 25236 } 25237 else if (e.metaKey && key === 221) 25238 { 25239 this.indent.increase(); 25240 } 25241 else if (!e.shiftKey) 25242 { 25243 this.indent.increase(); 25244 } 25245 else 25246 { 25247 this.indent.decrease(); 25248 } 25249 } 25250 25251 return false;
25252 }, 25253 setupSelectAll: function(e, key) 25254 { 25255 if (this.keydown.ctrl && key === 65) 25256 { 25257 this.utils.enableSelectAll(); 25258 } 25259 else if (key !== this.keyCode.LEFT_WIN && !this.keydown.ctrl) 25260 { 25261 this.utils.disableSelectAll(); 25262 } 25263 }, 25264 insertNewLine: function(e) 25265 { 25266 e.preventDefault(); 25267 25268 var node = document.createTextNode('\n'); 25269 25270 var sel = this.selection.get(); 25271 var range = this.selection.range(sel); 25272 25273 range.deleteContents(); 25274 range.insertNode(node); 25275 25276 this.caret.after(node); 25277 25278 return false; 25279 }, 25280 insertParagraph: function(e) 25281 { 25282 e.preventDefault(); 25283 25284 var p = document.createElement('p'); 25285 //p.innerHTML = this.opts.invisibleSpace; 25286 p.innerHTML = '<br>'; 25287 25288 var sel = this.selection.get(); 25289 var range = this.selection.range(sel); 25290 25291 range.deleteContents(); 25292 range.insertNode(p); 25293 25294 this.caret.start(p); 25295 25296 return false; 25297 }, 25298 insertBreakLine: function(e) 25299 { 25300 return this.keydown.insertBreakLineProcessing(e); 25301 }, 25302 insertDblBreakLine: function(e) 25303 { 25304 return this.keydown.insertBreakLineProcessing(e, true); 25305 }, 25306 insertBreakLineProcessing: function(e, dbl) 25307 { 25308 e.stopPropagation(); 25309 25310 var br1 = document.createElement('br'); 25311 this.insert.node(br1); 25312 25313 if (dbl === true) 25314 { 25315 var br2 = document.createElement('br'); 25316 this.insert.node(br2); 25317 this.caret.after(br2); 25318 } 25319 else 25320 { 25321 this.caret.after(br1); 25322 } 25323 25324 return false; 25325 25326 }, 25327 wrapToParagraph: function() 25328 { 25329 var $current = $(this.keydown.current); 25330 var node = $('<p>').append($current.clone()); 25331 $current.replaceWith(node); 25332 25333 var next = $(node).next(); 25334 if (typeof(next[0]) !== 'undefined' && next[0].tagName === 'BR') 25335 { 25336 next.remove(); 25337 } 25338 25339 this.caret.end(node); 25340 25341 }, 25342 replaceToParagraph: function(tag) 25343 { 25344 var blockElem = this.selection.block(); 25345 var $prev = $(blockElem).prev(); 25346 25347 var blockHtml = blockElem.innerHTML.replace(/<br\s?\/?>/gi, ''); 25348 if (blockElem.tagName === tag && this.utils.isEmpty(blockHtml) && !$(blockElem).hasClass('redactor-in')) 25349 { 25350 var p = document.createElement('p'); 25351 $(blockElem).replaceWith(p); 25352 25353 this.keydown.setCaretToParagraph(p); 25354 25355 return false; 25356 } 25357 else if (blockElem.tagName === 'P') 25358 { 25359 $(blockElem).removeAttr('class').removeAttr('style'); 25360 25361 // fix #227 25362 if (this.detect.isIe() && this.utils.isEmpty(blockHtml) && this.utils.isInline(this.keydown.parent)) 25363 { 25364 $(blockElem).on('input', $.proxy(function() 25365 { 25366 var parent = this.selection.parent(); 25367 if (this.utils.isInline(parent)) 25368 { 25369 var html = $(parent).html(); 25370 $(blockElem).html(html); 25371 this.caret.end(blockElem); 25372 } 25373 25374 $(blockElem).off('keyup'); 25375 25376 }, this)); 25377 } 25378 25379 return false; 25380 } 25381 else if ($prev.hasClass(this.opts.videoContainerClass)) 25382 { 25383 $prev.removeAttr('class'); 25384 25385 var p = document.createElement('p'); 25386 $prev.replaceWith(p); 25387 25388 this.keydown.setCaretToParagraph(p); 25389 25390 return false; 25391 } 25392 }, 25393 setCaretToParagraph: function(p) 25394 { 25395 var range = document.createRange(); 25396 range.setStart(p, 0); 25397 25398 var textNode = document.createTextNode('\u200B'); 25399 25400 range.insertNode(textNode); 25401 range.setStartAfter(textNode); 25402 range.collapse(true); 25403 25404 var sel = window.getSelection(); 25405 sel.removeAllRanges(); 25406 sel.addRange(range); 25407 }, 25408 removeInvisibleSpace: function() 25409 { 25410 var $current = $(this.keydown.current); 25411 if ($current.text().search(/^\u200B$/g) === 0) 25412 { 25413 $current.remove(); 25414 } 25415 }, 25416 removeEmptyListInTable: function(e) 25417 { 25418 var $current = $(this.keydown.current); 25419 var $parent = $(this.keydown.parent); 25420 var td = $current.closest('td', this.$editor[0]); 25421 25422 if (td.length !== 0 && $current.closest('li', this.$editor[0]) && $parent.children('li').length === 1) 25423 { 25424 if (!this.utils.isEmpty($current.text())) 25425 { 25426 return; 25427 } 25428 25429 e.preventDefault(); 25430 25431 $current.remove(); 25432 $parent.remove(); 25433 25434 this.caret.start(td); 25435 } 25436 }, 25437 removeEmptyLists: function() 25438 { 25439 var removeIt = function() 25440 { 25441 var html = $.trim(this.innerHTML).replace(/\/t\/n/g, ''); 25442 if (html === '') 25443 { 25444 $(this).remove(); 25445 } 25446 }; 25447 25448 this.core.editor().find('li').each(removeIt); 25449 this.core.editor().find('ul, ol').each(removeIt); 25450 }, 25451 formatEmpty: function(e) 25452 { 25453 var html = $.trim(this.core.editor().html()); 25454 25455 if (!this.utils.isEmpty(html)) 25456 { 25457 return; 25458 } 25459 25460 e.preventDefault(); 25461 25462 if (this.opts.type === 'inline' || this.opts.type === 'pre') 25463 { 25464 this.core.editor().html(this.marker.html());
25465 this.selection.restore(); 25466 } 25467 else 25468 { 25469 this.core.editor().html(this.opts.emptyHtml); 25470 this.focus.start(); 25471 } 25472 25473 return false; 25474 25475 } 25476 }; 25477 }, 25478 25479 // =keyup 25480 keyup: function() 25481 { 25482 return { 25483 init: function(e) 25484 { 25485 if (this.rtePaste) 25486 { 25487 return; 25488 } 25489 25490 var key = e.which; 25491 this.keyup.block = this.selection.block(); 25492 this.keyup.current = this.selection.current(); 25493 this.keyup.parent = this.selection.parent(); 25494 this.keyup.lastShiftKey = e.shiftKey; 25495 25496 25497 // callback 25498 var stop = this.core.callback('keyup', e); 25499 if (stop === false) 25500 { 25501 e.preventDefault(); 25502 return false; 25503 } 25504 25505 // replace a prev figure to paragraph if caret is before image 25506 if (key === this.keyCode.ENTER) 25507 { 25508 if (this.keyup.block && this.keyup.block.tagName === 'FIGURE') 25509 { 25510 var $prev = $(this.keyup.block).prev(); 25511 if ($prev.length !== 0 && $prev[0].tagName === 'FIGURE') 25512 { 25513 var $newTag = this.utils.replaceToTag($prev, 'p'); 25514 this.caret.start($newTag); 25515 return; 25516 } 25517 } 25518 } 25519 25520 // replace figure to paragraph 25521 if (key === this.keyCode.BACKSPACE || key === this.keyCode.DELETE) 25522 { 25523 if (this.utils.isSelectAll()) 25524 { 25525 this.focus.start(); 25526 this.toolbar.setUnfixed(); 25527 25528 return; 25529 } 25530 25531 // if caret before figure - delete image 25532 if (this.keyup.block && this.keydown.block && this.keyup.block.tagName === 'FIGURE' && this.utils.isStartOfElement(this.keydown.block)) 25533 { 25534 e.preventDefault(); 25535 25536 this.selection.save(); 25537 $(this.keyup.block).find('figcaption').remove(); 25538 $(this.keyup.block).find('img').first().remove(); 25539 this.utils.replaceToTag(this.keyup.block, 'p'); 25540 25541 var $marker = this.marker.find(); 25542 $('html, body').animate({ scrollTop: $marker.position().top + 20 }, 500); 25543 25544 this.selection.restore(); 25545 return; 25546 } 25547 25548 25549 // if paragraph does contain only image replace to figure 25550 if (this.keyup.block && this.keyup.block.tagName === 'P') 25551 { 25552 var isContainImage = $(this.keyup.block).find('img').length; 25553 var text = $(this.keyup.block).text().replace(/\u200B/g, ''); 25554 if (text === '' && isContainImage !== 0) 25555 { 25556 this.utils.replaceToTag(this.keyup.block, 'figure'); 25557 } 25558 } 25559 25560 // if figure does not contain image - replace to paragraph 25561 if (this.keyup.block && this.keyup.block.tagName === 'FIGURE' && $(this.keyup.block).find('img').length === 0) 25562 { 25563 this.selection.save(); 25564 this.utils.replaceToTag(this.keyup.block, 'p'); 25565 this.selection.restore(); 25566 } 25567 } 25568 25569 // linkify 25570 if (this.linkify.isKey(key)) 25571 { 25572 this.selection.save(); 25573 this.linkify.format(); 25574 this.selection.restore(); 25575 } 25576 25577 } 25578 25579 }; 25580 }, 25581 25582 // =lang 25583 lang: function() 25584 { 25585 return { 25586 load: function() 25587 { 25588 this.opts.curLang = this.opts.langs[this.opts.lang]; 25589 }, 25590 get: function(name) 25591 { 25592 return (typeof this.opts.curLang[name] !== 'undefined') ? this.opts.curLang[name] : ''; 25593 } 25594 }; 25595 }, 25596 25597 // =line 25598 line: function() 25599 { 25600 return { 25601 insert: function() 25602 { 25603 this.buffer.set(); 25604 25605 // insert 25606 this.insert.html(this.line.getLineHtml()); 25607 25608 // find 25609 var $hr = this.core.editor().find('#redactor-hr-tmp-id'); 25610 $hr.removeAttr('id'); 25611 25612 this.core.callback('insertedLine', $hr); 25613 25614 return $hr; 25615 }, 25616 getLineHtml: function() 25617 { 25618 var html = '<hr id="redactor-hr-tmp-id" />'; 25619 if (!this.detect.isFirefox() && this.utils.isEmpty()) 25620 { 25621 html += '<p>' + this.opts.emptyHtml + '</p>'; 25622 } 25623 25624 return html; 25625 }, 25626 // ff only 25627 removeOnBackspace: function(e) 25628 { 25629 if (!this.utils.isCollapsed()) 25630 { 25631 return; 25632 } 25633 25634 var $block = $(this.selection.block()); 25635 if ($block.length === 0 || !this.utils.isStartOfElement($block)) 25636 { 25637 return; 25638 } 25639 25640 // if hr is previous element 25641 var $prev = $block.prev(); 25642 if ($prev && $prev.length !== 0 && $prev[0].tagName === 'HR') 25643 { 25644 e.preventDefault(); 25645 $prev.remove(); 25646 } 25647 } 25648 }; 25649 }, 25650 25651 // =link 25652 link: function() 25653 { 25654 return { 25655 25656 // public 25657 get: function() 25658 { 25659 return $(this.selection.inlines('a')); 25660 }, 25661 is: function() 25662 { 25663 var nodes = this.selection.nodes() ; 25664 var $link = $(this.selection.current()).closest('a', this.core.editor()[0]); 25665 25666 return ($link.length === 0 || nodes.length > 1) ? false : $link; 25667 }, 25668 unlink: function(e) 25669 { 25670 // if call from clickable element 25671 if (typeof e !== 'undefined' && e.preventDefault) 25672 { 25673 e.preventDefault(); 25674 } 25675 25676 // buffer 25677 this.buffer.set(); 25678 25679 var links = this.selection.inlines('a'); 25680 if (links.length === 0) 25681 { 25682 return; 25683 } 25684 25685 var $links = this.link.replaceLinksToText(links); 25686 25687 this.observe.closeAllTooltip(); 25688 this.core.callback('deletedLink', $links); 25689 25690 }, 25691 insert: function(link, cleaned) 25692 { 25693 var $el = this.link.is(); 25694 25695 if (cleaned !== true) 25696 { 25697 link = this.link.buildLinkFromObject($el, link); 25698 if (link === false) 25699 { 25700 return false;
25701 } 25702 } 25703 25704 // buffer 25705 this.buffer.set(); 25706 25707 // callback 25708 link = this.core.callback('beforeInsertingLink', link); 25709 25710 if ($el === false) 25711 { 25712 // insert 25713 $el = $('<a />'); 25714 $el = this.link.update($el, link); 25715 $el = $(this.insert.node($el)); 25716 25717 var $parent = $el.parent(); 25718 if (this.utils.isRedactorParent($parent) === false) 25719 { 25720 $el.wrap('<p>'); 25721 } 25722 25723 // remove unlink wrapper 25724 if ($parent.hasClass('redactor-unlink')) 25725 { 25726 $parent.replaceWith(function(){ 25727 return $(this).contents(); 25728 }); 25729 } 25730 25731 this.caret.after($el); 25732 this.core.callback('insertedLink', $el); 25733 } 25734 else 25735 { 25736 // update 25737 $el = this.link.update($el, link); 25738 this.caret.after($el); 25739 } 25740 25741 return $el; 25742 25743 }, 25744 update: function($el, link) 25745 { 25746 $el.text(link.text); 25747 $el.attr('href', link.url); 25748 25749 this.link.button($el, link.button); 25750 this.link.target($el, link.target); 25751 25752 return $el; 25753 25754 }, 25755 target: function($el, target) 25756 { 25757 return (target) ? $el.attr('target', '_blank') : $el.removeAttr('target'); 25758 }, 25759 button: function($el, button) 25760 { 25761 return (button) ? $el.addClass('button') : $el.removeClass('button'); 25762 }, 25763 show: function(e) 25764 { 25765 // if call from clickable element 25766 if (typeof e !== 'undefined' && e.preventDefault) 25767 { 25768 e.preventDefault(); 25769 } 25770 25771 // close tooltip 25772 this.observe.closeAllTooltip(); 25773 25774 // is link 25775 var $el = this.link.is(); 25776 25777 // build modal 25778 this.link.buildModal($el); 25779 25780 // build link 25781 var link = this.link.buildLinkFromElement($el); 25782 25783 // if link cut & paste inside editor browser added self host to a link 25784 link.url = this.link.removeSelfHostFromUrl(link.url); 25785 25786 // new tab target 25787 if (this.opts.linkNewTab && !$el) 25788 { 25789 link.target = true; 25790 } 25791 25792 // set modal values 25793 this.link.setModalValues(link); 25794 25795 // show modal 25796 this.modal.show(); 25797 25798 // focus 25799 if (this.detect.isDesktop()) 25800 { 25801 $('#redactor-link-url').focus(); 25802 } 25803 }, 25804 25805 // private 25806 setModalValues: function(link) 25807 { 25808 $('#redactor-link-blank').prop('checked', link.target); 25809 $('#redactor-link-button').prop('checked', link.button); 25810 $('#redactor-link-url').val(link.url); 25811 $('#redactor-link-url-text').val(link.text); 25812 }, 25813 buildModal: function($el) 25814 { 25815 this.modal.load('link', this.lang.get(($el === false) ? 'link-insert' : 'link-edit'), 600); 25816 25817 // button insert 25818 var $btn = this.modal.getActionButton(); 25819 $btn.text(this.lang.get(($el === false) ? 'insert' : 'save')).on('click', $.proxy(this.link.callback, this)); 25820 25821 }, 25822 callback: function() 25823 { 25824 // build link 25825 var link = this.link.buildLinkFromModal(); 25826 if (link === false) 25827 { 25828 return false; 25829 } 25830 25831 // close 25832 this.modal.close(); 25833 25834 // insert or update 25835 this.link.insert(link, true); 25836 }, 25837 cleanUrl: function(url) 25838 { 25839 return (typeof url === 'undefined') ? '' : $.trim(url.replace(/[^\W\w\D\d+&\'@#/%?=~_|!:,.;\(\)]/gi, '')); 25840 }, 25841 cleanText: function(text) 25842 { 25843 return (typeof text === 'undefined') ? '' : $.trim(text.replace(/(<([^>]+)>)/gi, '')); 25844 }, 25845 getText: function(link) 25846 { 25847 return (link.text === '' && link.url !== '') ? this.link.truncateUrl(link.url.replace(/<|>/g, '')) : link.text; 25848 }, 25849 isUrl: function(url) 25850 { 25851 var reUrl = new RegExp('^((https?|ftp):\\/\\/)?(([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.?)+[a-z]{2,}(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*(\\?[;&a-z\\d%_.~+=-]*)?(\\#[-a-z\\d_]*)?$','i'); 25852 25853 return (reUrl.test(url)) ? url : false; 25854 }, 25855 isMailto: function(url) 25856 { 25857 return (url.search('@') !== -1 && /(http|ftp|https):\/\//i.test(url) === false); 25858 }, 25859 isEmpty: function(link) 25860 { 25861 return (link.url === '' || (link.text === '' && link.url === '')); 25862 }, 25863 truncateUrl: function(url) 25864 { 25865 return (url.length > this.opts.linkSize) ? url.substring(0, this.opts.linkSize) + '...' : url; 25866 }, 25867 parse: function(link) 25868 { 25869 // mailto 25870 if (this.link.isMailto(link.url)) 25871 { 25872 link.url = 'mailto:' + link.url.replace('mailto:', ''); 25873 } 25874 // url 25875 else if (link.url.search('#') !== 0) 25876 { 25877 if (this.opts.linkValidation) 25878 { 25879 link.url = (this.link.isUrl(link.url)) ? 'http://' + link.url.replace(/(ftp|https?):\/\//gi, '') : link.url; 25880 } 25881 } 25882 25883 // empty url or text or isn't url 25884 return (this.link.isEmpty(link) || link.url === false) ? false : link; 25885 25886 }, 25887 buildLinkFromModal: function() 25888 { 25889 var link = {}; 25890 25891 // url 25892 link.url = this.link.cleanUrl($('#redactor-link-url').val()); 25893 25894 // text 25895 link.text = this.link.cleanText($('#redactor-link-url-text').val()); 25896 link.text = this.link.getText(link); 25897 25898 // button 25899 link.button = ($('#redactor-link-button').prop('checked')) ? true : false;
25900 25901 // target 25902 link.target = ($('#redactor-link-blank').prop('checked')) ? true : false; 25903 25904 // parse 25905 return this.link.parse(link); 25906 25907 }, 25908 buildLinkFromObject: function($el, link) 25909 { 25910 // url 25911 link.url = this.link.cleanUrl(link.url); 25912 25913 // text 25914 link.text = (typeof link.text === 'undefined' && this.selection.is()) ? this.selection.text() : this.link.cleanText(link.text); 25915 link.text = this.link.getText(link); 25916 25917 // button 25918 link.button = ($el === false) ? link.button : this.link.buildButton($el); 25919 25920 // target 25921 link.target = ($el === false) ? link.target : this.link.buildTarget($el); 25922 25923 // parse 25924 return this.link.parse(link); 25925 25926 }, 25927 buildLinkFromElement: function($el) 25928 { 25929 var link = { 25930 url: '', 25931 text: (this.selection.is()) ? this.selection.text() : '', 25932 target: false 25933 }; 25934 25935 if ($el !== false) 25936 { 25937 link.url = $el.attr('href'); 25938 link.text = $el.text(); 25939 link.button = this.link.buildButton($el); 25940 link.target = this.link.buildTarget($el); 25941 } 25942 25943 return link; 25944 }, 25945 buildButton: function($el) 25946 { 25947 console.log('build button'); 25948 return $el.hasClass('button') ? true : false; 25949 }, 25950 buildTarget: function($el) 25951 { 25952 console.log('build target'); 25953 return (typeof $el.attr('target') !== 'undefined' && $el.attr('target') === '_blank') ? true : false; 25954 }, 25955 removeSelfHostFromUrl: function(url) 25956 { 25957 var href = self.location.href.replace('#', '').replace(/\/$/i, ''); 25958 return url.replace(/^\/\#/, '#').replace(href, '').replace('mailto:', ''); 25959 }, 25960 replaceLinksToText: function(links) 25961 { 25962 var $first; 25963 var $links = $.each(links, function(i,s) 25964 { 25965 var $el = $(s); 25966 var $unlinked = $('<span class="redactor-unlink" />').append($el.contents()); 25967 $el.replaceWith($unlinked); 25968 25969 if (i === 0) 25970 { 25971 $first = $unlinked; 25972 } 25973 25974 return $el; 25975 }); 25976 25977 // set caret after unlinked node 25978 if (links.length === 1 && this.selection.isCollapsed()) 25979 { 25980 this.caret.after($first); 25981 } 25982 25983 return $links; 25984 } 25985 }; 25986 }, 25987 25988 // =linkify 25989 linkify: function() 25990 { 25991 return { 25992 isKey: function(key) 25993 { 25994 return key === this.keyCode.ENTER || key === this.keyCode.SPACE; 25995 }, 25996 isLink: function(node) 25997 { 25998 return (node.nodeValue.match(this.opts.regexps.linkyoutube) || node.nodeValue.match(this.opts.regexps.linkvimeo) || node.nodeValue.match(this.opts.regexps.linkimage) || node.nodeValue.match(this.opts.regexps.url)); 25999 }, 26000 isFiltered: function(i, node) 26001 { 26002 return node.nodeType === 3 && $.trim(node.nodeValue) !== "" && !$(node).parent().is("pre") && (this.linkify.isLink(node)); 26003 }, 26004 handler: function(i, node) 26005 { 26006 var $el = $(node); 26007 var text = $el.text(); 26008 var html = text; 26009 26010 if (html.match(this.opts.regexps.linkyoutube) || html.match(this.opts.regexps.linkvimeo)) 26011 { 26012 html = this.linkify.convertVideoLinks(html); 26013 } 26014 else if (html.match(this.opts.regexps.linkimage)) 26015 { 26016 html = this.linkify.convertImages(html); 26017 } 26018 else 26019 { 26020 html = this.linkify.convertLinks(html); 26021 } 26022 26023 $el.before(text.replace(text, html)).remove(); 26024 }, 26025 format: function() 26026 { 26027 if (!this.opts.linkify || this.utils.isCurrentOrParent('pre')) 26028 { 26029 return; 26030 } 26031 26032 this.core.editor().find(":not(iframe,img,a,pre,code,.redactor-unlink)").addBack().contents().filter($.proxy(this.linkify.isFiltered, this)).each($.proxy(this.linkify.handler, this)); 26033 26034 // collect 26035 var $el; 26036 var $objects = this.core.editor().find('.redactor-linkify-object').each($.proxy(function(i,s) 26037 { 26038 $el = $(s); 26039 $el.removeClass('redactor-linkify-object'); 26040 if ($el.attr('class') === '') 26041 { 26042 $el.removeAttr('class'); 26043 } 26044 26045 if (s.tagName === 'A') 26046 { 26047 this.core.callback('insertedLink', $el); 26048 } 26049 26050 return $el; 26051 26052 }, this)); 26053 26054 // callback 26055 setTimeout($.proxy(function() 26056 { 26057 this.code.sync(); 26058 this.core.callback('linkify', $objects); 26059 26060 }, this), 100); 26061 26062 }, 26063 convertVideoLinks: function(html) 26064 { 26065 var iframeStart = '<div class="' + this.opts.videoContainerClass + ' redactor-linkify-object"><iframe class="redactor-linkify-object" width="500" height="281" src="'; 26066 var iframeEnd = '" frameborder="0" allowfullscreen></iframe></div>'; 26067 26068 if (html.match(this.opts.regexps.linkyoutube)) 26069 { 26070 html = html.replace(this.opts.regexps.linkyoutube, iframeStart + '//www.youtube.com/embed/$1' + iframeEnd); 26071 } 26072 26073 if (html.match(this.opts.regexps.linkvimeo)) 26074 { 26075 html = html.replace(this.opts.regexps.linkvimeo, iframeStart + '//player.vimeo.com/video/$2' + iframeEnd); 26076 } 26077 26078 return html; 26079 }, 26080 convertImages: function(html) 26081 { 26082 var matches = html.match(this.opts.regexps.linkimage); 26083 if (!matches) 26084 { 26085 return html; 26086 } 26087 26088 return html.replace(html, '<img src="' + matches + '" class="redactor-linkify-object" />'); 26089 }, 26090 convertLinks: function(html) 26091 { 26092 var matches = html.match(this.opts.regexps.url); 26093 if (!matches) 26094 { 26095 return html; 26096 } 26097 26098 matches = $.grep(matches, function(v, k) { return $.inArray(v, matches) === k; }); 26099 26100 var length = matches.length; 26101 26102 for (var i = 0; i < length; i++) 26103 { 26104 var href = matches[i], text = href; 26105 var linkProtocol = (href.match(/(https?|ftp):\/\//i) !== null) ? '' : 'http://'; 26106 26107 if (text.length > this.opts.linkSize) 26108 { 26109 text = text.substring(0, this.opts.linkSize) + '...'; 26110 } 26111 26112 if (text.search('%') === -1) 26113 { 26114 text = decodeURIComponent(text); 26115 } 26116 26117 var regexB = "\\b"; 26118 26119 if ($.inArray(href.slice(-1), ["/", "&", "="]) !== -1) 26120 { 26121 regexB = ""; 26122 } 26123 26124 // escaping url 26125 var regexp = new RegExp('(' + href.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&") + regexB + ')', 'g'); 26126 26127 // target 26128 var target = ''; 26129 if (this.opts.pasteLinkTarget !== false) 26130 { 26131 target = ' target="' + this.opts.pasteLinkTarget + '"'; 26132 } 26133 26134 html = html.replace(regexp, '<a href="' + linkProtocol + $.trim(href) + '"' + target + ' class="redactor-linkify-object">' + $.trim(text) + '</a>'); 26135 } 26136 26137 return html; 26138 } 26139 }; 26140 }, 26141 26142 // =list 26143 list: function() 26144 { 26145 return { 26146 toggle: function(type) 26147 { 26148 if (this.utils.inBlocks(['table', 'td', 'th', 'tr'])) 26149 { 26150 return; 26151 } 26152 26153 type = (type === 'orderedlist') ? 'ol' : type; 26154 type = (type === 'unorderedlist') ? 'ul' : type; 26155 26156 type = type.toLowerCase(); 26157 26158 this.buffer.set(); 26159 this.selection.save(); 26160 26161 var nodes = this.list._getBlocks(); 26162 var block = this.selection.block(); 26163 var $list = $(block).parents('ul, ol').last(); 26164 if (nodes.length === 0 && $list.length !== 0) 26165 { 26166 nodes = [$list.get(0)]; 26167 } 26168 26169 nodes = (this.list._isUnformat(type, nodes)) ? this.list._unformat(type, nodes) : this.list._format(type, nodes); 26170
26171 this.selection.restore(); 26172 26173 return nodes; 26174 }, 26175 get: function() 26176 { 26177 var current = this.selection.current(); 26178 var $list = $(current).closest('ul, ol', this.core.editor()[0]); 26179 26180 return ($list.length === 0) ? false : $list; 26181 }, 26182 combineAfterAndBefore: function(block) 26183 { 26184 var $prev = $(block).prev(); 26185 var $next = $(block).next(); 26186 var isEmptyBlock = (block && block.tagName === 'P' && (block.innerHTML === '<br>' || block.innerHTML === '')); 26187 var isBlockWrapped = ($prev.closest('ol, ul', this.core.editor()[0]).length === 1 && $next.closest('ol, ul', this.core.editor()[0]).length === 1); 26188 26189 if (isEmptyBlock && isBlockWrapped) 26190 { 26191 $prev.children('li').last().append(this.marker.get()); 26192 $prev.append($next.contents()); 26193 this.selection.restore(); 26194 26195 return true; 26196 } 26197 26198 return false; 26199 26200 }, 26201 _getBlocks: function() 26202 { 26203 var finalBlocks = []; 26204 var blocks = this.selection.blocks(); 26205 for (var i = 0; i < blocks.length; i++) 26206 { 26207 var $el = $(blocks[i]); 26208 var isFirst = ($el.parent().hasClass('redactor-in')); 26209 26210 if (isFirst) finalBlocks.push(blocks[i]); 26211 } 26212 26213 return finalBlocks; 26214 }, 26215 _isUnformat: function(type, nodes) 26216 { 26217 var countLists = 0; 26218 for (var i = 0; i < nodes.length; i++) 26219 { 26220 if (nodes[i].nodeType !== 3) 26221 { 26222 var tag = nodes[i].tagName.toLowerCase(); 26223 if (tag === type || tag === 'figure') 26224 { 26225 countLists++; 26226 } 26227 } 26228 } 26229 26230 return (countLists === nodes.length); 26231 }, 26232 _uniteBlocks: function(nodes, tags) 26233 { 26234 var z = 0; 26235 var blocks = { 0: [] }; 26236 var lastcell = false; 26237 for (var i = 0; i < nodes.length; i++) 26238 { 26239 var $node = $(nodes[i]); 26240 var $cell = $node.closest('th, td'); 26241 26242 if ($cell.length !== 0) 26243 { 26244 if ($cell.get(0) !== lastcell) 26245 { 26246 // create block 26247 z++; 26248 blocks[z] = []; 26249 } 26250 26251 if (this.list._isUniteBlock(nodes[i], tags)) 26252 { 26253 blocks[z].push(nodes[i]); 26254 } 26255 } 26256 else 26257 { 26258 if (this.list._isUniteBlock(nodes[i], tags)) 26259 { 26260 blocks[z].push(nodes[i]); 26261 } 26262 else 26263 { 26264 // create block 26265 z++; 26266 blocks[z] = []; 26267 } 26268 } 26269 26270 lastcell = $cell.get(); 26271 } 26272 26273 return blocks; 26274 }, 26275 _isUniteBlock: function(node, tags) 26276 { 26277 return (node.nodeType === 3 || tags.indexOf(node.tagName.toLowerCase()) !== -1); 26278 }, 26279 _createList: function(type, blocks, key) 26280 { 26281 var last = blocks[blocks.length-1]; 26282 var $last = $(last); 26283 var $list = $('<' + type + '>'); 26284 $last.after($list); 26285 26286 return $list; 26287 }, 26288 _createListItem: function(item) 26289 { 26290 var $item = $('<li>'); 26291 if (item.nodeType === 3) 26292 { 26293 $item.append(item); 26294 } 26295 else 26296 { 26297 var $el = $(item); 26298 $item.append($el.contents()); 26299 $el.remove(); 26300 } 26301 26302 return $item; 26303 }, 26304 _format: function(type, nodes) 26305 { 26306 var tags = ['p', 'div', 'blockquote', 'pre', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'ul', 'ol']; 26307 var blocks = this.list._uniteBlocks(nodes, tags); 26308 var lists = []; 26309 26310 for (var key in blocks) 26311 { 26312 var items = blocks[key]; 26313 var $list = this.list._createList(type, blocks[key]); 26314 26315 for (var i = 0; i < items.length; i++) 26316 { 26317 var $item; 26318 26319 // lists 26320 if (items[i].nodeType !== 3 && (items[i].tagName === 'UL' || items[i].tagName === 'OL')) 26321 { 26322 $item = $(items[i]).contents(); 26323 $list.append($item); 26324 } 26325 // other blocks or texts 26326 else 26327 { 26328 $item = this.list._createListItem(items[i]); 26329 //this.utils.normalizeTextNodes($item); 26330 $list.append($item); 26331 } 26332 } 26333 26334 lists.push($list.get(0)); 26335 } 26336 26337 return lists; 26338 }, 26339 _unformat: function(type, nodes) 26340 { 26341 26342 if (nodes.length === 1) 26343 { 26344 // one list 26345 var $list = $(nodes[0]); 26346 var $items = $list.find('li'); 26347 26348 var selectedItems = this.selection.blocks(['li']); 26349 var block = this.selection.block(); 26350 var $li = $(block).closest('li'); 26351 if (selectedItems.length === 0 && $li.length !== 0) 26352 { 26353 selectedItems = [$li.get(0)]; 26354 } 26355 26356 // 1) entire 26357 if (selectedItems.length === $items.length) 26358 { 26359 return this.list._unformatEntire(nodes[0]); 26360 } 26361 26362 var pos = this.list._getItemsPosition($items, selectedItems); 26363 26364 // 2) top 26365 if (pos === 'Top') 26366 { 26367 return this.list._unformatAtSide('before', selectedItems, $list); 26368 } 26369 26370 // 3) bottom 26371 else if (pos === 'Bottom') 26372 { 26373 selectedItems.reverse(); 26374 return this.list._unformatAtSide('after', selectedItems, $list); 26375 } 26376 26377 // 4) middle 26378 else if (pos === 'Middle') 26379 { 26380 var $last = $(selectedItems[selectedItems.length-1]); 26381 26382 var ci = false;
26383 26384 var $parent = false; 26385 var $secondList = $('<' + $list.get(0).tagName.toLowerCase() + '>'); 26386 $items.each(function(i, node) 26387 { 26388 if (ci) 26389 { 26390 var $node = $(node); 26391 var $childList = ($node.children('ul, ol').length !== 0); 26392 26393 if ($node.closest('.redactor-split-item').length === 0 && ($parent === false || $node.closest($parent).length === 0)) 26394 { 26395 $node.addClass('redactor-split-item'); 26396 } 26397 26398 $parent = $node; 26399 26400 } 26401 26402 if (node === $last.get(0)) 26403 { 26404 ci = true; 26405 } 26406 }); 26407 26408 $items.filter('.redactor-split-item').each(function(i, node) 26409 { 26410 var $node = $(node); 26411 $node.removeClass('redactor-split-item'); 26412 $secondList.append(node); 26413 }); 26414 26415 $list.after($secondList); 26416 26417 selectedItems.reverse(); 26418 for (var i = 0; i < selectedItems.length; i++) 26419 { 26420 var $item = $(selectedItems[i]); 26421 var $container = this.list._createUnformatContainer($item); 26422 26423 $list.after($container); 26424 $container.find('ul, ol').remove(); 26425 $item.remove(); 26426 } 26427 26428 26429 return; 26430 } 26431 26432 } 26433 else 26434 { 26435 // unformat all 26436 for (var i = 0; i < nodes.length; i++) 26437 { 26438 if (nodes[i].nodeType !== 3 && nodes[i].tagName.toLowerCase() === type) 26439 { 26440 this.list._unformatEntire(nodes[i]); 26441 } 26442 } 26443 } 26444 }, 26445 _unformatEntire: function(list) 26446 { 26447 var $list = $(list); 26448 var $items = $list.find('li'); 26449 $items.each(function(i, node) 26450 { 26451 var $item = $(node); 26452 var $container = this.list._createUnformatContainer($item); 26453 26454 $item.remove(); 26455 $list.before($container); 26456 26457 }.bind(this)); 26458 26459 $list.remove(); 26460 }, 26461 _unformatAtSide: function(type, selectedItems, $list) 26462 { 26463 for (var i = 0; i < selectedItems.length; i++) 26464 { 26465 var $item = $(selectedItems[i]); 26466 var $container = this.list._createUnformatContainer($item); 26467 26468 $list[type]($container); 26469 26470 var $innerLists = $container.find('ul, ol').first(); 26471 $item.append($innerLists); 26472 26473 $innerLists.each(function(i, node) 26474 { 26475 var $node = $(node); 26476 var $parent = $node.closest('li'); 26477 26478 if ($parent.get(0) === selectedItems[i]) 26479 { 26480 $node.unwrap(); 26481 $parent.addClass('r-unwrapped'); 26482 } 26483 26484 }); 26485 26486 if (this.utils.isEmpty($item.html())) $item.remove(); 26487 } 26488 26489 // clear empty 26490 $list.find('.r-unwrapped').each(function(node) 26491 { 26492 var $node = $(node); 26493 if ($node.html().trim() === '') $node.remove(); 26494 else $node.removeClass('r-unwrapped'); 26495 }); 26496 }, 26497 _getItemsPosition: function($items, selectedItems) 26498 { 26499 var pos = 'Middle'; 26500 26501 var sFirst = selectedItems[0]; 26502 var sLast = selectedItems[selectedItems.length-1]; 26503 26504 var first = $items.first().get(0);
26505 var last = $items.last().get(0); 26506 26507 if (first === sFirst && last !== sLast) 26508 { 26509 pos = 'Top'; 26510 } 26511 else if (first !== sFirst && last === sLast) 26512 { 26513 pos = 'Bottom'; 26514 } 26515 26516 return pos; 26517 }, 26518 _createUnformatContainer: function($item) 26519 { 26520 var $container = $('<p>'); 26521 $container.append($item.contents()); 26522 26523 return $container; 26524 } 26525 }; 26526 }, 26527 26528 // =marker 26529 marker: function() 26530 { 26531 return { 26532 26533 // public 26534 get: function(num) 26535 { 26536 num = (typeof num === 'undefined') ? 1 : num; 26537 26538 var marker = document.createElement('span'); 26539 26540 marker.id = 'selection-marker-' + num; 26541 marker.className = 'redactor-selection-marker'; 26542 marker.innerHTML = this.opts.invisibleSpace; 26543 26544 return marker; 26545 }, 26546 html: function(num) 26547 { 26548 return this.utils.getOuterHtml(this.marker.get(num)); 26549 }, 26550 find: function(num) 26551 { 26552 num = (typeof num === 'undefined') ? 1 : num; 26553 26554 return this.core.editor().find('span#selection-marker-' + num); 26555 }, 26556 insert: function() 26557 { 26558 var sel = this.selection.get(); 26559 var range = this.selection.range(sel); 26560 26561 this.marker.insertNode(range, this.marker.get(1), true); 26562 if (range && range.collapsed === false) 26563 { 26564 this.marker.insertNode(range, this.marker.get(2), false); 26565 } 26566 26567 }, 26568 remove: function() 26569 { 26570 this.core.editor().find('.redactor-selection-marker').each(this.marker.iterateRemove); 26571 }, 26572 26573 // private 26574 insertNode: function(range, node, collapse) 26575 { 26576 var parent = this.selection.parent(); 26577 if (range === null || $(parent).closest('.redactor-in').length === 0) 26578 { 26579 return; 26580 } 26581 26582 range = range.cloneRange(); 26583 26584 try { 26585 range.collapse(collapse); 26586 range.insertNode(node); 26587 } 26588 catch (e) 26589 { 26590 this.focus.start(); 26591 } 26592 }, 26593 iterateRemove: function(i, el) 26594 { 26595 var $el = $(el); 26596 var text = $el.text().replace(/\u200B/g, ''); 26597 var parent = $el.parent()[0]; 26598 26599 if (text === '') $el.remove(); 26600 else $el.replaceWith(function() { return $(this).contents(); }); 26601 26602 // if (parent && parent.normalize) parent.normalize(); 26603 } 26604 }; 26605 }, 26606 26607 // =modal 26608 modal: function() 26609 { 26610 return { 26611 callbacks: {}, 26612 templates: function() 26613 { 26614 this.opts.modal = { 26615 'image-edit': String() 26616 + '<div class="redactor-modal-tab redactor-group" data-title="General">' 26617 + '<div id="redactor-image-preview" class="redactor-modal-tab-side">' 26618 + '</div>' 26619 + '<div class="redactor-modal-tab-area">' 26620 + '<section>' 26621 + '<label>' + this.lang.get('title') + '</label>' 26622 + '<input type="text" id="redactor-image-title" />' 26623 + '</section>' 26624 + '<section>' 26625 + '<label>' + this.lang.get('caption') + '</label>' 26626 + '<input type="text" id="redactor-image-caption" aria-label="' + this.lang.get('caption') + '" />' 26627 + '</section>' 26628 + '<section>' 26629 + '<label>' + this.lang.get('link') + '</label>' 26630 + '<input type="text" id="redactor-image-link" aria-label="' + this.lang.get('link') + '" />' 26631 + '</section>' 26632 + '<section>' 26633 + '<label class="redactor-image-position-option">' + this.lang.get('image-position') + '</label>' 26634 + '<select class="redactor-image-position-option" id="redactor-image-align" aria-label="' + this.lang.get('image-position') + '">' 26635 + '<option value="none">' + this.lang.get('none') + '</option>' 26636 + '<option value="left">' + this.lang.get('left') + '</option>' 26637 + '<option value="center">' + this.lang.get('center') + '</option>' 26638 + '<option value="right">' + this.lang.get('right') + '</option>' 26639 + '</select>' 26640 + '</section>' 26641 + '<section>' 26642 + '<label class="checkbox"><input type="checkbox" id="redactor-image-link-blank" aria-label="' + this.lang.get('link-in-new-tab') + '"> ' + this.lang.get('link-in-new-tab') + '</label>' 26643 + '</section>' 26644 + '<section>' 26645 + '<button id="redactor-modal-button-action">' + this.lang.get('insert') + '</button>' 26646 + '<button id="redactor-modal-button-cancel">' + this.lang.get('cancel') + '</button>' 26647 + '<button id="redactor-modal-button-delete" class="redactor-modal-button-offset">' + this.lang.get('delete') + '</button>' 26648 + '</section>' 26649 + '</div>' 26650 + '</div>', 26651 26652 'image': String() 26653 + '<div class="redactor-modal-tab" data-title="Upload">' 26654 + '<section>' 26655 + '<div id="redactor-modal-image-droparea"></div>' 26656 + '</section>' 26657 + '</div>', 26658 26659 'file': String() 26660 + '<div class="redactor-modal-tab" data-title="Upload">' 26661 + '<section>' 26662 + '<label>' + this.lang.get('filename') + ' <span class="desc">(' + this.lang.get('optional') + ')</span></label>' 26663 + '<input type="text" id="redactor-filename" aria-label="' + this.lang.get('filename') + '" /><br><br>' 26664 + '</section>' 26665 + '<section>' 26666 + '<div id="redactor-modal-file-upload"></div>' 26667 + '</section>' 26668 + '</div>', 26669
26670 'link': String() 26671 + '<div class="redactor-modal-tab" data-title="General">' 26672 + '<section>' 26673 + '<label>URL</label>' 26674 + '<input type="url" id="redactor-link-url" aria-label="URL" />' 26675 + '</section>' 26676 + '<section>' 26677 + '<label>' + this.lang.get('text') + '</label>' 26678 + '<input type="text" id="redactor-link-url-text" aria-label="' + this.lang.get('text') + '" />' 26679 + '</section>' 26680 + '<section>' 26681 + '<label class="checkbox"><input type="checkbox" id="redactor-link-button"> ' + this.lang.get('link-as-button') + '</label>' 26682 + '</section>' 26683 + '<section>' 26684 + '<label class="checkbox"><input type="checkbox" id="redactor-link-blank"> ' + this.lang.get('link-in-new-tab') + '</label>' 26685 + '</section>' 26686 + '<section>' 26687 + '<button id="redactor-modal-button-action">' + this.lang.get('insert') + '</button>' 26688 + '<button id="redactor-modal-button-cancel">' + this.lang.get('cancel') + '</button>' 26689 + '</section>' 26690 + '</div>' 26691 }; 26692 26693 $.extend(this.opts, this.opts.modal); 26694 26695 }, 26696 addCallback: function(name, callback) 26697 { 26698 this.modal.callbacks[name] = callback; 26699 }, 26700 addTemplate: function(name, template) 26701 { 26702 this.opts.modal[name] = template; 26703 }, 26704 getTemplate: function(name) 26705 { 26706 return this.opts.modal[name]; 26707 }, 26708 getModal: function() 26709 { 26710 return this.$modalBody; 26711 }, 26712 getActionButton: function() 26713 { 26714 return this.$modalBody.find('#redactor-modal-button-action'); 26715 }, 26716 getCancelButton: function() 26717 { 26718 return this.$modalBody.find('#redactor-modal-button-cancel'); 26719 }, 26720 getDeleteButton: function() 26721 { 26722 return this.$modalBody.find('#redactor-modal-button-delete'); 26723 }, 26724 load: function(templateName, title, width) 26725 { 26726 if (typeof this.$modalBox !== 'undefined' && this.$modalBox.hasClass('open')) 26727 { 26728 return; 26729 } 26730 26731 this.modal.templateName = templateName; 26732 this.modal.width = width; 26733 26734 this.modal.build(); 26735 this.modal.enableEvents(); 26736 this.modal.setTitle(title); 26737 this.modal.setDraggable(); 26738 this.modal.setContent(); 26739 26740 // callbacks 26741 if (typeof this.modal.callbacks[templateName] !== 'undefined') 26742 { 26743 this.modal.callbacks[templateName].call(this); 26744 } 26745 26746 }, 26747 show: function() 26748 { 26749 26750 if (!this.detect.isDesktop()) 26751 { 26752 document.activeElement.blur(); 26753 } 26754 26755 this.selection.save(); 26756 this.modal.buildTabber(); 26757 26758 if (this.detect.isMobile()) 26759 { 26760 this.modal.width = '96%'; 26761 } 26762 26763 // resize 26764 setTimeout($.proxy(this.modal.buildWidth, this), 0); 26765 $(window).on('resize.redactor-modal', $.proxy(this.modal.buildWidth, this)); 26766 26767 26768 this.$modalOverlay.redactorAnimation('fadeIn', { 26769 duration: 0.25 26770 }); 26771 26772 this.$modalBox.addClass('open').show(); 26773 this.$modal.redactorAnimation('fadeIn', { 26774 timing: 'cubic-bezier(0.175, 0.885, 0.320, 1.105)' 26775 }, 26776 $.proxy(function() 26777 { 26778 26779 this.utils.saveScroll(); 26780 this.utils.disableBodyScroll(); 26781 26782 // modal shown callback 26783 this.core.callback('modalOpened', this.modal.templateName, this.$modal); 26784 26785 // fix bootstrap modal focus 26786 $(document).off('focusin.modal'); 26787 26788 // enter 26789 var $elements = this.$modal.find('input[type=text],input[type=url],input[type=email]'); 26790 $elements.on('keydown.redactor-modal', $.proxy(this.modal.setEnter, this)); 26791 26792 }, this) 26793 ); 26794 26795 }, 26796 buildWidth: function() 26797 { 26798 var windowHeight = $(window).height(); 26799 var windowWidth = $(window).width(); 26800 26801 var number = (typeof this.modal.width === 'number'); 26802 26803 if (!number && this.modal.width.match(/%$/)) 26804 { 26805 this.$modal.css({ 'width': this.modal.width, 'margin-bottom': '16px' }); 26806 } 26807 else if (parseInt(this.modal.width) > windowWidth) 26808 { 26809 this.$modal.css({ 'width': '96%', 'margin-bottom': '2%' }); 26810 } 26811 else 26812 { 26813 if (number) 26814 { 26815 this.modal.width += 'px'; 26816 } 26817 26818 this.$modal.css({ 'width': this.modal.width, 'margin-bottom': '16px' }); 26819 } 26820 26821 // margin top 26822 var height = this.$modal.outerHeight();
26823 var top = (windowHeight/2 - height/2) + 'px'; 26824 26825 if (this.detect.isMobile()) 26826 { 26827 top = '2%'; 26828 } 26829 else if (height > windowHeight) 26830 { 26831 top = '16px'; 26832 26833 } 26834 26835 this.$modal.css('margin-top', top); 26836 }, 26837 buildTabber: function() 26838 { 26839 this.modal.tabs = this.$modal.find('.redactor-modal-tab'); 26840 26841 if (this.modal.tabs.length < 2) 26842 { 26843 return; 26844 } 26845 26846 this.modal.$tabsBox = $('<div id="redactor-modal-tabber" />'); 26847 $.each(this.modal.tabs, $.proxy(function(i,s) 26848 { 26849 var a = $('<a href="#" rel="' + i + '" />').text($(s).attr('data-title')); 26850 26851 a.on('click', $.proxy(this.modal.showTab, this)); 26852 26853 if (i === 0) 26854 { 26855 a.addClass('active'); 26856 } 26857 26858 this.modal.$tabsBox.append(a); 26859 26860 }, this)); 26861 26862 this.$modalBody.prepend(this.modal.$tabsBox); 26863 26864 }, 26865 showTab: function(e) 26866 { 26867 e.preventDefault(); 26868 26869 var $el = $(e.target); 26870 var index = $el.attr('rel'); 26871 26872 this.modal.tabs.hide(); 26873 this.modal.tabs.eq(index).show(); 26874 26875 $('#redactor-modal-tabber').find('a').removeClass('active'); 26876 $el.addClass('active'); 26877 26878 return false; 26879 26880 }, 26881 setTitle: function(title) 26882 { 26883 this.$modalHeader.html(title); 26884 }, 26885 setContent: function() 26886 { 26887 this.$modalBody.html(this.modal.getTemplate(this.modal.templateName)); 26888 26889 this.modal.getCancelButton().on('mousedown', $.proxy(this.modal.close, this)); 26890 }, 26891 setDraggable: function() 26892 { 26893 if (typeof $.fn.draggable === 'undefined') 26894 { 26895 return; 26896 } 26897 26898 this.$modal.draggable({ handle: this.$modalHeader }); 26899 this.$modalHeader.css('cursor', 'move'); 26900 }, 26901 setEnter: function(e) 26902 { 26903 if (e.which !== 13) 26904 { 26905 return; 26906 } 26907 26908 e.preventDefault(); 26909 this.modal.getActionButton().click(); 26910 }, 26911 build: function() 26912 { 26913 this.modal.buildOverlay(); 26914 26915 this.$modalBox = $('<div id="redactor-modal-box"/>').hide(); 26916 this.$modal = $('<div id="redactor-modal" role="dialog" />'); 26917 this.$modalHeader = $('<div id="redactor-modal-header" />'); 26918 this.$modalClose = $('<button type="button" id="redactor-modal-close" aria-label="' + this.lang.get('close') + '" />').html('×'); 26919 this.$modalBody = $('<div id="redactor-modal-body" />'); 26920 26921 this.$modal.append(this.$modalHeader); 26922 this.$modal.append(this.$modalBody); 26923 this.$modal.append(this.$modalClose); 26924 this.$modalBox.append(this.$modal); 26925 this.$modalBox.appendTo(document.body); 26926 26927 }, 26928 buildOverlay: function() 26929 { 26930 this.$modalOverlay = $('<div id="redactor-modal-overlay">').hide(); 26931 $('body').prepend(this.$modalOverlay); 26932 }, 26933 enableEvents: function() 26934 { 26935 this.$modalClose.on('mousedown.redactor-modal', $.proxy(this.modal.close, this)); 26936 $(document).on('keyup.redactor-modal', $.proxy(this.modal.closeHandler, this)); 26937 this.core.editor().on('keyup.redactor-modal', $.proxy(this.modal.closeHandler, this)); 26938 this.$modalBox.on('click.redactor-modal', $.proxy(this.modal.close, this)); 26939 }, 26940 disableEvents: function() 26941 { 26942 this.$modalClose.off('mousedown.redactor-modal'); 26943 $(document).off('keyup.redactor-modal'); 26944 this.core.editor().off('keyup.redactor-modal'); 26945 this.$modalBox.off('click§.redactor-modal'); 26946 $(window).off('resize.redactor-modal'); 26947 }, 26948 closeHandler: function(e) 26949 { 26950 if (e.which !== this.keyCode.ESC) 26951 { 26952 return; 26953 } 26954 26955 this.modal.close(false); 26956 }, 26957 close: function(e) 26958 { 26959 if (e) 26960 { 26961 if ($(e.target).attr('id') !== 'redactor-modal-button-cancel' && e.target !== this.$modalClose[0] && e.target !== this.$modalBox[0]) 26962 { 26963 return; 26964 } 26965 26966 e.preventDefault(); 26967 } 26968 26969 if (!this.$modalBox) 26970 { 26971 return; 26972 } 26973 26974 // restore selection 26975 this.selection.restore(); 26976 26977 this.modal.disableEvents(); 26978 this.utils.enableBodyScroll(); 26979 this.utils.restoreScroll(); 26980 26981 this.$modalOverlay.redactorAnimation('fadeOut', { duration: 0.4 }, $.proxy(function() 26982 { 26983 this.$modalOverlay.remove(); 26984 26985 }, this)); 26986 26987 this.$modal.redactorAnimation('fadeOut', { 26988 26989 duration: 0.3, 26990 timing: 'cubic-bezier(0.175, 0.885, 0.320, 1.175)' 26991 26992 }, $.proxy(function() 26993 { 26994 if (typeof this.$modalBox !== 'undefined') 26995 { 26996 this.$modalBox.remove(); 26997 this.$modalBox = undefined; 26998 } 26999 27000 this.core.callback('modalClosed', this.modal.templateName); 27001 27002 }, this)); 27003 27004 } 27005 }; 27006 }, 27007 27008 // =observe 27009 observe: function() 27010 { 27011 return { 27012 load: function() 27013 { 27014 if (typeof this.opts.destroyed !== 'undefined') 27015 { 27016 return; 27017 } 27018 27019 this.observe.links(); 27020 this.observe.images(); 27021 27022 }, 27023 isCurrent: function($el, $current) 27024 { 27025 if (typeof $current === 'undefined') 27026 { 27027 $current = $(this.selection.current()); 27028 } 27029 27030 return $current.is($el) || $current.parents($el).length > 0; 27031 }, 27032 toolbar: function() 27033 { 27034 this.observe.buttons(); 27035 this.observe.dropdowns(); 27036 }, 27037 buttons: function(e, btnName) 27038 { 27039 var current = this.selection.current(); 27040 var parent = this.selection.parent(); 27041 27042 if (e !== false) this.button.setInactiveAll(); 27043 else this.button.setInactiveAll(btnName); 27044 27045 27046 if (e === false && btnName !== 'html') 27047 { 27048 if ($.inArray(btnName, this.opts.activeButtons) !== -1) this.button.toggleActive(btnName); 27049 return; 27050 } 27051 27052 if (!this.utils.isRedactorParent(current)) 27053 { 27054 return; 27055 } 27056 27057 // disable line 27058 if (this.core.editor().css('display') !== 'none') 27059 { 27060 if (this.utils.isCurrentOrParentHeader() || this.utils.isCurrentOrParent(['table', 'pre', 'blockquote', 'li'])) this.button.disable('horizontalrule'); 27061 else this.button.enable('horizontalrule'); 27062 } 27063 27064 $.each(this.opts.activeButtonsStates, $.proxy(function(key, value) 27065 { 27066 var parentEl = $(parent).closest(key, this.$editor[0]); 27067 var currentEl = $(current).closest(key, this.$editor[0]); 27068 27069 if (parentEl.length !== 0 && !this.utils.isRedactorParent(parentEl)) 27070 { 27071 return; 27072 } 27073 27074 if (!this.utils.isRedactorParent(currentEl)) 27075 { 27076 return; 27077 } 27078 27079 if (parentEl.length !== 0 || currentEl.closest(key, this.$editor[0]).length !== 0) 27080 { 27081 this.button.setActive(value); 27082 } 27083 27084 }, this)); 27085 27086 }, 27087 dropdowns: function() 27088 { 27089 var finded = $('<div />').html(this.selection.html()).find('a').length; 27090 var $current = $(this.selection.current()); 27091 var isRedactor = this.utils.isRedactorParent($current); 27092 27093 $.each(this.opts.observe.dropdowns, $.proxy(function(key, value) 27094 { 27095 var observe = value.observe, 27096 element = observe.element, 27097 $item = value.item, 27098 inValues = typeof observe['in'] !== 'undefined' ? observe['in']
27098: false, 27099 outValues = typeof observe.out !== 'undefined' ? observe.out : false; 27100 27101 if (($current.closest(element).length > 0 && isRedactor) || (element === 'a' && finded !== 0)) 27102 { 27103 this.observe.setDropdownProperties($item, inValues, outValues); 27104 } 27105 else 27106 { 27107 this.observe.setDropdownProperties($item, outValues, inValues); 27108 } 27109 27110 }, this)); 27111 }, 27112 setDropdownProperties: function($item, addProperties, deleteProperties) 27113 { 27114 if (deleteProperties && typeof deleteProperties.attr !== 'undefined') 27115 { 27116 this.observe.setDropdownAttr($item, deleteProperties.attr, true); 27117 } 27118 27119 if (typeof addProperties.attr !== 'undefined') 27120 { 27121 this.observe.setDropdownAttr($item, addProperties.attr); 27122 } 27123 27124 if (typeof addProperties.title !== 'undefined') 27125 { 27126 $item.find('span').text(addProperties.title); 27127 } 27128 }, 27129 setDropdownAttr: function($item, properties, isDelete) 27130 { 27131 $.each(properties, function(key, value) 27132 { 27133 if (key === 'class') 27134 { 27135 if (!isDelete) 27136 { 27137 $item.addClass(value); 27138 } 27139 else 27140 { 27141 $item.removeClass(value); 27142 } 27143 } 27144 else 27145 { 27146 if (!isDelete) 27147 { 27148 $item.attr(key, value); 27149 } 27150 else 27151 { 27152 $item.removeAttr(key); 27153 } 27154 } 27155 }); 27156 }, 27157 addDropdown: function($item, btnName, btnObject) 27158 { 27159 if (typeof btnObject.observe === "undefined") 27160 { 27161 return; 27162 } 27163 27164 btnObject.item = $item; 27165 27166 this.opts.observe.dropdowns.push(btnObject); 27167 }, 27168 images: function() 27169 { 27170 if (this.opts.imageEditable) 27171 { 27172 this.core.editor().addClass('redactor-layer-img-edit'); 27173 this.core.editor().find('img').each($.proxy(function(i, img) 27174 { 27175 var $img = $(img); 27176 27177 // IE fix (when we clicked on an image and then press backspace IE does goes to image's url) 27178 $img.closest('a', this.$editor[0]).on('click', function(e) { e.preventDefault(); }); 27179 27180 this.image.setEditable($img); 27181 27182 27183 }, this)); 27184 } 27185 }, 27186 links: function() 27187 { 27188 if (this.opts.linkTooltip) 27189 { 27190 this.core.editor().find('a').each($.proxy(function(i, s) 27191 { 27192 var $link = $(s); 27193 if ($link.data('cached') !== true) 27194 { 27195 $link.data('cached', true); 27196 $link.on('touchstart.redactor.' + this.uuid + ' click.redactor.' + this.uuid, $.proxy(this.observe.showTooltip, this)); 27197 } 27198 27199 }, this)); 27200 } 27201 }, 27202 getTooltipPosition: function($link) 27203 { 27204 return $link.offset(); 27205 }, 27206 showTooltip: function(e) 27207 { 27208 var $el = $(e.target); 27209 27210 if ($el[0].tagName === 'IMG') 27211 { 27212 return; 27213 } 27214 27215 if ($el[0].tagName !== 'A') 27216 { 27217 $el = $el.closest('a', this.$editor[0]); 27218 } 27219 27220 if ($el[0].tagName !== 'A') 27221 { 27222 return; 27223 } 27224 27225 var $link = $el; 27226 27227 var pos = this.observe.getTooltipPosition($link); 27228 var tooltip = $('<span class="redactor-link-tooltip"></span>'); 27229 27230 var href = $link.attr('href'); 27231 if (href === undefined) 27232 { 27233 href = ''; 27234 } 27235 27236 if (href.length > 24) 27237 { 27238 href = href.substring(0, 24) + '...'; 27239 } 27240 27241 var aLink = $('<a href="' + $link.attr('href') + '" target="_blank" />').html(href).addClass('redactor-link-tooltip-action'); 27242 var aEdit = $('<a href="#" />').html(this.lang.get('edit')).on('click', $.proxy(this.link.show, this)).addClass('redactor-link-tooltip-action'); 27243 var aUnlink = $('<a href="#" />').html(this.lang.get('unlink')).on('click', $.proxy(this.link.unlink, this)).addClass('redactor-link-tooltip-action'); 27244 27245 tooltip.append(aLink).append(' | ').append(aEdit).append(' | ').append(aUnlink); 27246 27247 var lineHeight = parseInt($link.css('line-height'), 10); 27248 var lineClicked = Math.ceil((e.pageY - pos.top)/lineHeight); 27249 var top = pos.top + lineClicked * lineHeight; 27250 27251 tooltip.css({ 27252 top: top + 'px', 27253 left: pos.left + 'px' 27254 }); 27255 27256 $('.redactor-link-tooltip').remove(); 27257 $('body').append(tooltip); 27258 27259 this.core.editor().on('touchstart.redactor.' + this.uuid + ' click.redactor.' + this.uuid, $.proxy(this.observe.closeTooltip, this)); 27260 $(document).on('touchstart.redactor.' + this.uuid + ' click.redactor.' + this.uuid, $.proxy(this.observe.closeTooltip, this)); 27261 }, 27262 closeAllTooltip: function() 27263 { 27264 $('.redactor-link-tooltip').remove(); 27265 }, 27266 closeTooltip: function(e) 27267 { 27268 e = e.originalEvent || e; 27269 27270 var target = e.target; 27271 var $parent = $(target).closest('a', this.$editor[0]); 27272 if ($parent.length !== 0 && $parent[0].tagName === 'A' && target.tagName !== 'A') 27273 { 27274 return; 27275 } 27276 else if ((target.tagName === 'A' && this.utils.isRedactorParent(target)) || $(target).hasClass('redactor-link-tooltip-action')) 27277 { 27278 return; 27279 } 27280 27281 this.observe.closeAllTooltip(); 27282 27283 this.core.editor().off('touchstart.redactor.' + this.uuid + ' click.redactor.' + this.uuid, $.proxy(this.observe.closeTooltip, this)); 27284 $(document).off('touchstart.redactor.' + this.uuid + ' click.redactor.' + this.uuid, $.proxy(this.observe.closeTooltip, this)); 27285 } 27286 27287 }; 27288 }, 27289 27290 // =offset 27291 offset: function() 27292 { 27293 return { 27294 get: function(node) 27295 { 27296 var cloned = this.offset.clone(node); 27297 if (cloned === false) 27298 { 27299 return 0; 27300 } 27301 27302 var div = document.createElement('div'); 27303 div.appendChild(cloned.cloneContents()); 27304 div.innerHTML = div.innerHTML.replace(/<img(.*?[^>])>$/gi, 'i'); 27305 27306 var text = $.trim($(div).text()).replace(/[\t\n\r\n]/g, '').replace(/\u200B/g, ''); 27307 27308 return text.length; 27309 27310 }, 27311 clone: function(node) 27312 { 27313 var sel = this.selection.get(); 27314 var range = this.selection.range(sel); 27315 27316 if (range === null && typeof node === 'undefined') 27317 { 27318 return false;
27319 } 27320 27321 node = (typeof node === 'undefined') ? this.$editor : node; 27322 if (node === false) 27323 { 27324 return false; 27325 } 27326 27327 node = node[0] || node; 27328 27329 var cloned = range.cloneRange(); 27330 cloned.selectNodeContents(node); 27331 cloned.setEnd(range.endContainer, range.endOffset); 27332 27333 return cloned; 27334 }, 27335 set: function(start, end) 27336 { 27337 end = (typeof end === 'undefined') ? start : end; 27338 27339 if (!this.focus.is()) 27340 { 27341 this.focus.start(); 27342 } 27343 27344 var sel = this.selection.get(); 27345 var range = this.selection.range(sel); 27346 var node, offset = 0; 27347 var walker = document.createTreeWalker(this.$editor[0], NodeFilter.SHOW_TEXT, null, null); 27348 27349 while ((node = walker.nextNode()) !== null) 27350 { 27351 offset += node.nodeValue.length; 27352 if (offset > start) 27353 { 27354 range.setStart(node, node.nodeValue.length + start - offset); 27355 start = Infinity; 27356 } 27357 27358 if (offset >= end) 27359 { 27360 range.setEnd(node, node.nodeValue.length + end - offset); 27361 break; 27362 } 27363 } 27364 27365 range.collapse(false); 27366 this.selection.update(sel, range); 27367 } 27368 }; 27369 }, 27370 27371 // =paragraphize 27372 paragraphize: function() 27373 { 27374 return { 27375 load: function(html) 27376 { 27377 if (this.opts.paragraphize === false || this.opts.type === 'inline' || this.opts.type === 'pre') 27378 { 27379 return html; 27380 } 27381 27382 if (html === '' || html === '<p></p>') 27383 { 27384 return this.opts.emptyHtml; 27385 } 27386 27387 html = html + "\n"; 27388 27389 this.paragraphize.safes = []; 27390 this.paragraphize.z = 0; 27391 27392 // before 27393 html = html.replace(/(<br\s?\/?>){1,}\n?<\/blockquote>/gi, '</blockquote>'); 27394 html = html.replace(/<\/pre>/gi, "</pre>\n\n"); 27395 html = html.replace(/<p>\s<br><\/p>/gi, '<p></p>'); 27396 27397 html = this.paragraphize.getSafes(html); 27398 27399 html = html.replace('<br>', "\n"); 27400 html = this.paragraphize.convert(html); 27401 27402 html = this.paragraphize.clear(html); 27403 html = this.paragraphize.restoreSafes(html); 27404 27405 // after 27406 html = html.replace(new RegExp('<br\\s?/?>\n?<(' + this.opts.paragraphizeBlocks.join('|') + ')(.*?[^>])>', 'gi'), '<p><br /></p>\n<$1$2>'); 27407 27408 return $.trim(html); 27409 }, 27410 getSafes: function(html) 27411 { 27412 var $div = $('<div />').append(html); 27413 27414 // remove paragraphs in blockquotes 27415 $div.find('blockquote p').replaceWith(function() 27416 { 27417 return $(this).append('<br />').contents(); 27418 }); 27419 27420 $div.find(this.opts.paragraphizeBlocks.join(', ')).each($.proxy(function(i,s) 27421 { 27422 this.paragraphize.z++; 27423 this.paragraphize.safes[this.paragraphize.z] = s.outerHTML; 27424 27425 return $(s).replaceWith("\n#####replace" + this.paragraphize.z + "#####\n\n"); 27426 27427 27428 }, this)); 27429 27430 // deal with redactor selection markers 27431 $div.find('span.redactor-selection-marker').each($.proxy(function(i,s) 27432 { 27433 this.paragraphize.z++; 27434 this.paragraphize.safes[this.paragraphize.z] = s.outerHTML; 27435 27436 return $(s).replaceWith("\n#####replace" + this.paragraphize.z + "#####\n\n"); 27437 }, this)); 27438 27439 return $div.html(); 27440 }, 27441 restoreSafes: function(html) 27442 { 27443 $.each(this.paragraphize.safes, function(i,s) 27444 { 27445 s = (typeof s !== 'undefined') ? s.replace(/\$/g, '$') : s; 27446 html = html.replace('#####replace' + i + '#####', s); 27447 27448 }); 27449 27450 return html; 27451 }, 27452 convert: function(html) 27453 { 27454 html = html.replace(/\r\n/g, "xparagraphmarkerz"); 27455 html = html.replace(/\n/g, "xparagraphmarkerz"); 27456 html = html.replace(/\r/g, "xparagraphmarkerz"); 27457 27458 var re1 = /\s+/g; 27459 html = html.replace(re1, " "); 27460 html = $.trim(html); 27461 27462 var re2 = /xparagraphmarkerzxparagraphmarkerz/gi; 27463 html = html.replace(re2, "</p><p>"); 27464 27465 var re3 = /xparagraphmarkerz/gi; 27466 html = html.replace(re3, "<br>"); 27467 27468 html = '<p>' + html + '</p>'; 27469 27470 html = html.replace("<p></p>", ""); 27471 html = html.replace("\r\n\r\n", ""); 27472 html = html.replace(/<\/p><p>/g, "</p>\r\n\r\n<p>"); 27473 html = html.replace(new RegExp("<br\\s?/?></p>", "g"), "</p>"); 27474 html = html.replace(new RegExp("<p><br\\s?/?>", "g"), "<p>"); 27475 html = html.replace(new RegExp("<p><br\\s?/?>", "g"), "<p>"); 27476 html = html.replace(new RegExp("<br\\s?/?></p>", "g"), "</p>"); 27477 html = html.replace(/<p> <\/p>/gi, ""); 27478 html = html.replace(/<p>\s?<br> <\/p>/gi, ''); 27479 html = html.replace(/<p>\s?<br>/gi, '<p>'); 27480 27481 return html; 27482 }, 27483 clear: function(html) 27484 { 27485 27486 html = html.replace(/<p>(.*?)#####replace(.*?)#####\s?<\/p>/gi, '<p>$1</p>#####replace$2#####'); 27487 html = html.replace(/(<br\s?\/?>){2,}<\/p>/gi, '</p>'); 27488 27489 html = html.replace(new RegExp('</blockquote></p>', 'gi'), '</blockquote>'); 27490 html = html.replace(new RegExp('<p></blockquote>', 'gi'), '</blockquote>'); 27491 html = html.replace(new RegExp('<p><blockquote>', 'gi'), '<blockquote>'); 27492 html = html.replace(new RegExp('<blockquote></p>', 'gi'), '<blockquote>'); 27493 27494 html = html.replace(new RegExp('<p><p ', 'gi'), '<p '); 27495 html = html.replace(new RegExp('<p><p>
27495', 'gi'), '<p>'); 27496 html = html.replace(new RegExp('</p></p>', 'gi'), '</p>'); 27497 html = html.replace(new RegExp('<p>\\s?</p>', 'gi'), ''); 27498 html = html.replace(new RegExp("\n</p>", 'gi'), '</p>'); 27499 html = html.replace(new RegExp('<p>\t?\t?\n?<p>', 'gi'), '<p>'); 27500 html = html.replace(new RegExp('<p>\t*</p>', 'gi'), ''); 27501 27502 return html; 27503 } 27504 }; 27505 }, 27506 27507 // =paste 27508 paste: function() 27509 { 27510 return { 27511 init: function(e) 27512 { 27513 this.rtePaste = true; 27514 var pre = (this.opts.type === 'pre' || this.utils.isCurrentOrParent('pre')) ? true : false; 27515 27516 // clipboard event 27517 if (this.detect.isDesktop()) 27518 { 27519 27520 if (!this.paste.pre && this.opts.clipboardImageUpload && this.opts.imageUpload && this.paste.detectClipboardUpload(e)) 27521 { 27522 if (this.detect.isIe()) 27523 { 27524 setTimeout($.proxy(this.paste.clipboardUpload, this), 100); 27525 } 27526 27527 return; 27528 } 27529 } 27530 27531 this.utils.saveScroll(); 27532 this.selection.save(); 27533 this.paste.createPasteBox(pre); 27534 27535 $(window).on('scroll.redactor-freeze', $.proxy(function() 27536 { 27537 $(window).scrollTop(this.saveBodyScroll); 27538 27539 }, this)); 27540 27541 setTimeout($.proxy(function() 27542 { 27543 var html = this.paste.getPasteBoxCode(pre); 27544 27545 // buffer 27546 this.buffer.set(); 27547 this.selection.restore(); 27548 27549 this.utils.restoreScroll(); 27550 27551 // paste info 27552 var data = this.clean.getCurrentType(html); 27553 27554 // clean 27555 html = this.clean.onPaste(html, data); 27556 27557 // callback 27558 var returned = this.core.callback('paste', html); 27559 html = (typeof returned === 'undefined') ? html : returned; 27560 27561 this.paste.insert(html, data); 27562 this.rtePaste = false; 27563 27564 // clean pre breaklines 27565 if (pre) 27566 { 27567 this.clean.cleanPre(); 27568 } 27569 27570 $(window).off('scroll.redactor-freeze'); 27571 27572 }, this), 1); 27573 27574 }, 27575 getPasteBoxCode: function(pre) 27576 { 27577 var html = (pre) ? this.$pasteBox.val() : this.$pasteBox.html(); 27578 this.$pasteBox.remove(); 27579 27580 return html; 27581 }, 27582 createPasteBox: function(pre) 27583 { 27584 var css = { position: 'fixed', width: '1px', top: 0, left: '-9999px' }; 27585 27586 this.$pasteBox = (pre) ? $('<textarea>').css(css) : $('<div>').attr('contenteditable', 'true').css(css); 27587 this.paste.appendPasteBox(); 27588 this.$pasteBox.focus(); 27589 }, 27590 appendPasteBox: function() 27591 { 27592 if (this.detect.isIe()) 27593 { 27594 this.core.box().append(this.$pasteBox); 27595 } 27596 else 27597 { 27598 // bootstrap modal 27599 var $visibleModals = $('.modal-body:visible'); 27600 if ($visibleModals.length > 0) 27601 { 27602 $visibleModals.append(this.$pasteBox); 27603 } 27604 else 27605 { 27606 $('body').prepend(this.$pasteBox); 27607 } 27608 } 27609 }, 27610 detectClipboardUpload: function(e) 27611 { 27612 e = e.originalEvent || e; 27613 27614 var clipboard = e.clipboardData; 27615 if (this.detect.isIe() || this.detect.isFirefox()) 27616 { 27617 return false; 27618 } 27619 27620 // prevent safari fake url 27621 var types = clipboard.types; 27622 if (types.indexOf('public.tiff') !== -1) 27623 { 27624 e.preventDefault(); 27625 return false; 27626 } 27627 27628 if (!clipboard.items || !clipboard.items.length) 27629 { 27630 return; 27631 } 27632 27633 var file = clipboard.items[0].getAsFile(); 27634 if (file === null) 27635 { 27636 return false; 27637 } 27638 27639 var reader = new FileReader(); 27640 reader.readAsDataURL(file); 27641 reader.onload = $.proxy(this.paste.insertFromClipboard, this); 27642 27643 return true; 27644 }, 27645 clipboardUpload: function() 27646 { 27647 var imgs = this.$editor.find('img'); 27648 $.each(imgs, $.proxy(function(i,s) 27649 { 27650 if (s.src.search(/^data\:image/i) === -1) 27651 { 27652 return; 27653 } 27654 27655 var formData = !!window.FormData ? new FormData() : null; 27656 if (!window.FormData) 27657 { 27658 return; 27659 } 27660 27661 this.upload.direct = true; 27662 this.upload.type = 'image'; 27663 this.upload.url = this.opts.imageUpload; 27664 this.upload.callback = $.proxy(function(data) 27665 { 27666 if (this.detect.isIe()) 27667 { 27668 $(s).wrap($('<figure />')); 27669 } 27670 27671 else 27672 { 27673 var $parent = $(s).parent(); 27674 this.utils.replaceToTag($parent, 'figure'); 27675 } 27676 27677 s.src = data.url; 27678 this.core.callback('imageUpload', $(s), data); 27679 27680 }, this); 27681 27682 var blob = this.utils.dataURItoBlob(s.src); 27683 27684 formData.append('clipboard', 1); 27685 formData.append(this.opts.imageUploadParam, blob); 27686 27687 this.progress.show(); 27688 this.upload.send(formData, false); 27689 this.code.sync(); 27690 this.rtePaste = false;
27691 27692 }, this)); 27693 }, 27694 insertFromClipboard: function(e) 27695 { 27696 var formData = !!window.FormData ? new FormData() : null; 27697 if (!window.FormData) 27698 { 27699 return; 27700 } 27701 27702 this.upload.direct = true; 27703 this.upload.type = 'image'; 27704 this.upload.url = this.opts.imageUpload; 27705 this.upload.callback = this.image.insert; 27706 27707 var blob = this.utils.dataURItoBlob(e.target.result); 27708 27709 formData.append('clipboard', 1); 27710 formData.append(this.opts.imageUploadParam, blob); 27711 27712 this.progress.show(); 27713 this.upload.send(formData, e); 27714 this.rtePaste = false; 27715 }, 27716 insert: function(html, data) 27717 { 27718 if (data.pre) 27719 { 27720 this.insert.raw(html); 27721 } 27722 else if (data.text) 27723 { 27724 this.insert.text(html); 27725 } 27726 else 27727 { 27728 this.insert.html(html, data); 27729 } 27730 27731 // Firefox Clipboard Observe 27732 if (this.detect.isFirefox() && this.opts.imageUpload && this.opts.clipboardImageUpload) 27733 { 27734 setTimeout($.proxy(this.paste.clipboardUpload, this), 100); 27735 } 27736 27737 } 27738 }; 27739 }, 27740 27741 // =placeholder 27742 placeholder: function() 27743 { 27744 return { 27745 27746 // public 27747 enable: function() 27748 { 27749 setTimeout($.proxy(function() 27750 { 27751 return (this.placeholder.isEditorEmpty()) ? this.placeholder.show() : this.placeholder.hide(); 27752 27753 }, this), 5); 27754 }, 27755 show: function() 27756 { 27757 this.core.editor().addClass('redactor-placeholder'); 27758 }, 27759 update: function(text) 27760 { 27761 this.opts.placeholder = text; 27762 this.core.editor().attr('placeholder', text); 27763 }, 27764 hide: function() 27765 { 27766 this.core.editor().removeClass('redactor-placeholder'); 27767 }, 27768 is: function() 27769 { 27770 return this.core.editor().hasClass('redactor-placeholder'); 27771 }, 27772 27773 27774 // private 27775 init: function() 27776 { 27777 if (!this.placeholder.enabled()) 27778 { 27779 return; 27780 } 27781 27782 if (!this.utils.isEditorRelative()) 27783 { 27784 this.utils.setEditorRelative(); 27785 } 27786 27787 this.placeholder.build(); 27788 this.placeholder.buildPosition(); 27789 this.placeholder.enable(); 27790 this.placeholder.enableEvents(); 27791 27792 }, 27793 enabled: function() 27794 { 27795 return (this.opts.placeholder) ? this.core.element().attr('placeholder', this.opts.placeholder) : this.placeholder.isAttr(); 27796 }, 27797 enableEvents: function() 27798 { 27799 this.core.editor().on('keydown.redactor-placeholder.' + this.uuid, $.proxy(this.placeholder.enable, this)); 27800 }, 27801 disableEvents: function() 27802 { 27803 this.core.editor().off('.redactor-placeholder.' + this.uuid); 27804 }, 27805 build: function() 27806 { 27807 this.core.editor().attr('placeholder', this.core.element().attr('placeholder')); 27808 }, 27809 buildPosition: function() 27810 { 27811 var $style = $('<style />'); 27812 $style.addClass('redactor-placeholder-style-tag'); 27813 $style.html('#' + this.core.id() + '.redactor-placeholder::after ' + this.placeholder.getPosition()); 27814 27815 $('head').append($style); 27816 }, 27817 getPosition: function() 27818 { 27819 return '{ top: ' + this.core.editor().css('padding-top') + '; left: ' + this.core.editor().css('padding-left') + '; }'; 27820 }, 27821 isEditorEmpty: function() 27822 { 27823 var html = $.trim(this.core.editor().html()).replace(/[\t\n]/g, ''); 27824 var states = ['', '<p>â</p>', '<p>â<br></p>', this.opts.emptyHtmlRendered]; 27825 27826 return ($.inArray(html, states) !== -1); 27827 }, 27828 isAttr: function() 27829 { 27830 return (typeof this.core.element().attr('placeholder') !== 'undefined' && this.core.element().attr('placeholder') !== ''); 27831 }, 27832 destroy: function() 27833 { 27834 this.core.editor().removeAttr('placeholder'); 27835 27836 this.placeholder.hide(); 27837 this.placeholder.disableEvents(); 27838 27839 $('.redactor-placeholder-style-tag').remove(); 27840 } 27841 }; 27842 }, 27843 27844 // =progress 27845 progress: function() 27846 { 27847 return { 27848 $box: null, 27849 $bar: null, 27850 target: document.body, // or id selector 27851 27852 // public 27853 show: function() 27854 { 27855 if (!this.progress.is()) 27856 { 27857 this.progress.build(); 27858 this.progress.$box.redactorAnimation('fadeIn'); 27859 } 27860 else 27861 { 27862 this.progress.$box.show(); 27863 } 27864 }, 27865 hide: function() 27866 { 27867 if (this.progress.is()) 27868 { 27869 this.progress.$box.redactorAnimation('fadeOut', { duration: 0.35 }, $.proxy(this.progress.destroy, this)); 27870 } 27871 }, 27872 update: function(value) 27873 { 27874 this.progress.show(); 27875 this.progress.$bar.css('width', value + '%'); 27876 }, 27877 is: function() 27878 { 27879 return (this.progress.$box === null) ? false : true; 27880 }, 27881 27882 // private 27883 build: function() 27884 { 27885 this.progress.$bar = $('<span />'); 27886 this.progress.$box = $('<div id="redactor-progress" />'); 27887 27888 this.progress.$box.append(this.progress.$bar); 27889 $(this.progress.target).append(this.progress.$box); 27890 }, 27891 destroy: function() 27892 { 27893 if (this.progress.is()) 27894 { 27895 this.progress.$box.remove(); 27896 } 27897 27898 this.progress.$box = null; 27899 this.progress.$bar = null; 27900 } 27901 }; 27902 }, 27903 27904 // =selection 27905 selection: function() 27906 { 27907 return { 27908 get: function() 27909 { 27910 if (window.getSelection) 27911 { 27912 return window.getSelection(); 27913 } 27914 else if (document.selection && document.selection.type !== "Control") 27915 { 27916 return document.selection; 27917 } 27918 27919 return null; 27920 }, 27921 range: function(sel) 27922 { 27923 if (typeof sel === 'undefined') 27924 { 27925 sel = this.selection.get(); 27926 } 27927 27928 if (sel.getRangeAt && sel.rangeCount) 27929 { 27930 return sel.getRangeAt(0); 27931 } 27932 27933 return null; 27934 }, 27935 is: function() 27936 { 27937 return (this.selection.isCollapsed()) ? false : true; 27938 }, 27939 isRedactor: function() 27940 { 27941 var range = this.selection.range(); 27942 27943 if (range !== null) 27944 { 27945 var el = range.startContainer.parentNode; 27946 27947 if ($(el).hasClass('redactor-in') || $(el).parents('.redactor-in').length !== 0) 27948 { 27949 return true; 27950 } 27951 } 27952 27953 return false;
27954 }, 27955 isCollapsed: function() 27956 { 27957 var sel = this.selection.get(); 27958 27959 return (sel === null) ? false : sel.isCollapsed; 27960 }, 27961 update: function(sel, range) 27962 { 27963 if (range === null) 27964 { 27965 return; 27966 } 27967 27968 sel.removeAllRanges(); 27969 sel.addRange(range); 27970 }, 27971 current: function() 27972 { 27973 var sel = this.selection.get(); 27974 27975 return (sel === null) ? false : sel.anchorNode; 27976 }, 27977 parent: function() 27978 { 27979 var current = this.selection.current(); 27980 27981 return (current === null) ? false : current.parentNode; 27982 }, 27983 block: function(node) 27984 { 27985 node = node || this.selection.current(); 27986 27987 while (node) 27988 { 27989 if (this.utils.isBlockTag(node.tagName)) 27990 { 27991 return ($(node).hasClass('redactor-in')) ? false : node; 27992 } 27993 27994 node = node.parentNode; 27995 } 27996 27997 return false; 27998 }, 27999 inline: function(node) 28000 { 28001 node = node || this.selection.current(); 28002 28003 while (node) 28004 { 28005 if (this.utils.isInlineTag(node.tagName)) 28006 { 28007 return ($(node).hasClass('redactor-in')) ? false : node; 28008 } 28009 28010 node = node.parentNode; 28011 } 28012 28013 return false; 28014 }, 28015 element: function(node) 28016 { 28017 if (!node) 28018 { 28019 node = this.selection.current(); 28020 } 28021 28022 while (node) 28023 { 28024 if (node.nodeType === 1) 28025 { 28026 if ($(node).hasClass('redactor-in')) 28027 { 28028 return false; 28029 } 28030 28031 return node; 28032 } 28033 28034 node = node.parentNode; 28035 } 28036 28037 return false; 28038 }, 28039 prev: function() 28040 { 28041 var current = this.selection.current(); 28042 28043 return (current === null) ? false : this.selection.current().previousSibling; 28044 }, 28045 next: function() 28046 { 28047 var current = this.selection.current(); 28048 28049 return (current === null) ? false : this.selection.current().nextSibling; 28050 }, 28051 blocks: function(tag) 28052 { 28053 var blocks = []; 28054 var nodes = this.selection.nodes(tag); 28055 28056 $.each(nodes, $.proxy(function(i,node) 28057 { 28058 if (this.utils.isBlock(node)) 28059 { 28060 blocks.push(node); 28061 } 28062 28063 }, this)); 28064 28065 var block = this.selection.block(); 28066 if (blocks.length === 0 && block === false) 28067 { 28068 return []; 28069 } 28070 else if (blocks.length === 0 && block !== false) 28071 { 28072 return [block]; 28073 } 28074 else 28075 { 28076 return blocks; 28077 } 28078 28079 }, 28080 inlines: function(tag) 28081 { 28082 var inlines = []; 28083 var nodes = this.selection.nodes(tag); 28084 28085 $.each(nodes, $.proxy(function(i,node) 28086 { 28087 if (this.utils.isInline(node)) 28088 { 28089 inlines.push(node); 28090 } 28091 28092 }, this)); 28093 28094 var inline = this.selection.inline(); 28095 if (inlines.length === 0 && inline === false) 28096 { 28097 return []; 28098 } 28099 else if (inlines.length === 0 && inline !== false) 28100 { 28101 return [inline]; 28102 } 28103 else 28104 { 28105 return inlines; 28106 } 28107 }, 28108 nodes: function(tag) 28109 { 28110 var filter = (typeof tag === 'undefined') ? [] : (($.isArray(tag)) ? tag : [tag]); 28111 28112 var sel = this.selection.get(); 28113 var range = this.selection.range(sel); 28114 var nodes = []; 28115 var resultNodes = []; 28116 28117 if (this.utils.isCollapsed()) 28118 { 28119 nodes = [this.selection.current()]; 28120 } 28121 else 28122 { 28123 var node = range.startContainer; 28124 var endNode = range.endContainer; 28125 28126 // single node 28127 if (node === endNode) 28128 { 28129 return [node]; 28130 } 28131 28132 // iterate 28133 while (node && node !== endNode) 28134 { 28135 nodes.push(node = this.selection.nextNode(node)); 28136 } 28137 28138 // partially selected nodes 28139 node = range.startContainer; 28140 while (node && node !== range.commonAncestorContainer) 28141 { 28142 nodes.unshift(node); 28143 node = node.parentNode; 28144 } 28145 } 28146 28147 // remove service nodes 28148 $.each(nodes, function(i,s) 28149 { 28150 if (s) 28151 { 28152 var tagName = (s.nodeType !== 1) ? false : s.tagName.toLowerCase(); 28153 28154 if ($(s).hasClass('redactor-script-tag') || $(s).hasClass('redactor-selection-marker')) 28155 { 28156 return; 28157 } 28158 else if (tagName && filter.length !== 0 && $.inArray(tagName, filter) === -1) 28159 { 28160 return; 28161 } 28162 else 28163 { 28164 resultNodes.push(s); 28165 } 28166 } 28167 }); 28168 28169 return (resultNodes.length === 0) ? [] : resultNodes; 28170 }, 28171 nextNode: function(node) 28172 { 28173 if (node.hasChildNodes()) 28174 { 28175 return node.firstChild; 28176 } 28177 else 28178 { 28179 while (node && !node.nextSibling) 28180 { 28181 node = node.parentNode; 28182 } 28183 28184 if (!node) 28185 { 28186 return null; 28187 } 28188 28189 return node.nextSibling; 28190 } 28191 }, 28192 save: function() 28193 { 28194 this.marker.insert(); 28195 this.savedSel = this.core.editor().html(); 28196 }, 28197 restore: function(removeMarkers) 28198 { 28199 var node1 = this.marker.find(1); 28200 var node2 = this.marker.find(2); 28201 28202 if (this.detect.isFirefox()) 28203 { 28204 this.core.editor().focus(); 28205 } 28206 28207 if (node1.length !== 0 && node2.length !== 0) 28208 { 28209 this.caret.set(node1, node2); 28210 } 28211 else if (node1.length !== 0) 28212 { 28213 this.caret.start(node1); 28214 } 28215 else 28216 { 28217 this.core.editor().focus(); 28218 } 28219 28220 if (removeMarkers !== false) 28221 { 28222 this.marker.remove(); 28223 this.savedSel = false;
28224 } 28225 }, 28226 saveInstant: function() 28227 { 28228 var el = this.core.editor()[0]; 28229 var doc = el.ownerDocument, win = doc.defaultView; 28230 var sel = win.getSelection(); 28231 28232 if (!sel.getRangeAt || !sel.rangeCount) 28233 { 28234 return; 28235 } 28236 28237 var range = sel.getRangeAt(0); 28238 var selectionRange = range.cloneRange(); 28239 28240 selectionRange.selectNodeContents(el); 28241 selectionRange.setEnd(range.startContainer, range.startOffset); 28242 28243 var start = selectionRange.toString().length; 28244 28245 this.saved = { 28246 start: start, 28247 end: start + range.toString().length, 28248 node: range.startContainer 28249 }; 28250 28251 return this.saved; 28252 }, 28253 restoreInstant: function(saved) 28254 { 28255 if (typeof saved === 'undefined' && !this.saved) 28256 { 28257 return; 28258 } 28259 28260 this.saved = (typeof saved !== 'undefined') ? saved : this.saved; 28261 28262 var $node = this.core.editor().find(this.saved.node); 28263 if ($node.length !== 0 && $node.text().trim().replace(/\u200B/g, '').length === 0) 28264 { 28265 try { 28266 var range = document.createRange(); 28267 range.setStart($node[0], 0); 28268 28269 var sel = window.getSelection(); 28270 sel.removeAllRanges(); 28271 sel.addRange(range); 28272 } 28273 catch(e) {} 28274 28275 return; 28276 } 28277 28278 var el = this.core.editor()[0]; 28279 var doc = el.ownerDocument, win = doc.defaultView; 28280 var charIndex = 0, range = doc.createRange(); 28281 28282 range.setStart(el, 0); 28283 range.collapse(true); 28284 28285 var nodeStack = [el], node, foundStart = false, stop = false; 28286 while (!stop && (node = nodeStack.pop())) 28287 { 28288 if (node.nodeType == 3) 28289 { 28290 var nextCharIndex = charIndex + node.length; 28291 if (!foundStart && this.saved.start >= charIndex && this.saved.start <= nextCharIndex) 28292 { 28293 range.setStart(node, this.saved.start - charIndex); 28294 foundStart = true; 28295 } 28296 28297 if (foundStart && this.saved.end >= charIndex && this.saved.end <= nextCharIndex) 28298 { 28299 range.setEnd(node, this.saved.end - charIndex); 28300 stop = true; 28301 } 28302 charIndex = nextCharIndex; 28303 } 28304 else 28305 { 28306 var i = node.childNodes.length; 28307 while (i--) 28308 { 28309 nodeStack.push(node.childNodes[i]); 28310 } 28311 } 28312 } 28313 28314 var sel = win.getSelection(); 28315 sel.removeAllRanges(); 28316 sel.addRange(range); 28317 }, 28318 node: function(node) 28319 { 28320 $(node).prepend(this.marker.get(1)); 28321 $(node).append(this.marker.get(2)); 28322 28323 this.selection.restore(); 28324 }, 28325 all: function() 28326 { 28327 this.core.editor().focus(); 28328 28329 var sel = this.selection.get(); 28330 var range = this.selection.range(sel); 28331 28332 range.selectNodeContents(this.core.editor()[0]); 28333 28334 this.selection.update(sel, range); 28335 }, 28336 remove: function() 28337 { 28338 this.selection.get().removeAllRanges(); 28339 }, 28340 replace: function(html) 28341 { 28342 this.insert.html(html); 28343 }, 28344 text: function() 28345 { 28346 return this.selection.get().toString(); 28347 }, 28348 html: function() 28349 { 28350 var html = ''; 28351 var sel = this.selection.get(); 28352 28353 if (sel.rangeCount) 28354 { 28355 var container = document.createElement('div'); 28356 var len = sel.rangeCount; 28357 for (var i = 0; i < len; ++i) 28358 { 28359 container.appendChild(sel.getRangeAt(i).cloneContents()); 28360 } 28361 28362 html = this.clean.onGet(container.innerHTML); 28363 } 28364 28365 return html; 28366 }, 28367 extractEndOfNode: function(node) 28368 { 28369 var sel = this.selection.get(); 28370 var range = this.selection.range(sel); 28371 28372 var clonedRange = range.cloneRange(); 28373 clonedRange.selectNodeContents(node); 28374 clonedRange.setStart(range.endContainer, range.endOffset); 28375 28376 return clonedRange.extractContents(); 28377 }, 28378 28379 // #backward 28380 removeMarkers: function() 28381 { 28382 this.marker.remove(); 28383 }, 28384 marker: function(num) 28385 { 28386 return this.marker.get(num); 28387 }, 28388 markerHtml: function(num) 28389 { 28390 return this.marker.html(num); 28391 } 28392 28393 }; 28394 }, 28395 28396 // =shortcuts 28397 shortcuts: function() 28398 { 28399 return { 28400 // based on https://github.com/jeresig/jquery.hotkeys 28401 hotkeysSpecialKeys: { 28402 8: "backspace", 9: "tab", 10: "return", 13: "return", 16: "shift", 17: "ctrl", 18: "alt", 19: "pause", 28403 20: "capslock", 27: "esc", 32: "space", 33: "pageup", 34: "pagedown", 35: "end", 36: "home", 28404 37: "left", 38: "up", 39: "right", 40: "down", 45: "insert", 46: "del", 59: ";", 61: "=", 28405 96: "0", 97: "1", 98: "2", 99: "3", 100: "4", 101: "5", 102: "6", 103: "7", 28406 104: "8", 105: "9", 106: "*", 107: "+", 109: "-", 110: ".", 111 : "/", 28407 112: "f1", 113: "f2", 114: "f3", 115: "f4", 116: "f5", 117: "f6", 118: "f7", 119: "f8", 28408 120: "f9", 121: "f10", 122: "f11", 123: "f12", 144: "numlock", 145: "scroll", 173: "-", 186: ";", 187: "=", 28409 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\", 221: "]", 222: "'" 28410 }, 28411 hotkeysShiftNums: { 28412 "`": "~", "1": "!", "2": "@", "3": "#", "4": "$", "5": "%", "6": "^", "7": "&", 28413 "8": "*", "9": "(", "0": ")", "-": "_", "=": "+", ";": ": ", "'": "\"", ",": "<", 28414 ".": ">", "/": "?", "\\": "|" 28415 }, 28416 init: function(e, key) 28417 { 28418 // disable browser's hot keys for bold and italic if shortcuts off 28419 if (this.opts.shortcuts === false) 28420 { 28421 if ((e.ctrlKey || e.metaKey) && (key === 66 || key === 73)) 28422 { 28423 e.preventDefault(); 28424 } 28425 28426 return false;
28427 } 28428 else 28429 { 28430 // build 28431 $.each(this.opts.shortcuts, $.proxy(function(str, command) 28432 { 28433 this.shortcuts.build(e, str, command); 28434 28435 }, this)); 28436 } 28437 }, 28438 build: function(e, str, command) 28439 { 28440 var handler = $.proxy(function() 28441 { 28442 this.shortcuts.buildHandler(command); 28443 28444 }, this); 28445 28446 var keys = str.split(','); 28447 var len = keys.length; 28448 for (var i = 0; i < len; i++) 28449 { 28450 if (typeof keys[i] === 'string') 28451 { 28452 this.shortcuts.handler(e, $.trim(keys[i]), handler); 28453 } 28454 } 28455 28456 }, 28457 buildHandler: function(command) 28458 { 28459 var func; 28460 if (command.func.search(/\./) !== '-1') 28461 { 28462 func = command.func.split('.'); 28463 if (typeof this[func[0]] !== 'undefined') 28464 { 28465 this[func[0]][func[1]].apply(this, command.params); 28466 } 28467 } 28468 else 28469 { 28470 this[command.func].apply(this, command.params); 28471 } 28472 }, 28473 handler: function(e, keys, origHandler) 28474 { 28475 keys = keys.toLowerCase().split(" "); 28476 28477 var special = this.shortcuts.hotkeysSpecialKeys[e.keyCode]; 28478 var character = String.fromCharCode(e.which).toLowerCase(); 28479 var modif = "", possible = {}; 28480 28481 $.each([ "alt", "ctrl", "meta", "shift"], function(index, specialKey) 28482 { 28483 if (e[specialKey + 'Key'] && special !== specialKey) 28484 { 28485 modif += specialKey + '+'; 28486 } 28487 }); 28488 28489 28490 if (special) 28491 { 28492 possible[modif + special] = true; 28493 } 28494 28495 if (character) 28496 { 28497 possible[modif + character] = true; 28498 possible[modif + this.shortcuts.hotkeysShiftNums[character]] = true; 28499 28500 // "$" can be triggered as "Shift+4" or "Shift+$" or just "$" 28501 if (modif === "shift+") 28502 { 28503 possible[this.shortcuts.hotkeysShiftNums[character]] = true; 28504 } 28505 } 28506 28507 var len = keys.length; 28508 for (var i = 0; i < len; i++) 28509 { 28510 if (possible[keys[i]]) 28511 { 28512 e.preventDefault(); 28513 return origHandler.apply(this, arguments); 28514 } 28515 } 28516 } 28517 }; 28518 }, 28519 28520 // =storage 28521 storage: function() 28522 { 28523 return { 28524 data: [], 28525 add: function(data) 28526 { 28527 // type, node, url, id 28528 data.status = true; 28529 data.url = decodeURI(data.url); 28530 28531 this.storage.data[data.url] = data; 28532 }, 28533 status: function(url, status) 28534 { 28535 this.storage.data[decodeURI(url)].status = status; 28536 }, 28537 observe: function() 28538 { 28539 var _this = this; 28540 28541 var $images = this.core.editor().find('[data-image]'); 28542 $images.each(function(i, s) 28543 { 28544 _this.storage.add({ type: 'image', node: s, url: s.src, id: $(s).attr('data-image') }); 28545 }); 28546 28547 var $files = this.core.editor().find('[data-file]'); 28548 $files.each(function(i, s) 28549 { 28550 _this.storage.add({ type: 'file', node: s, url: s.href, id: $(s).attr('data-file') }); 28551 }); 28552 28553 var $s3 = this.core.editor().find('[data-s3]'); 28554 $s3.each(function(i, s) 28555 { 28556 var url = (s.tagName === 'IMG') ? s.src : s.href; 28557 _this.storage.add({ type: 's3', node: s, url: url, id: $(s).attr('data-s3') }); 28558 }); 28559 28560 }, 28561 changes: function() 28562 { 28563 for (var key in this.storage.data) 28564 { 28565 var data = this.storage.data[key]; 28566 var attr = (data.node.tagName === 'IMG') ? 'src' : 'href'; 28567 var $el = this.core.editor().find('[data-' + data.type + '][' + attr + '="' + data.url + '"]'); 28568 28569 if ($el.length === 0) 28570 { 28571 this.storage.status(data.url, false); 28572 } 28573 else 28574 { 28575 this.storage.status(data.url, true); 28576 } 28577 } 28578 28579 28580 return this.storage.data; 28581 } 28582 28583 }; 28584 }, 28585 28586 // =toolbar 28587 toolbar: function() 28588 { 28589 return { 28590 build: function() 28591 { 28592 this.button.hideButtons(); 28593 this.button.hideButtonsOnMobile(); 28594 28595 this.$toolbarBox = $('<div />').addClass('redactor-toolbar-box'); 28596 this.$toolbar = this.toolbar.createContainer(); 28597 this.$toolbarBox.append(this.$toolbar); 28598 28599 this.toolbar.append(); 28600 this.button.$toolbar = this.$toolbar; 28601 this.button.setFormatting(); 28602 this.button.load(this.$toolbar); 28603 28604 this.toolbar.setOverflow(); 28605 this.toolbar.setFixed(); 28606 28607 }, 28608 createContainer: function() 28609 { 28610 return $('<ul>').addClass('redactor-toolbar').attr({ 'id': 'redactor-toolbar-' + this.uuid, 'role': 'toolbar' }); 28611 }, 28612 append: function() 28613 { 28614 if (this.opts.toolbarExternal) 28615 { 28616 this.$toolbar.addClass('redactor-toolbar-external'); 28617 $(this.opts.toolbarExternal).html(this.$toolbarBox); 28618 } 28619 else 28620 { 28621 if (this.opts.type === 'textarea') 28622 { 28623 this.$box.prepend(this.$toolbarBox); 28624 } 28625 else 28626 { 28627 this.$element.before(this.$toolbarBox); 28628 } 28629 28630 } 28631 }, 28632 setOverflow: function() 28633 { 28634 if (this.opts.toolbarOverflow) 28635 { 28636 this.$toolbar.addClass('redactor-toolbar-overflow'); 28637 } 28638 }, 28639 setFixed: function() 28640 { 28641 if (!this.opts.toolbarFixed || this.opts.toolbarExternal) 28642 { 28643 return; 28644 } 28645 28646 if (this.opts.toolbarFixedTarget !== document) 28647 { 28648 var $el = $(this.opts.toolbarFixedTarget); 28649 this.toolbar.toolbarOffsetTop = ($el.length === 0) ? 0 : this.core.box().offset().top - $el.offset().top; 28650 } 28651 28652 // bootstrap modal fix 28653 var late = (this.core.box().closest('.modal-body').length !== 0) ? 1000 : 0; 28654 28655 setTimeout($.proxy(function() 28656 { 28657 var self = this; 28658 this.toolbar.observeScroll(false); 28659 if (this.detect.isDesktop()) 28660 { 28661 $(this.opts.toolbarFixedTarget).on('scroll.redactor.' + this.uuid, function() 28662 { 28663 if (self.core.editor().height() < 100 || self.placeholder.isEditorEmpty()) 28664 { 28665 return; 28666 } 28667 28668 self.toolbar.observeScroll(); 28669 }); 28670 } 28671 else 28672 { 28673 $(this.opts.toolbarFixedTarget).on('scroll.redactor.' + this.uuid, function() 28674 { 28675 if (self.core.editor().height() < 100 || self.placeholder.isEditorEmpty()) 28676 { 28677 return; 28678 } 28679 28680 self.core.toolbar().hide(); 28681 clearTimeout($.data(this, "scrollCheck")); 28682 $.data(this, "scrollCheck", setTimeout(function() 28683 { 28684 self.core.toolbar().show(); 28685 self.toolbar.observeScroll(); 28686 }, 250) ); 28687 28688 }); 28689 } 28690 28691 }, this), late); 28692 28693 }, 28694 setUnfixed: function() 28695 { 28696 this.toolbar.observeScrollDisable(); 28697 }, 28698 getBoxTop: function() 28699 { 28700 return (this.opts.toolbarFixedTarget === document) ? this.core.box().offset().top : this.toolbar.toolbarOffsetTop; 28701 }, 28702 observeScroll: function(start) 28703 { 28704 // tolerance 0 if redactor in the hidden layer 28705 var tolerance = 0; 28706 28707 if (start !== false) 28708 { 28709 tolerance = (this.opts.toolbarFixedTarget === document) ? 20 : 0; 28710 } 28711 28712 var scrollTop = $(this.opts.toolbarFixedTarget).scrollTop(); 28713 var boxTop = this.toolbar.getBoxTop(); 28714 28715 if (scrollTop === boxTop) 28716 { 28717 return; 28718 } 28719
28720 if ((scrollTop + this.opts.toolbarFixedTopOffset + tolerance) > boxTop) 28721 { 28722 this.toolbar.observeScrollEnable(scrollTop, boxTop); 28723 } 28724 else 28725 { 28726 this.toolbar.observeScrollDisable(); 28727 } 28728 }, 28729 observeScrollResize: function() 28730 { 28731 this.$toolbar.css({ 28732 28733 width: this.core.box().innerWidth(), 28734 left: this.core.box().offset().left 28735 28736 }); 28737 }, 28738 observeScrollEnable: function(scrollTop, boxTop) 28739 { 28740 if (typeof this.fullscreen !== 'undefined' && this.fullscreen.isOpened === false) 28741 { 28742 this.toolbar.observeScrollDisable(); 28743 return; 28744 } 28745 28746 var end = boxTop + this.core.box().outerHeight() - 32; 28747 var width = this.core.box().innerWidth(); 28748 28749 var position = (this.detect.isDesktop()) ? 'fixed' : 'absolute'; 28750 var top = (this.detect.isDesktop()) ? this.opts.toolbarFixedTopOffset : ($(this.opts.toolbarFixedTarget).scrollTop() - boxTop + this.opts.toolbarFixedTopOffset); 28751 var left = (this.detect.isDesktop()) ? this.core.box().offset().left : 0; 28752 28753 28754 if (this.opts.toolbarFixedTarget !== document) 28755 { 28756 position = 'absolute'; 28757 top = this.opts.toolbarFixedTopOffset + $(this.opts.toolbarFixedTarget).scrollTop() - boxTop; 28758 left = 0; 28759 } 28760 28761 this.$toolbar.addClass('toolbar-fixed-box'); 28762 28763 this.$toolbar.css({ 28764 position: position, 28765 width: width, 28766 top: top, 28767 left: left 28768 }); 28769 28770 28771 if (scrollTop > end) 28772 { 28773 $('.redactor-dropdown-' + this.uuid + ':visible').hide(); 28774 } 28775 28776 this.toolbar.setDropdownsFixed(); 28777 28778 this.$toolbar.css('visibility', (scrollTop < end) ? 'visible' : 'hidden'); 28779 $(window).on('resize.redactor-toolbar.' + this.uuid, $.proxy(this.toolbar.observeScrollResize, this)); 28780 }, 28781 observeScrollDisable: function() 28782 { 28783 this.$toolbar.css({ 28784 position: 'relative', 28785 width: 'auto', 28786 top: 0, 28787 left: 0, 28788 visibility: 'visible' 28789 }); 28790 28791 this.toolbar.unsetDropdownsFixed(); 28792 this.$toolbar.removeClass('toolbar-fixed-box'); 28793 $(window).off('resize.redactor-toolbar.' + this.uuid); 28794 }, 28795 setDropdownsFixed: function() 28796 { 28797 var position = (this.opts.toolbarFixedTarget === document && this.detect.isDesktop()) ? 'fixed' : 'absolute'; 28798 this.toolbar.setDropdownPosition(position); 28799 }, 28800 unsetDropdownsFixed: function() 28801 { 28802 this.toolbar.setDropdownPosition('absolute'); 28803 }, 28804 setDropdownPosition: function(position) 28805 { 28806 var self = this; 28807 $('.redactor-dropdown-' + this.uuid).each(function() 28808 { 28809 var $el = $(this); 28810 var $button = self.button.get($el.attr('rel')); 28811 var top = (position === 'fixed') ? self.opts.toolbarFixedTopOffset : $button.offset().top; 28812 28813 $el.css({ position: position, top: ($button.innerHeight() + top) + 'px' }); 28814 }); 28815 } 28816 }; 28817 }, 28818 28819 // =upload 28820 upload: function() 28821 { 28822 return { 28823 init: function(id, url, callback) 28824 { 28825 this.upload.direct = false; 28826 this.upload.callback = callback; 28827 this.upload.url = url; 28828 this.upload.$el = $(id); 28829 this.upload.$droparea = $('<div id="redactor-droparea" />'); 28830 28831 this.upload.$placeholdler = $('<div id="redactor-droparea-placeholder" />').text(this.lang.get('upload-label')); 28832 this.upload.$input = $('<input type="file" name="file" multiple />'); 28833 28834 this.upload.$placeholdler.append(this.upload.$input); 28835 this.upload.$droparea.append(this.upload.$placeholdler); 28836 this.upload.$el.append(this.upload.$droparea); 28837 28838 this.upload.$droparea.off('redactor.upload'); 28839 this.upload.$input.off('redactor.upload'); 28840 28841 this.upload.$droparea.on('dragover.redactor.upload', $.proxy(this.upload.onDrag, this)); 28842 this.upload.$droparea.on('dragleave.redactor.upload', $.proxy(this.upload.onDragLeave, this)); 28843 28844 // change 28845 this.upload.$input.on('change.redactor.upload', $.proxy(function(e) 28846 { 28847 e = e.originalEvent || e; 28848 var len = this.upload.$input[0].files.length; 28849 28850 for (var i = 0; i < len; i++) 28851 { 28852 var index = (len - 1) - i; 28853 this.upload.traverseFile(this.upload.$input[0].files[index], e); 28854 } 28855 }, this)); 28856 28857 // drop 28858 this.upload.$droparea.on('drop.redactor.upload', $.proxy(function(e) 28859 { 28860 e.preventDefault(); 28861 28862 this.upload.$droparea.removeClass('drag-hover').addClass('drag-drop'); 28863 this.upload.onDrop(e); 28864 28865 }, this)); 28866 }, 28867 directUpload: function(file, e) 28868 { 28869 this.upload.direct = true; 28870 this.upload.traverseFile(file, e); 28871 }, 28872 onDrop: function(e) 28873 { 28874 e = e.originalEvent || e; 28875 var files = e.dataTransfer.files; 28876 28877 if (this.opts.multipleImageUpload) 28878 { 28879 var len = files.length; 28880 for (var i = 0; i < len; i++) 28881 { 28882 this.upload.traverseFile(files[i], e); 28883 } 28884 } 28885 else 28886 { 28887 this.upload.traverseFile(files[0], e); 28888 } 28889 }, 28890 traverseFile: function(file, e) 28891 { 28892 if (this.opts.s3) 28893 { 28894 this.upload.setConfig(file); 28895 this.uploads3.send(file, e); 28896 return; 28897 } 28898 28899 var formData = !!window.FormData ? new FormData() : null; 28900 if (window.FormData) 28901 { 28902 this.upload.setConfig(file); 28903 28904 var name = (this.upload.type === 'image') ? this.opts.imageUploadParam : this.opts.fileUploadParam; 28905 formData.append(name, file); 28906 } 28907 28908 var stop = this.core.callback('uploadStart', e, formData); 28909 if (stop !== false) 28910 { 28911 this.progress.show(); 28912 this.upload.send(formData, e); 28913 } 28914 }, 28915 setConfig: function(file) 28916 { 28917 this.upload.getType(file); 28918 28919 if (this.upload.direct) 28920 { 28921 this.upload.url = (this.upload.type === 'image') ? this.opts.imageUpload : this.opts.fileUpload; 28922 this.upload.callback = (this.upload.type === 'image') ? this.image.insert : this.file.insert; 28923 } 28924 }, 28925 getType: function(file) 28926 { 28927 this.upload.type = (this.opts.imageTypes.indexOf(file.type) === -1) ? 'file' : 'image'; 28928 28929 if (this.opts.imageUpload === null && this.opts.fileUpload !== null) 28930 { 28931 this.upload.type = 'file'; 28932 } 28933 }, 28934 getHiddenFields: function(obj, fd) 28935 { 28936 if (obj === false || typeof obj !== 'object') 28937 { 28938 return fd; 28939 } 28940 28941 $.each(obj, $.proxy(function(k, v) 28942 { 28943 if (v !== null && v.toString().indexOf('#') === 0) 28944 { 28945 v = $(v).val(); 28946 } 28947 28948 fd.append(k, v); 28949 28950 }, this)); 28951 28952 return fd; 28953 28954 }, 28955 send: function(formData, e) 28956 { 28957 // append hidden fields 28958 if (this.upload.type === 'image') 28959 { 28960 formData = this.utils.appendFields(this.opts.imageUploadFields, formData); 28961 formData = this.utils.appendForms(this.opts.imageUploadForms, formData); 28962 formData = this.upload.getHiddenFields(this.upload.imageFields, formData); 28963 } 28964 else 28965 { 28966 formData = this.utils.appendFields(this.opts.fileUploadFields, formData); 28967 formData = this.utils.appendForms(this.opts.fileUploadForms, formData); 28968 formData = this.upload.getHiddenFields(this.upload.fileFields, formData); 28969 } 28970 28971 var xhr = new XMLHttpRequest(); 28972 xhr.open('POST', this.upload.url); 28973 xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest"); 28974 28975 // complete 28976 xhr.onreadystatechange = $.proxy(function() 28977 { 28978 if (xhr.readyState === 4) 28979 { 28980 var data = xhr.responseText; 28981 28982 data = data.replace(/^\[/, ''); 28983 data = data.replace(/\]$/, ''); 28984 28985 var json; 28986 try 28987 { 28988 json = (typeof data === 'string' ? JSON.parse(data) : data); 28989 } 28990 catch(err) 28991 { 28992 json = { error: true }; 28993 } 28994 28995 28996 this.progress.hide(); 28997 28998 if (!this.upload.direct) 28999 { 29000 this.upload.$droparea.removeClass('drag-drop'); 29001 } 29002 29003 this.upload.callback(json, this.upload.direct, e); 29004 } 29005 }, this); 29006 29007 // before send 29008 var stop = this.core.callback('uploadBeforeSend', xhr); 29009 if (stop !== false) 29010 { 29011 xhr.send(formData); 29012 } 29013 }, 29014 onDrag: function(e) 29015 { 29016 e.preventDefault(); 29017 this.upload.$droparea.addClass('drag-hover'); 29018 }, 29019 onDragLeave: function(e) 29020 { 29021 e.preventDefault(); 29022 this.upload.$droparea.removeClass('drag-hover'); 29023 }, 29024 clearImageFields: function() 29025 { 29026 this.upload.imageFields = {}; 29027 }, 29028 addImageFields: function(name, value) 29029 { 29030 this.upload.imageFields[name] = value; 29031 }, 29032 removeImageFields: function(name) 29033 { 29034 delete this.upload.imageFields[name]; 29035 }, 29036 clearFileFields: function() 29037 { 29038 this.upload.fileFields = {}; 29039 }, 29040 addFileFields: function(name, value) 29041 { 29042 this.upload.fileFields[name] = value; 29043 }, 29044 removeFileFields: function(name) 29045 { 29046 delete this.upload.fileFields[name]; 29047 } 29048 }; 29049 }, 29050 29051 // =s3 29052 uploads3: function() 29053 { 29054 return { 29055 send: function(file, e) 29056 { 29057 this.uploads3.executeOnSignedUrl(file, $.proxy(function(signedURL) 29058 { 29059 this.uploads3.sendToS3(file, signedURL, e); 29060 }, this)); 29061 }, 29062 executeOnSignedUrl: function(file, callback) 29063 { 29064 var xhr = new XMLHttpRequest(); 29065 var mark = (this.opts.s3.search(/\?/) === -1) ? '?' : '&'; 29066 29067 xhr.open('GET', this.opts.s3 + mark + 'name=' + file.name + '&type=' + file.type, true); 29068 29069 // hack to pass bytes through unprocessed. 29070 if (xhr.overrideMimeType) 29071 { 29072 xhr.overrideMimeType('text/plain;
29072 charset=x-user-defined'); 29073 } 29074 29075 var that = this; 29076 xhr.onreadystatechange = function(e) 29077 { 29078 if (this.readyState === 4 && this.status === 200) 29079 { 29080 that.progress.show(); 29081 callback(decodeURIComponent(this.responseText)); 29082 } 29083 }; 29084 29085 xhr.send(); 29086 }, 29087 createCORSRequest: function(method, url) 29088 { 29089 var xhr = new XMLHttpRequest(); 29090 if ("withCredentials" in xhr) 29091 { 29092 xhr.open(method, url, true); 29093 } 29094 else if (typeof XDomainRequest !== "undefined") 29095 { 29096 xhr = new XDomainRequest(); 29097 xhr.open(method, url); 29098 } 29099 else 29100 { 29101 xhr = null; 29102 } 29103 29104 return xhr; 29105 }, 29106 29107 sendToS3: function(file, url, e) 29108 { 29109 var xhr = this.uploads3.createCORSRequest('PUT', url); 29110 if (!xhr) 29111 { 29112 return; 29113 } 29114 29115 xhr.onload = $.proxy(function() 29116 { 29117 var json; 29118 this.progress.hide(); 29119 29120 if (xhr.status !== 200) 29121 { 29122 // error 29123 json = { error: true }; 29124 this.upload.callback(json, this.upload.direct, xhr); 29125 29126 return; 29127 } 29128 29129 var s3file = url.split('?'); 29130 if (!s3file[0]) 29131 { 29132 // url parsing is fail 29133 return false; 29134 } 29135 29136 29137 if (!this.upload.direct) 29138 { 29139 this.upload.$droparea.removeClass('drag-drop'); 29140 } 29141 29142 json = { url: s3file[0], id: s3file[0], s3: true }; 29143 if (this.upload.type === 'file') 29144 { 29145 var arr = s3file[0].split('/'); 29146 json.name = arr[arr.length-1]; 29147 } 29148 29149 this.upload.callback(json, this.upload.direct, e); 29150 29151 29152 }, this); 29153 29154 xhr.onerror = function() {}; 29155 xhr.upload.onprogress = function(e) {}; 29156 29157 xhr.setRequestHeader('Content-Type', file.type); 29158 xhr.setRequestHeader('x-amz-acl', 'public-read'); 29159 29160 xhr.send(file); 29161 29162 } 29163 }; 29164 }, 29165 29166 // =utils 29167 utils: function() 29168 { 29169 return { 29170 isEmpty: function(html) 29171 { 29172 html = (typeof html === 'undefined') ? this.core.editor().html() : html; 29173 29174 html = html.replace(/[\u200B-\u200D\uFEFF]/g, ''); 29175 html = html.replace(/ /gi, ''); 29176 html = html.replace(/<\/?br\s?\/?>/g, ''); 29177 html = html.replace(/\s/g, ''); 29178 html = html.replace(/^<p>[^\W\w\D\d]*?<\/p>$/i, ''); 29179 html = html.replace(/<iframe(.*?[^>])>$/i, 'iframe'); 29180 html = html.replace(/<source(.*?[^>])>$/i, 'source'); 29181 29182 // remove empty tags 29183 html = html.replace(/<[^\/>][^>]*><\/[^>]+>/gi, ''); 29184 html = html.replace(/<[^\/>][^>]*><\/[^>]+>/gi, ''); 29185 29186 html = $.trim(html); 29187 29188 return html === ''; 29189 }, 29190 isElement: function(obj) 29191 { 29192 try { 29193 // Using W3 DOM2 (works for FF, Opera and Chrome) 29194 return obj instanceof HTMLElement; 29195 } 29196 catch(e) 29197 { 29198 return (typeof obj === "object") && (obj.nodeType === 1) && (typeof obj.style === "object") && (typeof obj.ownerDocument === "object"); 29199 } 29200 }, 29201 strpos: function(haystack, needle, offset) 29202 { 29203 var i = haystack.indexOf(needle, offset); 29204 return i >= 0 ? i : false; 29205 }, 29206 dataURItoBlob: function(dataURI) 29207 { 29208 var byteString; 29209 if (dataURI.split(',')[0].indexOf('base64') >= 0) 29210 { 29211 byteString = atob(dataURI.split(',')[1]); 29212 } 29213 else 29214 { 29215 byteString = unescape(dataURI.split(',')[1]); 29216 } 29217 29218 var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]; 29219 29220 var ia = new Uint8Array(byteString.length); 29221 for (var i = 0; i < byteString.length; i++) 29222 { 29223 ia[i] = byteString.charCodeAt(i); 29224 } 29225 29226 return new Blob([ia], { type:mimeString }); 29227 }, 29228 getOuterHtml: function(el) 29229 { 29230 return $('<div>').append($(el).eq(0).clone()).html(); 29231 }, 29232 cloneAttributes: function(from, to) 29233 { 29234 from = from[0] || from; 29235 to = $(to); 29236 29237 var attrs = from.attributes; 29238 var len = attrs.length; 29239 while (len--) 29240 { 29241 var attr = attrs[len];
29242 to.attr(attr.name, attr.value); 29243 } 29244 29245 return to; 29246 }, 29247 breakBlockTag: function() 29248 { 29249 var block = this.selection.block(); 29250 if (!block) 29251 { 29252 return false; 29253 } 29254 29255 var isEmpty = this.utils.isEmpty(block.innerHTML); 29256 29257 var tag = block.tagName.toLowerCase(); 29258 if (tag === 'pre' || tag === 'li' || tag === 'td' || tag === 'th') 29259 { 29260 return false; 29261 } 29262 29263 if (!isEmpty && this.utils.isStartOfElement(block)) 29264 { 29265 return { $block: $(block), $next: $(block).next(), type: 'start' }; 29266 } 29267 else if (!isEmpty && this.utils.isEndOfElement(block)) 29268 { 29269 return { $block: $(block), $next: $(block).next(), type: 'end' }; 29270 } 29271 else 29272 { 29273 var endOfNode = this.selection.extractEndOfNode(block); 29274 var $nextPart = $('<' + tag + ' />').append(endOfNode); 29275 29276 $nextPart = this.utils.cloneAttributes(block, $nextPart); 29277 $(block).after($nextPart); 29278 29279 return { $block: $(block), $next: $nextPart, type: 'break' }; 29280 } 29281 }, 29282 // tag detection 29283 inBlocks: function(tags) 29284 { 29285 tags = ($.isArray(tags)) ? tags : [tags]; 29286 29287 var blocks = this.selection.blocks(); 29288 var len = blocks.length; 29289 var contains = false; 29290 for (var i = 0; i < len; i++) 29291 { 29292 if (blocks[i] !== false) 29293 { 29294 var tag = blocks[i].tagName.toLowerCase(); 29295 29296 if ($.inArray(tag, tags) !== -1) 29297 { 29298 contains = true; 29299 } 29300 } 29301 } 29302 29303 return contains; 29304 29305 }, 29306 inInlines: function(tags) 29307 { 29308 tags = ($.isArray(tags)) ? tags : [tags]; 29309 29310 var inlines = this.selection.inlines(); 29311 var len = inlines.length; 29312 var contains = false; 29313 for (var i = 0; i < len; i++) 29314 { 29315 var tag = inlines[i].tagName.toLowerCase(); 29316 29317 if ($.inArray(tag, tags) !== -1) 29318 { 29319 contains = true; 29320 } 29321 } 29322 29323 return contains; 29324 29325 }, 29326 isTag: function(current, tag) 29327 { 29328 var element = $(current).closest(tag, this.core.editor()[0]); 29329 if (element.length === 1) 29330 { 29331 return element[0]; 29332 } 29333 29334 return false; 29335 }, 29336 isBlock: function(block) 29337 { 29338 if (block === null) 29339 { 29340 return false; 29341 } 29342 29343 block = block[0] || block; 29344 29345 return block && this.utils.isBlockTag(block.tagName); 29346 }, 29347 isBlockTag: function(tag) 29348 { 29349 return (typeof tag === 'undefined') ? false : this.reIsBlock.test(tag); 29350 }, 29351 isInline: function(inline) 29352 { 29353 inline = inline[0] || inline; 29354 29355 return inline && this.utils.isInlineTag(inline.tagName); 29356 }, 29357 isInlineTag: function(tag) 29358 { 29359 return (typeof tag === 'undefined') ? false : this.reIsInline.test(tag); 29360 }, 29361 // parents detection 29362 isRedactorParent: function(el) 29363 { 29364 if (!el) 29365 { 29366 return false; 29367 } 29368 29369 if ($(el).parents('.redactor-in').length === 0 || $(el).hasClass('redactor-in')) 29370 { 29371 return false; 29372 } 29373 29374 return el; 29375 }, 29376 isCurrentOrParentHeader: function() 29377 { 29378 return this.utils.isCurrentOrParent(['H1', 'H2', 'H3', 'H4', 'H5', 'H6']); 29379 }, 29380 isCurrentOrParent: function(tagName) 29381 { 29382 var parent = this.selection.parent(); 29383 var current = this.selection.current(); 29384 29385 if ($.isArray(tagName)) 29386 { 29387 var matched = 0; 29388 $.each(tagName, $.proxy(function(i, s) 29389 { 29390 if (this.utils.isCurrentOrParentOne(current, parent, s)) 29391 { 29392 matched++; 29393 } 29394 }, this)); 29395 29396 return (matched === 0) ? false : true; 29397 } 29398 else 29399 { 29400 return this.utils.isCurrentOrParentOne(current, parent, tagName); 29401 } 29402 }, 29403 isCurrentOrParentOne: function(current, parent, tagName) 29404 { 29405 tagName = tagName.toUpperCase(); 29406 29407 return parent && parent.tagName === tagName ? parent : current && current.tagName === tagName ? current : false; 29408 }, 29409 isEditorRelative: function() 29410 { 29411 var position = this.core.editor().css('position'); 29412 var arr = ['absolute', 'fixed', 'relative']; 29413 29414 return ($.inArray(arr, position) !== -1); 29415 }, 29416 setEditorRelative: function() 29417 { 29418 this.core.editor().addClass('redactor-relative'); 29419 }, 29420 // scroll 29421 getScrollTarget: function() 29422 { 29423 var $scrollTarget = $(this.opts.scrollTarget); 29424 29425 return ($scrollTarget.length !== 0) ? $scrollTarget : $(document); 29426 }, 29427 freezeScroll: function() 29428 { 29429 this.freezeScrollTop = this.utils.getScrollTarget().scrollTop(); 29430 this.utils.getScrollTarget().scrollTop(this.freezeScrollTop); 29431 }, 29432 unfreezeScroll: function() 29433 { 29434 if (typeof this.freezeScrollTop === 'undefined') 29435 { 29436 return; 29437 } 29438 29439 this.utils.getScrollTarget().scrollTop(this.freezeScrollTop); 29440 }, 29441 saveScroll: function() 29442 { 29443 this.tmpScrollTop = this.utils.getScrollTarget().scrollTop(); 29444 }, 29445 restoreScroll: function() 29446 { 29447 if (typeof this.tmpScrollTop === 'undefined') 29448 { 29449 return; 29450 } 29451 29452 this.utils.getScrollTarget().scrollTop(this.tmpScrollTop); 29453 }, 29454 isStartOfElement: function(element) 29455 { 29456 if (typeof element === 'undefined') 29457 { 29458 element = this.selection.block(); 29459 if (!element) 29460 { 29461 return false;
29462 } 29463 } 29464 29465 return (this.offset.get(element) === 0) ? true : false; 29466 }, 29467 isEndOfElement: function(element) 29468 { 29469 if (typeof element === 'undefined') 29470 { 29471 element = this.selection.block(); 29472 if (!element) 29473 { 29474 return false; 29475 } 29476 } 29477 29478 var text = $.trim($(element).text()).replace(/[\t\n\r\n]/g, '').replace(/\u200B/g, ''); 29479 var offset = this.offset.get(element); 29480 29481 return (offset === text.length) ? true : false; 29482 }, 29483 removeEmptyAttr: function(el, attr) 29484 { 29485 var $el = $(el); 29486 if (typeof $el.attr(attr) === 'undefined') 29487 { 29488 return true; 29489 } 29490 29491 if ($el.attr(attr) === '') 29492 { 29493 $el.removeAttr(attr); 29494 return true; 29495 } 29496 29497 return false; 29498 }, 29499 replaceToTag: function(node, tag) 29500 { 29501 var replacement; 29502 $(node).replaceWith(function() 29503 { 29504 replacement = $('<' + tag + ' />').append($(this).contents()); 29505 29506 for (var i = 0; i < this.attributes.length; i++) 29507 { 29508 replacement.attr(this.attributes[i].name, this.attributes[i].value); 29509 } 29510 29511 return replacement; 29512 }); 29513 29514 return replacement; 29515 }, 29516 // select all 29517 isSelectAll: function() 29518 { 29519 return this.selectAll; 29520 }, 29521 enableSelectAll: function() 29522 { 29523 this.selectAll = true; 29524 }, 29525 disableSelectAll: function() 29526 { 29527 this.selectAll = false; 29528 }, 29529 disableBodyScroll: function() 29530 { 29531 var $body = $('html'); 29532 var windowWidth = window.innerWidth; 29533 if (!windowWidth) 29534 { 29535 var documentElementRect = document.documentElement.getBoundingClientRect(); 29536 windowWidth = documentElementRect.right - Math.abs(documentElementRect.left); 29537 } 29538 29539 var isOverflowing = document.body.clientWidth < windowWidth; 29540 var scrollbarWidth = this.utils.measureScrollbar(); 29541 29542 $body.css('overflow', 'hidden'); 29543 if (isOverflowing) 29544 { 29545 $body.css('padding-right', scrollbarWidth); 29546 } 29547 }, 29548 measureScrollbar: function() 29549 { 29550 var $body = $('body'); 29551 var scrollDiv = document.createElement('div'); 29552 scrollDiv.className = 'redactor-scrollbar-measure'; 29553 29554 $body.append(scrollDiv); 29555 var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth; 29556 $body[0].removeChild(scrollDiv); 29557 return scrollbarWidth; 29558 }, 29559 enableBodyScroll: function() 29560 { 29561 $('html').css({ 'overflow': '', 'padding-right': '' }); 29562 $('body').remove('redactor-scrollbar-measure'); 29563 }, 29564 appendFields: function(appendFields, data) 29565 { 29566 if (!appendFields) 29567 { 29568 return data; 29569 } 29570 else if (typeof appendFields === 'object') 29571 { 29572 $.each(appendFields, function(k, v) 29573 { 29574 if (v !== null && v.toString().indexOf('#') === 0) 29575 { 29576 v = $(v).val(); 29577 } 29578 29579 data.append(k, v); 29580 29581 }); 29582 29583 return data; 29584 } 29585 29586 var $fields = $(appendFields); 29587 if ($fields.length === 0) 29588 { 29589 return data; 29590 } 29591 else 29592 { 29593 var str = ''; 29594 $fields.each(function() 29595 { 29596 data.append($(this).attr('name'), $(this).val()); 29597 }); 29598 29599 return data; 29600 } 29601 }, 29602 appendForms: function(appendForms, data) 29603 { 29604 if (!appendForms) 29605 { 29606 return data; 29607 } 29608 29609 var $forms = $(appendForms); 29610 if ($forms.length === 0) 29611 { 29612 return data; 29613 } 29614 else 29615 { 29616 var formData = $forms.serializeArray(); 29617 29618 $.each(formData, function(z,f) 29619 { 29620 data.append(f.name, f.value); 29621 }); 29622 29623 return data; 29624 } 29625 }, 29626 isRgb: function(str) 29627 { 29628 return (str.search(/^rgb/i) === 0); 29629 }, 29630 rgb2hex: function(rgb) 29631 { 29632 rgb = rgb.match(/^rgba?[\s+]?\([\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?/i); 29633 29634 return (rgb && rgb.length === 4) ? "#" + 29635 ("0" + parseInt(rgb[1],10).toString(16)).slice(-2) + 29636 ("0" + parseInt(rgb[2],10).toString(16)).slice(-2) + 29637 ("0" + parseInt(rgb[3],10).toString(16)).slice(-2) : ''; 29638 }, 29639 29640 // #backward 29641 isCollapsed: function() 29642 { 29643 return this.selection.isCollapsed(); 29644 }, 29645 isMobile: function() 29646 { 29647 return this.detect.isMobile(); 29648 }, 29649 isDesktop: function() 29650 { 29651 return this.detect.isDesktop(); 29652 }, 29653 isPad: function() 29654 { 29655 return this.detect.isIpad(); 29656 } 29657 29658 }; 29659 }, 29660 29661 // #backward 29662 browser: function() 29663 { 29664 return { 29665 webkit: function() 29666 { 29667 return this.detect.isWebkit(); 29668 }, 29669 ff: function() 29670 { 29671 return this.detect.isFirefox(); 29672 }, 29673 ie: function() 29674 { 29675 return this.detect.isIe(); 29676 } 29677 }; 29678 } 29679 }; 29680 29681 $(window).on('load.tools.redactor', function() 29682 { 29683 $('[data-tools="redactor"]').redactor(); 29684 }); 29685 29686 // constructor 29687 Redactor.prototype.init.prototype = Redactor.prototype; 29688 29689})(jQuery); 29690 29691(function($) 29692{ 29693 $.fn.redactorAnimation = function(animation, options, callback) 29694 { 29695 return this.each(function() 29696 { 29697 new redactorAnimation(this, animation, options, callback); 29698 }); 29699 }; 29700 29701 function redactorAnimation(element, animation, options, callback) 29702 { 29703 // default 29704 var opts = { 29705 duration: 0.5, 29706 iterate: 1, 29707 delay: 0, 29708 prefix: 'redactor-', 29709 timing: 'linear' 29710 }; 29711 29712 this.animation = animation; 29713 this.slide = (this.animation === 'slideDown' || this.animation === 'slideUp'); 29714 this.$element = $(element); 29715 this.prefixes = ['', '-moz-', '-o-animation-', '-webkit-']; 29716 this.queue = []; 29717 29718 // options or callback 29719 if (typeof options === 'function') 29720 { 29721 callback = options; 29722 this.opts = opts; 29723 } 29724 else 29725 { 29726 this.opts = $.extend(opts, options); 29727 } 29728 29729 // slide 29730 if (this.slide) 29731 { 29732 this.$element.height(this.$element.height()); 29733 } 29734 29735 // init 29736 this.init(callback); 29737 29738 } 29739 29740 redactorAnimation.prototype = { 29741 29742 init: function(callback) 29743 { 29744 this.queue.push(this.animation); 29745 29746 this.clean(); 29747 29748 if (this.animation === 'show') 29749 { 29750 this.opts.timing = 'linear'; 29751 this.$element.removeClass('hide').show(); 29752 29753 if (typeof callback === 'function') 29754 { 29755 callback(this); 29756 } 29757 } 29758 else if (this.animation === 'hide') 29759 { 29760 this.opts.timing = 'linear'; 29761 this.$element.hide(); 29762 29763 if (typeof callback === 'function') 29764 { 29765 callback(this); 29766 } 29767 } 29768 else 29769 {
29770 this.animate(callback); 29771 } 29772 29773 }, 29774 animate: function(callback) 29775 { 29776 this.$element.addClass('redactor-animated').css('display', '').removeClass('hide'); 29777 this.$element.addClass(this.opts.prefix + this.queue[0]); 29778 29779 this.set(this.opts.duration + 's', this.opts.delay + 's', this.opts.iterate, this.opts.timing); 29780 29781 var _callback = (this.queue.length > 1) ? null : callback; 29782 this.complete('AnimationEnd', $.proxy(function() 29783 { 29784 if (this.$element.hasClass(this.opts.prefix + this.queue[0])) 29785 { 29786 this.clean(); 29787 this.queue.shift(); 29788 29789 if (this.queue.length) 29790 { 29791 this.animate(callback); 29792 } 29793 } 29794 29795 }, this), _callback); 29796 }, 29797 set: function(duration, delay, iterate, timing) 29798 { 29799 var len = this.prefixes.length; 29800 29801 while (len--) 29802 { 29803 this.$element.css(this.prefixes[len] + 'animation-duration', duration); 29804 this.$element.css(this.prefixes[len] + 'animation-delay', delay); 29805 this.$element.css(this.prefixes[len] + 'animation-iteration-count', iterate); 29806 this.$element.css(this.prefixes[len] + 'animation-timing-function', timing); 29807 } 29808 29809 }, 29810 clean: function() 29811 { 29812 this.$element.removeClass('redactor-animated'); 29813 this.$element.removeClass(this.opts.prefix + this.queue[0]); 29814 29815 this.set('', '', '', ''); 29816 29817 }, 29818 complete: function(type, make, callback) 29819 { 29820 this.$element.one(type.toLowerCase() + ' webkit' + type + ' o' + type + ' MS' + type, $.proxy(function() 29821 { 29822 if (typeof make === 'function') 29823 { 29824 make(); 29825 } 29826 29827 if (typeof callback === 'function') 29828 { 29829 callback(this); 29830 } 29831 29832 // hide 29833 var effects = ['fadeOut', 'slideUp', 'zoomOut', 'slideOutUp', 'slideOutRight', 'slideOutLeft']; 29834 if ($.inArray(this.animation, effects) !== -1) 29835 { 29836 this.$element.css('display', 'none'); 29837 } 29838 29839 // slide 29840 if (this.slide) 29841 { 29842 this.$element.css('height', ''); 29843 } 29844 29845 }, this)); 29846 29847 } 29848 }; 29849 29850})(jQuery); 29851$(function () { 29852 // Pass authenticity_token 29853 var params = '[name="authenticity_token"]'; 29854 // Set global settings 29855 $.Redactor.settings = { 29856 /* 29857 imageUpload: '/redactor2_rails/images', 29858 imageUploadFields: params, 29859 fileUpload: '/redactor2_rails/files', 29860 fileUploadFields: params, 29861 callbacks: { 29862 imageUploadError: function(json) 29863 { 29864 console.log(json.error); 29865 console.log(json.anothermessage); 29866 }, 29867 fileUploadError: function(json) 29868 { 29869 console.log(json.error); 29870 console.log(json.anothermessage); 29871 } 29872 } 29873 */ 29874 }; 29875 // Initialize Redactor 29876 //$('.redactor').redactor(); 29877}); 29878(function($) 29879{ 29880 $.Redactor.prototype.alignment = function() 29881 { 29882 return { 29883 langs: { 29884 en: { 29885 "align": "Align", 29886 "align-left": "Align Left", 29887 "align-center": "Align Centre", 29888 "align-right": "Align Right", 29889 } 29890 }, 29891 init: function() 29892 { 29893 var that = this; 29894 var dropdown = {}; 29895 29896 dropdown.left = { title: that.lang.get('align-left'), func: that.alignment.setLeft }; 29897 dropdown.center = { title: that.lang.get('align-center'), func: that.alignment.setCenter }; 29898 dropdown.right = { title: that.lang.get('align-right'), func: that.alignment.setRight }; 29899 //dropdown.justify = { title: that.lang.get('align-justify'), func: that.alignment.setJustify }; 29900 29901 var button = this.button.addAfter('lists', 'alignment', this.lang.get('align')); 29902 this.button.setIcon(button, '<i class="re-icon-alignment"></i>'); 29903 this.button.addDropdown(button, dropdown); 29904 }, 29905 removeAlign: function() 29906 { 29907 this.block.removeClass('text-center'); 29908 this.block.removeClass('text-right'); 29909 this.block.removeClass('text-justify'); 29910 }, 29911 setLeft: function() 29912 { 29913 this.buffer.set(); 29914 this.alignment.removeAlign(); 29915 }, 29916 setCenter: function() 29917 { 29918 this.buffer.set(); 29919 this.alignment.removeAlign(); 29920 this.block.addClass('text-center'); 29921 this.core.editor().focus() 29922 }, 29923 setRight: function() 29924 { 29925 this.buffer.set(); 29926 this.alignment.removeAlign(); 29927 this.block.addClass('text-right'); 29928 this.core.editor().focus() 29929 }, 29930 setJustify: function() 29931 { 29932 this.buffer.set(); 29933 this.alignment.removeAlign();
29934 this.block.addClass('text-justify'); 29935 this.core.editor().focus() 29936 } 29937 }; 29938 }; 29939})(jQuery); 29940(function($) 29941{ 29942 $.Redactor.prototype.filemanager = function() 29943 { 29944 return { 29945 langs: { 29946 en: { 29947 "upload": "Upload", 29948 "choose": "Choose" 29949 } 29950 }, 29951 init: function() 29952 { 29953 if (!this.opts.fileManagerJson) 29954 { 29955 return; 29956 } 29957 29958 this.modal.addCallback('file', this.filemanager.load); 29959 }, 29960 load: function() 29961 { 29962 var $box = $('<div style="overflow: auto; height: 300px; display: none;" class="redactor-modal-tab" data-title="Choose">').hide(); 29963 this.modal.getModal().append($box); 29964 29965 29966 $.ajax({ 29967 dataType: "json", 29968 cache: false, 29969 url: this.opts.fileManagerJson, 29970 success: $.proxy(function(data) 29971 { 29972 var ul = $('<ul id="redactor-modal-list">'); 29973 $.each(data, $.proxy(function(key, val) 29974 { 29975 29976 var a = $('<a href="#" data-params="' + encodeURI(JSON.stringify(val)) + '" class="redactor-file-manager-link">' + val.title + ' <span style="font-size: 11px; color: #888;">' + val.name + '</span> <span style="position: absolute; right: 10px; font-size: 11px; color: #888;">(' + val.size + ')</span></a>'); 29977 var li = $('<li />'); 29978 29979 a.on('click', $.proxy(this.filemanager.insert, this)); 29980 29981 li.append(a); 29982 ul.append(li); 29983 29984 }, this)); 29985 29986 $box.append(ul); 29987 29988 29989 }, this) 29990 }); 29991 29992 }, 29993 insert: function(e) 29994 { 29995 e.preventDefault(); 29996 29997 var $el = $(e.target).closest('.redactor-file-manager-link'); 29998 var json = $.parseJSON(decodeURI($el.attr('data-params'))); 29999 30000 this.file.insert(json, null); 30001 } 30002 }; 30003 }; 30004})(jQuery); 30005(function($) 30006{ 30007 $.Redactor.prototype.hubblebutton = function() 30008 { 30009 return { 30010 init: function() 30011 { 30012 var button = this.button.add('button', 'Button'); 30013 this.button.setIcon(button, '<i class="mdi mdi-code-greater-than"></i>'); 30014 this.button.addCallback(button, this.hubblebutton.toggle); 30015 }, 30016 toggle: function() 30017 { 30018 this.inline.toggleClass('button'); 30019 } 30020 }; 30021 }; 30022})(jQuery); 30023(function($) 30024{ 30025 $.Redactor.prototype.hubbledo = function() 30026 { 30027 return { 30028 init: function() 30029 { 30030 var undobutton = this.button.add('undo', 'Undo'); 30031 var redobutton = this.button.add('redo', 'Redo'); 30032 30033 this.button.setIcon(undobutton, '<i class="mdi mdi-undo"></i>'); 30034 this.button.setIcon(redobutton, '<i class="mdi mdi-redo"></i>'); 30035 30036 this.button.addCallback(undobutton, this.buffer.undo); 30037 this.button.addCallback(redobutton, this.buffer.redo); 30038 } 30039 }; 30040 }; 30041})(jQuery); 30042(function($) 30043{ 30044 $.Redactor.prototype.hubbleimage = function() 30045 { 30046 return { 30047 init: function() 30048 { 30049 this.modal.addCallback('image-edit', this.hubbleimage.load); 30050 }, 30051 load: function() 30052 { 30053 $('input#redactor-image-link').parents('section').append('<div class="info tips">Links to other websites must start with <em>http://</em> or <em>https://</em><br />Links to pages in this website should start with <em>/</em></div>'); 30054 $('input#redactor-image-link').keyup(function(){ 30055 $('button#redactor-modal-button-action').prop('disabled', false); 30056 $('div.info.errors', $(this).parents('section')).remove(); 30057 if ($('input#redactor-image-link').val().indexOf('lvh.me:3000') >= 0) { 30058 $('button#redactor-modal-button-action').prop('disabled', true); 30059 $(this).parents('section').append('<div class="info errors">If you wish to link to an internal page, add the URL from the first <em>/</em> after the domain name (e.g. <em>/pages/1</em>)</div>'); 30060 } 30061 }); 30062 } 30063 }; 30064 }; 30065})(jQuery); 30066(function($) 30067{ 30068 $.Redactor.prototype.hubblelink = function() 30069 { 30070 return { 30071 init: function() 30072 { 30073 this.modal.addCallback('link', this.hubblelink.load); 30074 }, 30075 load: function() 30076 { 30077 var $link_anchor = ''; 30078 if (window.location.href.indexOf('_broadcasts/') > -1) { 30079 $link_anchor = 'https://www.lvh.me:3000'; 30080 } 30081 var $section_type = $('<section class="type"></section>'); 30082 $section_type.append($('<label for="redactor-choose-type">Destination</label>')); 30083 var $select_type = $('<select id="redactor-choose-type"></select>'); 30084 $select_type.append($('<option value="" selected="selected">Please select...</option>')); 30085 $select_type.append($('<option value="page">Page</option>')); 30086 $select_type.append($('<option id="redactor-option-article" value="article">Article</option>')); 30087 $select_type.append($('<option id="redactor-option-event" value="event">Event</option>')); 30088 $select_type.append($('<option id="redactor-option-resource" value="resource">Resource</option>')); 30089 $select_type.append($('<option id="redactor-option-story" value="story">Story</option>')); 30090 $select_type.append($('<option value="custom">Custom URL</option>')); 30091 $select_type.append($('<option value="email">Email address</option>')); 30092 $section_type.append($select_type); 30093 var $section_page = $('<section class="choose page" data-type="page"></section>'); 30094 $section_page.append($('<label for="redactor-choose-page">Page</label>')); 30095 $section_page.append($('<select id="redactor-choose-page"><option value="" selected="selected">Please select...</option></select>')); 30096 var $section_article = $('<section class="choose article" data-type="article"></section>'); 30097 $section_article.append($('<label for="redactor-choose-article">Article</label>')); 30098 $section_article.append($('<select id="redactor-choose-article"><option value="" selected="selected">Please select...</option></select>')); 30099 var $section_event = $('<section class="choose event" data-type="event"></section>'); 30100 $section_event.append($('<label for="redactor-choose-event">Event</label>')); 30101 $section_event.append($('<select id="redactor-choose-event"><option value="" selected="selected">Please select...</option></select>')); 30102 var $section_resource = $('<section class="choose resource" data-type="resource"></section>'); 30103 $section_resource.append($('<label for="redactor-choose-resource">Resource</label>')); 30104 $section_resource.append($('<select id="redactor-choose-resource"><option value="" selected="selected">Please select...</option></select>')); 30105 var $section_story = $('<section class="choose story" data-type="story"></section>'); 30106 $section_story.append($('<label for="redactor-choose-story">Story</label>')); 30107 $section_story.append($('<select id="redactor-choose-story"><option value="" selected="selected">Please select...</option></select>')); 30108 $('div.redactor-modal-tab').prepend($section_story); 30109 $('div.redactor-modal-tab').prepend($section_resource); 30110 $('div.redactor-modal-tab').prepend($section_event); 30111 $('div.redactor-modal-tab').prepend($section_article); 30112 $('div.redactor-modal-tab').prepend($section_page); 30113 $('div.redactor-modal-tab').prepend($section_type); 30114 $.ajax({ 30115 type: 'GET', 30116 url: '/admin/pages', 30117 data: { 30118 sort: { 30119 title: 'asc' 30120 } 30121 }, 30122 dataType: 'json', 30123 success: function($result) { 30124 $.each($result, function($index, $value){ 30125 $('select#redactor-choose-page').append('<option value="'+$link_anchor+'/pages/'+$result[$index].path+'">'+$result[$index].title+'</option>'); 30126 }); 30127 } 30128 }); 30129 $.ajax({ 30130 type: 'GET', 30131 url: '/admin/events', 30132 data: { 30133 sort: { 30134 title: 'asc' 30135 } 30136 }, 30137 dataType: 'json', 30138 success: function($result) { 30139 if ($result.length == 0) { 30140 $('option#redactor-option-event').hide(); 30141 } 30142 $.each($result, function($index, $value){ 30143 $('select#redactor-choose-event').append('<option value="'+$link_anchor+'/events/'+$result[$index].path+'">'+$result[$index].title+'</option>'); 30144 }); 30145 }, 30146 error: function($request, $status, $error) { 30147 $('option#redactor-option-event').hide(); 30148 } 30149 }); 30150 $.ajax({ 30151 type: 'GET', 30152 url: '/admin/articles', 30153 data: { 30154 sort: { 30155 title: 'asc' 30156 } 30157 }, 30158 dataType: 'json', 30159 success: function($result) { 30160 if ($result.length == 0) { 30161 $('option#redactor-option-article').hide(); 30162 } 30163 $.each($result, function($index, $value){ 30164 $('select#redactor-choose-article').append('<option value="'+$link_anchor+'/articles/'+$result[$index].path+'">'+$result[$index].title+'</option>'); 30165 }); 30166 }, 30167 error: function($request, $status, $error) { 30168 $('option#redactor-option-article').hide(); 30169 } 30170 }); 30171 $.ajax({ 30172 type: 'GET', 30173 url: '/admin/resources', 30174 data: { 30175 sort: { 30176 title: 'asc' 30177 } 30178 }, 30179 dataType: 'json', 30180 success: function($result) { 30181 if ($result.length == 0) { 30182 $('option#redactor-option-resource').hide(); 30183 } 30184 $.each($result, function($index, $value){ 30185 $('select#redactor-choose-resource').append('<option value="'+$link_anchor+'/resources/'+$result[$index].path+'">'+$result[$index].title+'</option>'); 30186 }); 30187 }, 30188 error: function($request, $status, $error) { 30189 $('option#redactor-option-resource').hide(); 30190 } 30191 }); 30192 $.ajax({ 30193 type: 'GET', 30194 url: '/admin/stories', 30195 data: { 30196 sort: { 30197 title: 'asc' 30198 } 30199 }, 30200 dataType: 'json', 30201 success: function($result) { 30202 if ($result.length == 0) { 30203 $('option#redactor-option-story').hide(); 30204 } 30205 $.each($result, function($index, $value){ 30206 $('select#redactor-choose-story').append('<option value="'+$link_anchor+'/stories/'+$result[$index].path+'">'+$result[$index].title+'</option>'); 30207 }); 30208 }, 30209 error: function($request, $status, $error) { 30210 $('option#redactor-option-story').hide(); 30211 } 30212 }); 30213 $('section.choose').hide(); 30214 $('input#redactor-link-url').parents('section').hide(); 30215 var $href = this.link.buildLinkFromElement(this.link.is()).url; 30216 if ($href != '') { 30217 $found = false;
30218 $('section.choose select option').each(function(){ 30219 if ($href == $(this).val()) { 30220 $('select#redactor-choose-type').val($(this).parents('section').data('type')); 30221 $(this).parents('section').show(); 30222 $(this).prop('selected', true); 30223 $found = true; 30224 } 30225 }); 30226 if (!$found) { 30227 $('select#redactor-choose-type').val('custom'); 30228 $('input#redactor-link-url').parents('section').show(); 30229 } 30230 } 30231 $('select#redactor-choose-type').change(function(){ 30232 $('section.choose').hide(); 30233 $('section.choose select').val(''); 30234 $('input#redactor-link-url').val(''); 30235 $('input#redactor-link-url').parents('section').hide(); 30236 if ($(this).val() != '') { 30237 if ($(this).val() == 'custom') { 30238 $('input#redactor-link-url').parents('section').show(); 30239 $('input#redactor-link-url').val('https://'); 30240 } else if ($(this).val() == 'email') { 30241 $('input#redactor-link-url').parents('section').show(); 30242 $('input#redactor-link-url').val('mailto:'); 30243 } else { 30244 $('section.'+$(this).val()).show(); 30245 } 30246 } 30247 }); 30248 $('section.choose select').change(function(){ 30249 $('button#redactor-modal-button-action').prop('disabled', false); 30250 $('button#redactor-modal-button-action').css('opacity', '1'); 30251 $('div.info.errors', $(this).parents('section')).remove(); 30252 $('input#redactor-link-url').val($(this).val()); 30253 }); 30254 $('input#redactor-link-url').keyup(function(){ 30255 $('button#redactor-modal-button-action').prop('disabled', false); 30256 $('button#redactor-modal-button-action').css('opacity', '1'); 30257 $('div.info.errors', $(this).parents('section')).remove(); 30258 if ( 30259 ($('input#redactor-link-url').val().indexOf('http://') != 0) && 30260 ($('input#redactor-link-url').val().indexOf('https://') != 0) && 30261 ($('input#redactor-link-url').val().indexOf('mailto:') != 0) && 30262 ($('input#redactor-link-url').val().indexOf('tel:') != 0) && 30263 ($('input#redactor-link-url').val().indexOf('/') != 0) && 30264 ($('input#redactor-link-url').val().indexOf('#') != 0) 30265 ) { 30266 $('button#redactor-modal-button-action').prop('disabled', true); 30267 $('button#redactor-modal-button-action').css('opacity', '0.5'); 30268 $(this).parents('section').append('<div class="info errors">Links to other websites must start with <em>http://</em> or <em>https://</em><br />Links to an email address must start with <em>mailto:</em><br />Links to a telephone number must start with <em>tel:</em><br />Links to pages within this website must start with <em>/</em><br />Links to anchors within this page must start with <em>#</em></div>'); 30269 } 30270 if ($('input#redactor-link-url').val().indexOf('lvh.me:3000') >= 0) { 30271 $('button#redactor-modal-button-action').prop('disabled', true); 30272 $('button#redactor-modal-button-action').css('opacity', '0.5'); 30273 $(this).parents('section').append('<div class="info errors">If you wish to link to a page in this website, it is better to choose it from the lists above.</div>'); 30274 } 30275 }); 30276 } 30277 }; 30278 }; 30279})(jQuery); 30280(function($) 30281{ 30282 $.Redactor.prototype.hubblesubsup = function() 30283 { 30284 return { 30285 init: function() 30286 { 30287 var subbutton = this.button.add('subscript', 'Subscript'); 30288 var supbutton = this.button.add('superscript', 'Superscript'); 30289 30290 this.button.setIcon(subbutton, '<i class="mdi mdi-format-subscript"></i>'); 30291 this.button.setIcon(supbutton, '<i class="mdi mdi-format-superscript"></i>'); 30292 30293 this.button.addCallback(subbutton, this.hubblesubsup.formatSub); 30294 this.button.addCallback(supbutton, this.hubblesubsup.formatSup); 30295 }, 30296 formatSub: function() 30297 { 30298 this.inline.format('sub'); 30299 }, 30300 formatSup: function() 30301 { 30302 this.inline.format('sup'); 30303 } 30304 }; 30305 }; 30306})(jQuery); 30307(function($) 30308{ 30309 $.Redactor.prototype.hubbletoken = function() 30310 { 30311 return { 30312 init: function() 30313 { 30314 var that = this; 30315 var dropdown = {}; 30316 30317 dropdown.honorific = { title: 'Honorific', func: that.hubbletoken.insertHonorific }; 30318 dropdown.first_name = { title: 'First name', func: that.hubbletoken.insertFirstName }; 30319 dropdown.last_name = { title: 'Last name', func: that.hubbletoken.insertLastName }; 30320 dropdown.organisation = { title: 'Organisation', func: that.hubbletoken.insertOrganisation }; 30321 dropdown.create_account_button = { title: 'Create account button', func: that.hubbletoken.insertCreateAccountButton }; 30322 dropdown.direct_debit_button = { title: 'Direct Debit button', func: that.hubbletoken.insertDirectDebitButton }; 30323 dropdown.organisation_direct_debit_button = { title: 'Organisation Direct Debit button', func: that.hubbletoken.insertOrganisationDirectDebitButton }; 30324 30325 var button = this.button.add('token', 'Token'); 30326 this.button.setIcon(button, '<i class="mdi mdi-contain"></i>'); 30327 this.button.addDropdown(button, dropdown); 30328 }, 30329 insertHonorific: function() 30330 {
30331 html = '[honorific]' 30332 this.insert.html(html); 30333 }, 30334 insertFirstName: function() 30335 { 30336 html = '[first_name]' 30337 this.insert.html(html); 30338 }, 30339 insertLastName: function() 30340 { 30341 html = '[last_name]' 30342 this.insert.html(html); 30343 }, 30344 insertEmail: function() 30345 { 30346 html = '[email]' 30347 this.insert.html(html); 30348 }, 30349 insertAddress: function() 30350 { 30351 html = '[address]' 30352 this.insert.html(html); 30353 }, 30354 insertPhone: function() 30355 { 30356 html = '[phone]' 30357 this.insert.html(html); 30358 }, 30359 insertWebsite: function() 30360 { 30361 html = '[website]' 30362 this.insert.html(html); 30363 }, 30364 insertOrganisation: function() 30365 { 30366 html = '[organisation]' 30367 this.insert.html(html); 30368 }, 30369 insertCreateAccountButton: function() 30370 { 30371 html = '[create_account_button]' 30372 this.insert.html(html); 30373 }, 30374 insertDirectDebitButton: function() 30375 { 30376 html = '[direct_debit_button]' 30377 this.insert.html(html); 30378 }, 30379 insertOrganisationDirectDebitButton: function() 30380 { 30381 html = '[organisation_direct_debit_button]' 30382 this.insert.html(html); 30383 } 30384 }; 30385 }; 30386})(jQuery); 30387(function($) 30388{ 30389 $.Redactor.prototype.imagemanager = function() 30390 { 30391 return { 30392 langs: { 30393 en: { 30394 "upload": "Upload", 30395 "choose": "Choose" 30396 } 30397 }, 30398 init: function() 30399 { 30400 if (!this.opts.imageManagerJson) 30401 { 30402 return; 30403 } 30404 30405 this.modal.addCallback('image', this.imagemanager.load); 30406 }, 30407 load: function() 30408 { 30409 var $box = $('<div style="overflow: auto; height: 300px; display: none;" class="redactor-modal-tab" data-title="Choose">'); 30410 this.modal.getModal().append($box); 30411 30412 $.ajax({ 30413 dataType: "json", 30414 cache: false, 30415 url: this.opts.imageManagerJson, 30416 success: $.proxy(function(data) 30417 { 30418 $.each(data, $.proxy(function(key, val) 30419 { 30420 // title 30421 var thumbtitle = ''; 30422 if (typeof val.title !== 'undefined') 30423 { 30424 thumbtitle = val.title; 30425 } 30426 30427 var img = $('<img src="' + val.thumb + '" data-params="' + encodeURI(JSON.stringify(val)) + '" style="width: 100px; height: 75px; cursor: pointer;" />'); 30428 $box.append(img); 30429 $(img).click($.proxy(this.imagemanager.insert, this)); 30430 30431 }, this)); 30432 30433 }, this) 30434 }); 30435 30436 30437 }, 30438 insert: function(e) 30439 { 30440 var $el = $(e.target); 30441 var json = $.parseJSON(decodeURI($el.attr('data-params'))); 30442 30443 this.image.insert(json, null); 30444 } 30445 }; 30446 }; 30447})(jQuery); 30448(function($) 30449{ 30450 $.Redactor.prototype.source = function() 30451 { 30452 return { 30453 init: function() 30454 { 30455 var button = this.button.addFirst('html', 'HTML'); 30456 this.button.setIcon(button, '<i class="re-icon-html"></i>'); 30457 this.button.addCallback(button, this.source.toggle); 30458 30459 var style = { 30460 'width': '100%', 30461 'margin': '0', 30462 'background': '#1d1d1d', 30463 'box-sizing': 'border-box', 30464 'color': '#ccc', 30465 'font-size': '15px', 30466 'outline': 'none', 30467 'padding': '20px', 30468 'line-height': '24px', 30469 'font-family': 'Consolas, Menlo, Monaco, "Courier New", monospace' 30470 }; 30471 30472 this.source.$textarea = $('<textarea />'); 30473 this.source.$textarea.css(style).hide(); 30474 30475 if (this.opts.type === 'textarea') 30476 { 30477 this.core.box().append(this.source.$textarea); 30478 } 30479 else 30480 { 30481 this.core.box().after(this.source.$textarea); 30482 } 30483 30484 this.core.element().on('destroy.callback.redactor', $.proxy(function() 30485 { 30486 this.source.$textarea.remove(); 30487 30488 }, this)); 30489 30490 }, 30491 toggle: function() 30492 { 30493 return (this.source.$textarea.hasClass('open')) ? this.source.hide() : this.source.show(); 30494 }, 30495 setCaretOnShow: function() 30496 { 30497 this.source.offset = this.offset.get(); 30498 var scroll = $(window).scrollTop(); 30499 30500 var width = this.core.editor().innerWidth(); 30501 var height = this.core.editor().innerHeight(); 30502 30503 // caret position sync 30504 this.source.start = 0; 30505 this.source.end = 0; 30506 var $editorDiv = $("<div/>").append($.parseHTML(this.core.editor().html(), document, true)); 30507 var $selectionMarkers = $editorDiv.find("span.redactor-selection-marker"); 30508 30509 if ($selectionMarkers.length > 0) 30510 { 30511 var editorHtml = $editorDiv.html().replace(/&/g, '&'); 30512 30513 if ($selectionMarkers.length === 1) 30514 { 30515 this.source.start = this.utils.strpos(editorHtml, $editorDiv.find("#selection-marker-1").prop("outerHTML")); 30516 this.source.end = this.source.start; 30517 } 30518 else if ($selectionMarkers.length === 2) 30519 { 30520 this.source.start = this.utils.strpos(editorHtml, $editorDiv.find("#selection-marker-1").prop("outerHTML")); 30521 this.source.end = this.utils.strpos(editorHtml, $editorDiv.find("#selection-marker-2").prop("outerHTML")) - $editorDiv.find("#selection-marker-1").prop("outerHTML").toString().length; 30522 } 30523 } 30524 }, 30525 setCaretOnHide: function(html) 30526 { 30527 this.source.start = this.source.$textarea.get(0).selectionStart; 30528 this.source.end = this.source.$textarea.get(0).selectionEnd; 30529 30530 // if selection starts from end 30531 if (this.source.start > this.source.end && this.source.end > 0) 30532 { 30533 var tempStart = this.source.end; 30534 var tempEnd = this.source.start; 30535 30536 this.source.start = tempStart; 30537 this.source.end = tempEnd; 30538 } 30539 30540 this.source.start = this.source.enlargeOffset(html, this.source.start); 30541 this.source.end = this.source.enlargeOffset(html, this.source.end); 30542 30543 html = html.substr(0, this.source.start) + this.marker.html(1) + html.substr(this.source.start); 30544 30545 if (this.source.end > this.source.start) 30546 { 30547 var markerLength = this.marker.html(1).toString().length; 30548 30549 html = html.substr(0, this.source.end + markerLength) + this.marker.html(2) + html.substr(this.source.end + markerLength); 30550 } 30551 30552 30553 return html; 30554 30555 }, 30556 hide: function() 30557 { 30558 this.source.$textarea.removeClass('open').hide(); 30559 this.source.$textarea.off('.redactor-source'); 30560 30561 var code = this.source.$textarea.val(); 30562 30563 code = this.paragraphize.load(code); 30564 code = this.source.setCaretOnHide(code); 30565 30566 this.code.start(code); 30567 this.button.enableAll(); 30568 this.core.editor().show().focus();
30569 this.selection.restore(); 30570 30571 this.core.callback('visual'); 30572 }, 30573 show: function() 30574 { 30575 this.selection.save(); 30576 this.source.setCaretOnShow(); 30577 30578 var height = this.core.editor().height(); 30579 var code = this.code.get(); 30580 30581 // callback 30582 code = this.core.callback('source', code); 30583 30584 this.core.editor().hide(); 30585 this.button.disableAll('html'); 30586 30587 this.source.$textarea.val(code).height(height).addClass('open').show(); 30588 this.source.$textarea.on('keyup.redactor-source', $.proxy(function() 30589 { 30590 if (this.opts.type === 'textarea') 30591 { 30592 this.core.textarea().val(this.source.$textarea.val()); 30593 } 30594 30595 }, this)); 30596 30597 this.marker.remove(); 30598 30599 $(window).scrollTop(scroll); 30600 30601 if (this.source.$textarea[0].setSelectionRange) 30602 { 30603 this.source.$textarea[0].setSelectionRange(this.source.start, this.source.end); 30604 } 30605 30606 this.source.$textarea[0].scrollTop = 0; 30607 30608 setTimeout($.proxy(function() 30609 { 30610 this.source.$textarea.focus(); 30611 30612 }, this), 0); 30613 }, 30614 enlargeOffset: function(html, offset) 30615 { 30616 var htmlLength = html.length; 30617 var c = 0; 30618 30619 if (html[offset] === '>') 30620 { 30621 c++; 30622 } 30623 else 30624 { 30625 for(var i = offset; i <= htmlLength; i++) 30626 { 30627 c++; 30628 30629 if (html[i] === '>') 30630 { 30631 break; 30632 } 30633 else if (html[i] === '<' || i === htmlLength) 30634 { 30635 c = 0; 30636 break; 30637 } 30638 } 30639 } 30640 30641 return offset + c; 30642 } 30643 }; 30644 }; 30645})(jQuery); 30646(function($) 30647{ 30648 $.Redactor.prototype.table = function() 30649 { 30650 return { 30651 langs: { 30652 en: { 30653 "table": "Table", 30654 "insert-table": "Insert table", 30655 "insert-row-above": "Insert row above", 30656 "insert-row-below": "Insert row below", 30657 "insert-column-left": "Insert column left", 30658 "insert-column-right": "Insert column right", 30659 "add-head": "Add head", 30660 "delete-head": "Delete head", 30661 "delete-column": "Delete column", 30662 "delete-row": "Delete row", 30663 "delete-table": "Delete table" 30664 } 30665 }, 30666 init: function() 30667 { 30668 var dropdown = {}; 30669 30670 dropdown.insert_table = { 30671 title: this.lang.get('insert-table'), 30672 func: this.table.insert, 30673 observe: { 30674 element: 'table', 30675 in: { 30676 attr: { 30677 'class': 'redactor-dropdown-link-inactive', 30678 'aria-disabled': true, 30679 } 30680 } 30681 } 30682 }; 30683 30684 dropdown.insert_row_above = { 30685 title: this.lang.get('insert-row-above'), 30686 func: this.table.addRowAbove, 30687 observe: { 30688 element: 'table', 30689 out: { 30690 attr: { 30691 'class': 'redactor-dropdown-link-inactive', 30692 'aria-disabled': true, 30693 } 30694 } 30695 } 30696 }; 30697 30698 dropdown.insert_row_below = { 30699 title: this.lang.get('insert-row-below'), 30700 func: this.table.addRowBelow, 30701 observe: { 30702 element: 'table', 30703 out: { 30704 attr: { 30705 'class': 'redactor-dropdown-link-inactive', 30706 'aria-disabled': true, 30707 } 30708 } 30709 } 30710 }; 30711 30712 dropdown.insert_column_left = { 30713 title: this.lang.get('insert-column-left'), 30714 func: this.table.addColumnLeft, 30715 observe: { 30716 element: 'table', 30717 out: { 30718 attr: { 30719 'class': 'redactor-dropdown-link-inactive', 30720 'aria-disabled': true, 30721 } 30722 } 30723 } 30724 }; 30725 30726 dropdown.insert_column_right = { 30727 title: this.lang.get('insert-column-right'), 30728 func: this.table.addColumnRight, 30729 observe: { 30730 element: 'table', 30731 out: { 30732 attr: { 30733 'class': 'redactor-dropdown-link-inactive', 30734 'aria-disabled': true, 30735 } 30736 } 30737 } 30738 }; 30739 30740 dropdown.add_head = { 30741 title: this.lang.get('add-head'), 30742 func: this.table.addHead, 30743 observe: { 30744 element: 'table', 30745 out: { 30746 attr: { 30747 'class': 'redactor-dropdown-link-inactive', 30748 'aria-disabled': true, 30749 } 30750 } 30751 } 30752 }; 30753 30754 dropdown.delete_head = { 30755 title: this.lang.get('delete-head'), 30756 func: this.table.deleteHead, 30757 observe: { 30758 element: 'table', 30759 out: { 30760 attr: { 30761 'class': 'redactor-dropdown-link-inactive', 30762 'aria-disabled': true, 30763 } 30764 } 30765 } 30766 }; 30767 30768 dropdown.delete_column = { 30769 title: this.lang.get('delete-column'), 30770 func: this.table.deleteColumn, 30771 observe: { 30772 element: 'table', 30773 out: { 30774 attr: { 30775 'class': 'redactor-dropdown-link-inactive', 30776 'aria-disabled': true, 30777 } 30778 } 30779 } 30780 }; 30781 30782 dropdown.delete_row = { 30783 title: this.lang.get('delete-row'), 30784 func: this.table.deleteRow, 30785 observe: { 30786 element: 'table', 30787 out: { 30788 attr: { 30789 'class': 'redactor-dropdown-link-inactive', 30790 'aria-disabled': true, 30791 } 30792 } 30793 } 30794 }; 30795 30796 dropdown.delete_table = { 30797 title: this.lang.get('delete-table'), 30798 func: this.table.deleteTable, 30799 observe: { 30800 element: 'table', 30801 out: { 30802 attr: { 30803 'class': 'redactor-dropdown-link-inactive', 30804 'aria-disabled': true, 30805 } 30806 } 30807 } 30808 }; 30809 30810 30811 var button = this.button.addBefore('link', 'table', this.lang.get('table')); 30812 this.button.setIcon(button, '<i class="re-icon-table"></i>'); 30813 this.button.addDropdown(button, dropdown); 30814 }, 30815 insert: function() 30816 { 30817 if (this.table.getTable()) 30818 { 30819 return; 30820 } 30821 30822 this.placeholder.hide(); 30823 30824 var rows = 2; 30825 var columns = 3; 30826 var $tableBox = $('<div>'); 30827 var $table = $('<table />'); 30828 30829 for (var i = 0; i < rows; i++) 30830 { 30831 var $row = $('<tr>'); 30832 30833 for (var z = 0; z < columns; z++) 30834 { 30835 var $column = $('<td>' + this.opts.invisibleSpace + '</td>'); 30836 30837 // set the focus to the first td 30838 if (i === 0 && z === 0) 30839 { 30840 $column.append(this.marker.get()); 30841 } 30842 30843 $($row).append($column); 30844 } 30845 30846 $table.append($row); 30847 } 30848 30849 $tableBox.append($table); 30850 var html = $tableBox.html(); 30851 30852 this.buffer.set(); 30853 30854 var current = this.selection.current(); 30855 if ($(current).closest('li', this.core.editor()[0]).length !== 0) 30856 { 30857 $(current).closest('ul, ol').first().after(html); 30858 } 30859 else 30860 { 30861 this.air.collapsed(); 30862 this.insert.html(html); 30863 } 30864
30865 this.selection.restore(); 30866 this.core.callback('insertedTable', $table); 30867 }, 30868 getTable: function() 30869 { 30870 var $table = $(this.selection.current()).closest('table'); 30871 30872 if (!this.utils.isRedactorParent($table)) 30873 { 30874 return false; 30875 } 30876 30877 if ($table.length === 0) 30878 { 30879 return false; 30880 } 30881 30882 return $table; 30883 }, 30884 restoreAfterDelete: function($table) 30885 { 30886 this.selection.restore(); 30887 $table.find('span.redactor-selection-marker').remove(); 30888 30889 }, 30890 deleteTable: function() 30891 { 30892 var $table = this.table.getTable(); 30893 if (!$table) 30894 { 30895 return; 30896 } 30897 30898 this.buffer.set(); 30899 30900 30901 var $next = $table.next(); 30902 if (!this.opts.linebreaks && $next.length !== 0) 30903 { 30904 this.caret.start($next); 30905 } 30906 else 30907 { 30908 this.caret.after($table); 30909 } 30910 30911 30912 $table.remove(); 30913 30914 30915 }, 30916 deleteRow: function() 30917 { 30918 var $table = this.table.getTable(); 30919 if (!$table) 30920 { 30921 return; 30922 } 30923 30924 var $current = $(this.selection.current()); 30925 30926 this.buffer.set(); 30927 30928 var $current_tr = $current.closest('tr'); 30929 var $focus_tr = $current_tr.prev().length ? $current_tr.prev() : $current_tr.next(); 30930 if ($focus_tr.length) 30931 { 30932 var $focus_td = $focus_tr.children('td, th').first(); 30933 if ($focus_td.length) 30934 { 30935 $focus_td.prepend(this.marker.get()); 30936 } 30937 } 30938 30939 $current_tr.remove(); 30940 this.table.restoreAfterDelete($table); 30941 }, 30942 deleteColumn: function() 30943 { 30944 var $table = this.table.getTable(); 30945 if (!$table) 30946 { 30947 return; 30948 } 30949 30950 this.buffer.set(); 30951 30952 var $current = $(this.selection.current()); 30953 var $current_td = $current.closest('td, th'); 30954 var index = $current_td[0].cellIndex; 30955 30956 $table.find('tr').each($.proxy(function(i, elem) 30957 { 30958 var $elem = $(elem); 30959 var focusIndex = index - 1 < 0 ? index + 1 : index - 1; 30960 if (i === 0) 30961 { 30962 $elem.find('td, th').eq(focusIndex).prepend(this.marker.get()); 30963 } 30964 30965 $elem.find('td, th').eq(index).remove(); 30966 30967 }, this)); 30968 30969 this.table.restoreAfterDelete($table); 30970 }, 30971 addHead: function() 30972 { 30973 var $table = this.table.getTable(); 30974 if (!$table) 30975 { 30976 return; 30977 } 30978 30979 this.buffer.set(); 30980 30981 if ($table.find('thead').length !== 0) 30982 { 30983 this.table.deleteHead(); 30984 return; 30985 } 30986 30987 var tr = $table.find('tr').first().clone(); 30988 tr.find('td').replaceWith($.proxy(function() 30989 { 30990 return $('<th>').html(this.opts.invisibleSpace); 30991 }, this)); 30992 30993 $thead = $('<thead></thead>').append(tr); 30994 $table.prepend($thead); 30995 30996 30997 30998 }, 30999 deleteHead: function() 31000 { 31001 var $table = this.table.getTable(); 31002 if (!$table) 31003 { 31004 return; 31005 } 31006 31007 var $thead = $table.find('thead'); 31008 if ($thead.length === 0) 31009 { 31010 return; 31011 } 31012 31013 this.buffer.set(); 31014 31015 $thead.remove(); 31016 31017 }, 31018 addRowAbove: function() 31019 { 31020 this.table.addRow('before'); 31021 }, 31022 addRowBelow: function() 31023 { 31024 this.table.addRow('after'); 31025 }, 31026 addColumnLeft: function() 31027 { 31028 this.table.addColumn('before'); 31029 }, 31030 addColumnRight: function() 31031 { 31032 this.table.addColumn('after'); 31033 }, 31034 addRow: function(type) 31035 { 31036 var $table = this.table.getTable(); 31037 if (!$table) 31038 { 31039 return; 31040 } 31041 31042 this.buffer.set(); 31043 31044 var $current = $(this.selection.current()); 31045 var $current_tr = $current.closest('tr'); 31046 var new_tr = $current_tr.clone(); 31047 31048 new_tr.find('th').replaceWith(function() 31049 { 31050 var $td = $('<td>'); 31051 $td[0].attributes = this.attributes; 31052 31053 return $td.append($(this).contents()); 31054 }); 31055 31056 new_tr.find('td').html(this.opts.invisibleSpace); 31057 31058 if (type === 'after') 31059 { 31060 $current_tr.after(new_tr); 31061 } 31062 else 31063 { 31064 $current_tr.before(new_tr); 31065 } 31066 31067 31068 }, 31069 addColumn: function (type) 31070 { 31071 var $table = this.table.getTable(); 31072 if (!$table) 31073 { 31074 return; 31075 } 31076 31077 var index = 0; 31078 var current = $(this.selection.current()); 31079 31080 this.buffer.set(); 31081 31082 var $current_tr = current.closest('tr'); 31083 var $current_td = current.closest('td, th'); 31084 31085 $current_tr.find('td, th').each($.proxy(function(i, elem) 31086 { 31087 if ($(elem)[0] === $current_td[0]) 31088 { 31089 index = i; 31090 } 31091 31092 }, this)); 31093 31094 $table.find('tr').each($.proxy(function(i, elem) 31095 { 31096 var $current = $(elem).find('td, th').eq(index); 31097 31098 var td = $current.clone(); 31099 td.html(this.opts.invisibleSpace); 31100 31101 if (type === 'after') 31102 { 31103 $current.after(td); 31104 } 31105 else 31106 { 31107 $current.before(td); 31108 } 31109 31110 }, this)); 31111 31112 31113 } 31114 }; 31115 }; 31116})(jQuery); 31117(function($) 31118{ 31119 $.Redactor.prototype.video = function() 31120 { 31121 return {
31122 reUrlYoutube: /https?:\/\/(?:[0-9A-Z-]+\.)?(?:youtu\.be\/|youtube\.com\S*[^\w\-\s])([\w\-]{11})(?=[^\w\-]|$)(?![?=&+%\w.-]*(?:['"][^<>]*>|<\/a>))[?=&+%\w.-]*/ig, 31123 reUrlVimeo: /https?:\/\/(www\.)?vimeo.com\/(\d+)($|\/)/, 31124 langs: { 31125 en: { 31126 "video": "Video", 31127 "video-html-code": "Video Embed Code or Youtube/Vimeo Link" 31128 } 31129 }, 31130 getTemplate: function() 31131 { 31132 return String() 31133 + '<div class="modal-section" id="redactor-modal-video-insert">' 31134 + '<section>' 31135 + '<label>' + this.lang.get('video-html-code') + '</label>' 31136 + '<textarea id="redactor-insert-video-area" style="height: 160px;"></textarea>' 31137 + '</section>' 31138 + '<section>' 31139 + '<button id="redactor-modal-button-action">Insert</button>' 31140 + '<button id="redactor-modal-button-cancel">Cancel</button>' 31141 + '</section>' 31142 + '</div>'; 31143 }, 31144 init: function() 31145 { 31146 var button = this.button.addAfter('image', 'video', this.lang.get('video')); 31147 this.button.setIcon(button, '<i class="re-icon-video"></i>'); 31148 this.button.addCallback(button, this.video.show); 31149 }, 31150 show: function() 31151 { 31152 this.modal.addTemplate('video', this.video.getTemplate()); 31153 31154 this.modal.load('video', this.lang.get('video'), 700); 31155 31156 // action button 31157 this.modal.getActionButton().text(this.lang.get('insert')).on('click', this.video.insert); 31158 this.modal.show(); 31159 31160 // focus 31161 if (this.detect.isDesktop()) 31162 { 31163 setTimeout(function() 31164 { 31165 $('#redactor-insert-video-area').focus(); 31166 31167 }, 1); 31168 } 31169 31170 31171 }, 31172 insert: function() 31173 { 31174 var data = $('#redactor-insert-video-area').val(); 31175 31176 if (!data.match(/<iframe|<video/gi)) 31177 { 31178 data = this.clean.stripTags(data); 31179 31180 this.opts.videoContainerClass = (typeof this.opts.videoContainerClass === 'undefined') ? 'video-container' : this.opts.videoContainerClass; 31181 31182 // parse if it is link on youtube & vimeo 31183 var iframeStart = '<div class="' + this.opts.videoContainerClass + '"><iframe style="width: 500px; height: 281px;" src="', 31184 iframeEnd = '" frameborder="0" allowfullscreen></iframe></div>'; 31185 31186 if (data.match(this.video.reUrlYoutube)) 31187 { 31188 data = data.replace(this.video.reUrlYoutube, iframeStart + '//www.youtube.com/embed/$1' + iframeEnd); 31189 } 31190 else if (data.match(this.video.reUrlVimeo)) 31191 { 31192 data = data.replace(this.video.reUrlVimeo, iframeStart + '//player.vimeo.com/video/$2' + iframeEnd); 31193 } 31194 } 31195 31196 this.modal.close(); 31197 this.placeholder.hide(); 31198 31199 // buffer 31200 this.buffer.set(); 31201 31202 // insert 31203 this.air.collapsed(); 31204 this.insert.html(data); 31205 31206 } 31207 31208 }; 31209 }; 31210})(jQuery); 31211 31212function start_search($subdomain, $content_type, $search, $index) { 31213 31214 $('div#menu ul.menu li a').each(function(){ 31215 $(this).click(function(e){ 31216 //$(this).toggleClass('active'); 31217 $('div#menu ul.menu li a').removeClass('active'); 31218 $(this).addClass('active'); 31219 $search.data('page', '1'); 31220 process_search($subdomain, $content_type, $search, $index, get_query(), get_filters()); 31221 e.preventDefault(); 31222 }); 31223 }); 31224 31225 process_search($subdomain, $content_type, $search, $index, get_query(), get_filters()); 31226 $('input#query').keyup(function(){ 31227 $search.data('page', '1'); 31228 process_search($subdomain, $content_type, $search, $index, get_query(), get_filters()); 31229 }); 31230 31231} 31232 31233function get_query() { 31234 31235 return $('input#query').val() 31236 31237} 31238 31239function get_filters() { 31240 31241 $filters = []; 31242 $('div#menu ul.menu li a.active').each(function(){ 31243 $filters.push($(this).text()); 31244 }); 31245 return $filters 31246 31247} 31248 31249function process_search($subdomain, $content_type, $search, $index, $query, $filters) { 31250 31251 $base_filters = 'active=1 AND status=1 AND displayed=1'; 31252 if ($content_type == 'Event') { 31253 $current_date = Math.floor((new Date().getTime())/1000); 31254 $base_filters += ' AND start_date>='+$current_date; 31255 } 31256 31257 $index.search($('input#query').val(), { hitsPerPage: parseInt($search.data('rows')), page: (parseInt($search.data('page'))-1), filters: $base_filters, tagFilters: $.merge(['tenant_'+$subdomain], $filters) }) 31258 .then(function searchDone($response) { 31259 refresh_search_results($subdomain, $content_type, $search, $index, $query, $filters, $response); 31260 }) 31261 .catch(function searchFailure($response) { 31262 console.error($response); 31263 }); 31264 31265} 31266 31267function refresh_search_results($subdomain, $content_type, $search, $index, $query, $filters, $response) { 31268 31269 $('div#results', $search).html(''); 31270 $('div.pagination', $search).remove(); 31271 if ($response.hits.length > 0) { 31272 if ($response.nbPages > 1) { 31273 $pagination = $('<div class="pagination clearfix"></div>'); 31274 $back_span = $('<span class="back"></span>'); 31275 if ($response.page > 0) { 31276 $back_link = $('<a href="#" class="back button"><span class="mdi mdi-chevron-left"></span>Back</a>'); 31277 $back_link.click(function(e){ 31278 $search.data('page', (parseInt($search.data('page')) - 1)); 31279 process_search($subdomain, $content_type, $search, $index, $query, $filters); 31280 $(window).scrollTop($('div#main').offset().top); 31281 e.preventDefault(); 31282 }); 31283 $back_span.append($back_link); 31284 } 31285 $pagination.append($back_span); 31286 $pagination.append($('<span class="count">Page '+($response.page+1)+' of '+$response.nbPages+'</span>')); 31287 $next_span = $('<span class="next"></span>'); 31288 if (($response.page+1) < $response.nbPages) { 31289 $next_link = $('<a href="#" class="next button">Next<span class="mdi mdi-chevron-right"></span></a>'); 31290 $next_link.click(function(e){ 31291 $search.data('page', (parseInt($search.data('page')) + 1)); 31292 process_search($subdomain, $content_type, $search, $index, $query, $filters); 31293 $(window).scrollTop($('div#main').offset().top); 31294 e.preventDefault(); 31295 }); 31296 $next_span.append($next_link); 31297 } 31298 $pagination.append($next_span); 31299 $search.append($pagination); 31300 }
31301 $.each($response.hits, function($key, $record) { 31302 $('div#results', $search).append('<div class="panel">'+$record.teaser+'</div>') 31303 }); 31304 } else { 31305 $('div#results', $search).append('<div class="panel"><strong>There are no '+$content_type.toLowerCase()+'s to display.</strong></div>') 31306 } 31307 31308}; 31309 31310 31311function start_segments() { 31312 31313 $('table.segments tr.filter').each(function(){ 31314 $('td.field label', $(this)).text(($('td.field select', $(this)).val() != '') ? $('td.field select option:selected', $(this)).parent().attr('label') : ' '); 31315 refresh_selects($(this)); 31316 $('td.field select', $(this)).change(function(){ 31317 refresh_filter($(this).parents('tr.filter')); 31318 }); 31319 $('td.actions input', $(this)).change(function(){ 31320 refresh_filter_delete($(this).parents('tr.filter')); 31321 }); 31322 }); 31323 31324 $('a.add_filter').each(function(){ 31325 attach_add_filter($(this)); 31326 }); 31327 31328 $('a.add_filterset').click(function($event){ 31329 time = new Date().getTime(); 31330 regexp = new RegExp($(this).data('id'), 'g') 31331 $('div#filtersets').append($(this).data('fields').replace(regexp, time)); 31332 $('a.add_filter').each(function(){ 31333 attach_add_filter($(this)); 31334 }); 31335 $filter = $('div#filtersets tr.filter:last'); 31336 refresh_filter($filter); 31337 $('td.field select', $filter).change(function(){ 31338 refresh_filter($(this).parents('tr.filter')); 31339 }); 31340 $('td.actions span.delete', $filter).click(function($event){ 31341 delete_filter($(this).parents('tr.filter')); 31342 $event.preventDefault(); 31343 }); 31344 $event.preventDefault(); 31345 }); 31346 31347 $('td.actions span.delete').click(function($event){ 31348 delete_filter($(this).parents('tr.filter')); 31349 $event.preventDefault(); 31350 }); 31351 31352} 31353 31354function attach_add_filter($link) { 31355 31356 $link.click(function($event){ 31357 time = new Date().getTime(); 31358 regexp = new RegExp($(this).data('id'), 'g') 31359 $('table.segments tbody.filterset', $(this).parents('div.box')).append($(this).data('fields').replace(regexp, time)); 31360 $filter = $('table.segments tr.filter:last', $(this).parents('div.box')); 31361 refresh_filter($filter); 31362 $('td.field select', $filter).change(function(){ 31363 refresh_filter($(this).parents('tr.filter')); 31364 }); 31365 $('td.actions span.delete', $filter).click(function($event){ 31366 delete_filter($(this).parents('tr.filter')); 31367 $event.preventDefault(); 31368 }); 31369 $event.preventDefault(); 31370 }); 31371 31372} 31373 31374function refresh_filter($filter) { 31375 31376 $('td.field label', $filter).text(($('td.field select', $filter).val() != '') ? $('td.field select option:selected', $filter).parent().attr('label') : ' '); 31377 $('td.match select', $filter).hide(); 31378 $('td.value input', $filter).hide(); 31379 $('td.value input', $filter).val(''); 31380 $('td.value select', $filter).remove(); 31381 refresh_filter_delete($filter); 31382 if ($('td.field select', $filter).val() != '') { 31383 switch ($('td.field option:selected', $filter).attr('class')) { 31384 case 'text': 31385 $match_options = [ 31386 ['contains', 'contains'], 31387 ['is exactly', 'exact'], 31388 ['starts with', 'starts'], 31389 ['ends with', 'ends'], 31390 ['is present', 'present'], 31391 ['is absent', 'absent'] 31392 ]; 31393 refresh_selects($filter); 31394 break; 31395 case 'date': 31396 $match_options = [ 31397 ['is on or before', 'before'], 31398 ['is on or after', 'after'] 31399 ]; 31400 refresh_selects($filter); 31401 break; 31402 case 'date_relative': 31403 $match_options = [ 31404 ['is in the next', 'next'], 31405 ['is in the past', 'past'] 31406 ]; 31407 refresh_selects($filter); 31408 break; 31409 case 'options': 31410 $match_options = [ 31411 ['is', 'is'], 31412 ['is not', 'is_not'] 31413 ]; 31414 refresh_selects($filter); 31415 break; 31416 case 'association': 31417 $match_options = [ 31418 ['is', 'is'], 31419 ['is not', 'is_not'] 31420 ]; 31421 refresh_selects($filter); 31422 break; 31423 case 'field-text': 31424 $match_options = [ 31425 ['contains', 'contains'], 31426 ['is exactly', 'exact'], 31427 ['starts with', 'starts'], 31428 ['ends with', 'ends'], 31429 ['is present', 'present'], 31430 ['is absent', 'absent'] 31431 ]; 31432 refresh_selects($filter); 31433 break; 31434 case 'field-textarea': 31435 $match_options = [ 31436 ['contains', 'contains'], 31437 ['is exactly', 'exact'], 31438 ['starts with', 'starts'], 31439 ['ends with', 'ends'], 31440 ['is present', 'present'], 31441 ['is absent', 'absent'] 31442 ]; 31443 refresh_selects($filter); 31444 break; 31445 case 'field-date': 31446 $match_options = [ 31447 ['is on or before', 'before'], 31448 ['is on or after', 'after'], 31449 ['is present', 'present'], 31450 ['is absent', 'absent'] 31451 ]; 31452 refresh_selects($filter); 31453 break; 31454 case 'field-file': 31455 $match_options = [ 31456 ['is present', 'present'], 31457 ['is absent', 'absent'] 31458 ]; 31459 refresh_selects($filter); 31460 break; 31461 case 'field-select': 31462 $match_options = [ 31463 ['is', 'is'], 31464 ['is not', 'is_not'] 31465 ]; 31466 refresh_selects($filter); 31467 break; 31468 case 'field-radios': 31469 $match_options = [ 31470 ['is', 'is'], 31471 ['is not', 'is_not'] 31472 ]; 31473 refresh_selects($filter); 31474 break; 31475 case 'field-checkboxes': 31476 $match_options = [ 31477 ['is', 'is'], 31478 ['is not', 'is_not'] 31479 ]; 31480 refresh_selects($filter); 31481 break; 31482 default: 31483 $match_options = []; 31484 break; 31485 } 31486 $('td.match select option', $filter).remove(); 31487 $.each($match_options, function($index, $option){ 31488 $('td.match select', $filter).append('<option value="'+$option[1]+'">'+$option[0]+'</option>') 31489 }); 31490 $('td.match select', $filter).show(); 31491 } 31492 31493} 31494 31495function refresh_selects($filter) { 31496 31497 $field_select = $('td.field select', $filter); 31498 $match_select = $('td.match select', $filter); 31499 $match_select.hide(); 31500 $match_select.off('change'); 31501 if ($field_select.val() != '') { 31502 $match_select.show(); 31503 } 31504 $input = $('td.value input', $filter); 31505 $input.hide(); 31506 switch ($('option:selected', $field_select).attr('class')) { 31507 case 'text': 31508 $input.attr('type', 'text'); 31509 $input.show(); 31510 break; 31511 case 'date': 31512 $input.attr('type', 'date'); 31513 $input.show(); 31514 break; 31515 case 'date_relative': 31516 $value_options = []; 31517 switch ($('td.field select', $filter).val()) { 31518 case 'booking_date_relative': 31519 $value_options = [["1 day", "1_day"],["3 days", "3_days"],["1 week", "1_week"],["2 weeks", "2_weeks"],["1 month", "1_month"],["3 months", "3_months"],["6 months", "6_months"],["1 year", "1_year"]] 31520 break; 31521 case 'membership_created_relative': 31522 $value_options = [["1 day", "1_day"],["3 days", "3_days"],["1 week", "1_week"],["2 weeks", "2_weeks"],["1 month", "1_month"],["3 months", "3_months"],["6 months", "6_months"],["1 year", "1_year"]] 31523 break; 31524 case 'membership_next_charge_relative': 31525 $value_options = [["1 day", "1_day"],["3 days", "3_days"],["1 week", "1_week"],["2 weeks", "2_weeks"],["1 month", "1_month"],["3 months", "3_months"],["6 months", "6_months"],["1 year", "1_year"]] 31526 break; 31527 case 'relationship_membership_created_relative': 31528 $value_options = [["1 day", "1_day"],["3 days", "3_days"],["1 week", "1_week"],["2 weeks", "2_weeks"],["1 month", "1_month"],["3 months", "3_months"],["6 months", "6_months"],["1 year", "1_year"]] 31529 break; 31530 case 'relationship_membership_next_charge_relative': 31531 $value_options = [["1 day", "1_day"],["3 days", "3_days"],["1 week", "1_week"],["2 weeks", "2_weeks"],["1 month", "1_month"],["3 months", "3_months"],["6 months", "6_months"],["1 year", "1_year"]] 31532 break; 31533 case 'affiliation_membership_created_relative': 31534 $value_options = [["1 day", "1_day"],["3 days", "3_days"],["1 week", "1_week"],["2 weeks", "2_weeks"],["1 month", "1_month"],["3 months", "3_months"],["6 months", "6_months"],["1 year", "1_year"]] 31535 break; 31536 case 'affiliation_membership_next_charge_relative': 31537 $value_options = [["1 day", "1_day"],["3 days", "3_days"],["1 week", "1_week"],["2 weeks", "2_weeks"],["1 month", "1_month"],["3 months", "3_months"],["6 months", "6_months"],["1 year", "1_year"]] 31538 break; 31539 case 'organisation_membership_created_relative': 31540 $value_options = [["1 day", "1_day"],["3 days", "3_days"],["1 week", "1_week"],["2 weeks", "2_weeks"],["1 month", "1_month"],["3 months", "3_months"],["6 months", "6_months"],["1 year", "1_year"]] 31541 break; 31542 case 'organisation_membership_next_charge_relative': 31543 $value_options = [["1 day", "1_day"],["3 days", "3_days"],["1 week", "1_week"],["2 weeks", "2_weeks"],["1 month", "1_month"],["3 months", "3_months"],["6 months", "6_months"],["1 year", "1_year"]] 31544 break; 31545 } 31546 $select = create_select($value_options, $input.val()); 31547 $select.attr('name', $input.attr('name')); 31548 $input.after($select); 31549 break; 31550 case 'options': 31551 $value_options = []; 31552 switch ($('td.field select', $filter).val()) { 31553 case 'address_country': 31554 $value_options = [["- Select country -", ""], ["United Kingdom", "GB"], ["Afghanistan", "AF"], ["Aland Islands", "AX"], ["Albania", "AL"], ["Algeria", "DZ"], ["American Samoa", "AS"], ["Andorra", "AD"], ["Angola", "AO"], ["Anguilla", "AI"], ["Antarctica", "AQ"], ["Antigua and Barbuda", "AG"], ["Argentina", "AR"], ["Armenia", "AM"], ["Aruba", "AW"], ["Australia", "AU"], ["Austr
31554ia", "AT"], ["Azerbaijan", "AZ"], ["Bahamas", "BS"], ["Bahrain", "BH"], ["Bangladesh", "BD"], ["Barbados", "BB"], ["Belarus", "BY"], ["Belgium", "BE"], ["Belize", "BZ"], ["Benin", "BJ"], ["Bermuda", "BM"], ["Bhutan", "BT"], ["Bolivia (Plurinational State of)", "BO"], ["Bonaire, Sint Eustatius and Saba", "BQ"], ["Bosnia and Herzegovina", "BA"], ["Botswana", "BW"], ["Bouvet Island", "BV"], ["Brazil", "BR"], ["British Indian Ocean Territory", "IO"], ["Brunei Darussalam", "BN"], ["Bulgaria", "BG"], ["Burkina Faso", "BF"], ["Burundi", "BI"], ["Cabo Verde", "CV"], ["Cambodia", "KH"], ["Cameroon", "CM"], ["Canada", "CA"], ["Cayman Islands", "KY"], ["Central African Republic", "CF"], ["Chad", "TD"], ["Chile", "CL"], ["China", "CN"], ["Christmas Island", "CX"], ["Cocos (Keeling) Islands", "CC"], ["Colombia", "CO"], ["Comoros", "KM"], ["Congo", "CG"], ["Congo (Democratic Republic of the)", "CD"], ["Cook Islands", "CK"], ["Costa Rica", "CR"], ["Croatia", "HR"], ["Cuba", "CU"], ["Curaçao", "CW"], ["Cyprus", "CY"], ["Czechia", "CZ"], ["Côte d'Ivoire", "CI"], ["Denmark", "DK"], ["Djibouti", "DJ"], ["Dominica", "DM"], ["Dominican Republic", "DO"], ["Ecuador", "EC"], ["Egypt", "EG"], ["El Salvador", "SV"], ["Equatorial Guinea", "GQ"], ["Eritrea", "ER"], ["Estonia", "EE"], ["Eswatini", "SZ"], ["Ethiopia", "ET"], ["Falkland Islands (Malvinas)", "FK"], ["Faroe Islands", "FO"], ["Fiji", "FJ"], ["Finland", "FI"], ["France", "FR"], ["French Guiana", "GF"], ["French Polynesia", "PF"], ["French Southern Territories", "TF"], ["Gabon", "GA"], ["Gambia", "GM"], ["Georgia", "GE"], ["Germany", "DE"], ["Ghana", "GH"], ["Gibraltar", "GI"], ["Greece", "GR"], ["Greenland", "GL"], ["Grenada", "GD"], ["Guadeloupe", "GP"], ["Guam", "GU"], ["Guatemala", "GT"], ["Guernsey", "GG"], ["Guinea", "GN"], ["Guinea-Bissau", "GW"], ["Guyana", "GY"], ["Haiti", "HT"], ["Heard Island and McDonald Islands", "HM"], ["Holy See", "VA"], ["Honduras", "HN"], ["Hong Kong", "HK"], ["Hungary", "HU"], ["Iceland", "IS"], ["India", "IN"], ["Indonesia", "ID"], ["Iran (Islamic Republic of)", "IR"], ["Iraq", "IQ"], ["Ireland", "IE"], ["Isle of Man", "IM"], ["Israel", "IL"], ["Italy", "IT"], ["Jamaica", "JM"], ["Japan", "JP"], ["Jersey", "JE"], ["Jordan", "JO"], ["Kazakhstan", "KZ"], ["Kenya", "KE"], ["Kiribati", "KI"], ["Korea (Democratic People's Republic of)", "KP"], ["Korea (Republic of)", "KR"], ["Kuwait", "KW"], ["Kyrgyzstan", "KG"], ["Lao People's Democratic Republic", "LA"], ["Latvia", "LV"], ["Lebanon", "LB"], ["Lesotho", "LS"], ["Liberia", "LR"], ["Libya", "LY"], ["Liechtenstein", "LI"], ["Lithuania", "LT"], ["Luxembourg", "LU"], ["Macao", "MO"], ["Madagascar", "MG"], ["Malawi", "MW"], ["Malaysia", "MY"], ["Maldives", "MV"], ["Mali", "ML"], ["Malta", "MT"], ["Marshall Islands", "MH"], ["Martinique", "MQ"], ["Mauritania", "MR"], ["Mauritius", "MU"], ["Mayotte", "YT"], ["Mexico", "MX"], ["Micronesia (Federated States of)", "FM"], ["Moldova (Republic of)", "MD"], ["Monaco", "MC"], ["Mongolia", "MN"], ["Montenegro", "ME"], ["Montserrat", "MS"], ["Morocco", "MA"], ["Mozambique", "MZ"], ["Myanmar", "MM"], ["Namibia", "NA"], ["Nauru", "NR"], ["Nepal", "NP"], ["Netherlands", "NL"], ["New Caledonia", "NC"], ["New Zealand", "NZ"], ["Nicaragua", "NI"], ["Niger", "
31554NE"], ["Nigeria", "NG"], ["Niue", "NU"], ["Norfolk Island", "NF"], ["North Macedonia", "MK"], ["Northern Mariana Islands", "MP"], ["Norway", "NO"], ["Oman", "OM"], ["Pakistan", "PK"], ["Palau", "PW"], ["Palestine, State of", "PS"], ["Panama", "PA"], ["Papua New Guinea", "PG"], ["Paraguay", "PY"], ["Peru", "PE"], ["Philippines", "PH"], ["Pitcairn", "PN"], ["Poland", "PL"], ["Portugal", "PT"], ["Puerto Rico", "PR"], ["Qatar", "QA"], ["Romania", "RO"], ["Russian Federation", "RU"], ["Rwanda", "RW"], ["Réunion", "RE"], ["Saint Barthélemy", "BL"], ["Saint Helena, Ascension and Tristan da Cunha", "SH"], ["Saint Kitts and Nevis", "KN"], ["Saint Lucia", "LC"], ["Saint Martin (French part)", "MF"], ["Saint Pierre and Miquelon", "PM"], ["Saint Vincent and the Grenadines", "VC"], ["Samoa", "WS"], ["San Marino", "SM"], ["Sao Tome and Principe", "ST"], ["Saudi Arabia", "SA"], ["Senegal", "SN"], ["Serbia", "RS"], ["Seychelles", "SC"], ["Sierra Leone", "SL"], ["Singapore", "SG"], ["Sint Maarten (Dutch part)", "SX"], ["Slovakia", "SK"], ["Slovenia", "SI"], ["Solomon Islands", "SB"], ["Somalia", "SO"], ["South Africa", "ZA"], ["South Georgia", "GS"], ["South Sudan", "SS"], ["Spain", "ES"], ["Sri Lanka", "LK"], ["Sudan", "SD"], ["Suriname", "SR"], ["Svalbard and Jan Mayen", "SJ"], ["Swede
31554n", "SE"], ["Switzerland", "CH"], ["Syrian Arab Republic", "SY"], ["Taiwan", "TW"], ["Tajikistan", "TJ"], ["Tanzania, United Republic of", "TZ"], ["Thailand", "TH"], ["Timor-Leste", "TL"], ["Togo", "TG"], ["Tokelau", "TK"], ["Tonga", "TO"], ["Trinidad and Tobago", "TT"], ["Tunisia", "TN"], ["Turkmenistan", "TM"], ["Turks and Caicos Islands", "TC"], ["Tuvalu", "TV"], ["Türkiye", "TR"], ["Uganda", "UG"], ["Ukraine", "UA"], ["United Arab Emirates", "AE"], ["United Kingdom", "GB"], ["United States Minor Outlying Islands", "UM"], ["United States of America", "US"], ["Uruguay", "UY"], ["Uzbekistan", "UZ"], ["Vanuatu", "VU"], ["Venezuela (Bolivarian Republic of)", "VE"], ["Viet Nam", "VN"], ["Virgin Islands (British)", "VG"], ["Virgin Islands (U.S.)", "VI"], ["Wallis and Futuna", "WF"], ["Western Sahara", "EH"], ["Yemen", "YE"], ["Zambia", "ZM"], ["Zimbabwe", "ZW"]] 31555 break; 31556 case 'directory': 31557 $value_options = [["Active", "active"]] 31558 break; 31559 case 'gift_aid': 31560 $value_options = [["Active", "active"]] 31561 break; 31562 case 'membership_status': 31563 $value_options = [["Valid", "valid"],["Pending","pending"],["Approved","approved"],["Overdue", "overdue"],["Expired", "expired"],["Incomplete", "incomplete"],["Cancelled", "cancelled"]] 31564 break; 31565 case 'membership_payment_method': 31566 $value_options = [["Card (repeat)", "card_repeat"],["Direct Debit", "mandate"],["Manual", "manual"]] 31567 break; 31568 case 'relationship_membership_status': 31569 $value_options = [["Valid", "valid"],["Pending","pending"],["Approved","approved"],["Overdue", "overdue"],["Expired", "expired"],["Incomplete", "incomplete"],["Cancelled", "cancelled"]] 31570 break; 31571 case 'relationship_membership_payment_method': 31572 $value_options = [["Card (repeat)", "card_repeat"],["Direct Debit", "mandate"],["Manual", "manual"]] 31573 break; 31574 case 'affiliation_membership_status': 31575 $value_options = [["Valid", "valid"],["Pending","pending"],["Approved","approved"],["Overdue", "overdue"],["Expired", "expired"],["Incomplete", "incomplete"],["Cancelled", "cancelled"]] 31576 break; 31577 case 'affiliation_membership_payment_method': 31578 $value_options = [["Direct Debit", "mandate"],["Manual", "manual"]] 31579 break; 31580 case 'organisation_membership_status': 31581 $value_options = [["Valid", "valid"],["Pending","pending"],["Approved","approved"],["Overdue", "overdue"],["Expired", "expired"],["Incomplete", "incomplete"],["Cancelled", "cancelled"]] 31582 break; 31583 case 'organisation_membership_payment_method': 31584 $value_options = [["Direct Debit", "mandate"],["Manual", "manual"]] 31585 break; 31586 case 'affiliation_type': 31587 $value_options = [["Any", "any"],["Key person", "key_person"]] 31588 break; 31589 case 'role': 31590 $value_options = [["Editor", "Editor"],["Administrator", "Administrator"]] 31591 break; 31592 case 'user': 31593 $value_options = [["Any", "any"],["Active", "active"]] 31594 break; 31595 } 31596 $select = create_select($value_options, $input.val()); 31597 $select.attr('name', $input.attr('name')); 31598 $input.after($select); 31599 break; 31600 case 'association': 31601 switch ($('td.field select', $filter).val()) { 31602 case 'consent_type': 31603 $.ajax({ 31604 type: 'GET', 31605 url: '/admin/consent_types', 31606 context: $input, 31607 dataType: 'json', 31608 success: function($results) { 31609 $value = $(this).val(); 31610 $select = $('<select></select>'); 31611 $select.append('<option value="any">Any</option>'); 31612 $.each($results, function($index, $result){ 31613 $option = '<option value="'+$result.id+'"' 31614 if ($value == $result.id) { 31615 $option += ' selected="selected"' 31616 } 31617 $option += '>'+$result.label+'</option>' 31618 $select.append($option); 31619 }); 31620 $input = $('input', $(this).parents('td.value')); 31621 $select.attr('name', $input.attr('name')); 31622 $input.after($select); 31623 } 31624 }); 31625 break; 31626 case 'event': 31627 $.ajax({ 31628 type: 'GET', 31629 url: '/admin/events', 31630 context: $input, 31631 dataType: 'json', 31632 success: function($results) { 31633 $value = $(this).val(); 31634 $select = $('<select></select>'); 31635 $select.append('<option value="any">Any</option>'); 31636 $.each($results, function($index, $result){ 31637 $option = '<option value="'+$result.id+'"' 31638 if ($value == $result.id) { 31639 $option += ' selected="selected"' 31640 } 31641 $option += '>'+$result.title+'</option>' 31642 $select.append($option); 31643 }); 31644 $input = $('input', $(this).parents('td.value')); 31645 $select.attr('name', $input.attr('name')); 31646 $input.after($select); 31647 } 31648 }); 31649 break; 31650 case 'group': 31651 $.ajax({ 31652 type: 'GET', 31653 url: '/groups', 31654 context: $input, 31655 dataType: 'json', 31656 success: function($results) { 31657 $value = $(this).val(); 31658 $select = $('<select></select>'); 31659 $select.append('<option value="any">Any</option>'); 31660 $.each($results, function($index, $result){ 31661 $option = '<option value="'+$result.id+'"' 31662 if ($value == $result.id) { 31663 $option += ' selected="selected"' 31664 } 31665 $option += '>
31665'+$result.name+'</option>' 31666 $select.append($option); 31667 }); 31668 $input = $('input', $(this).parents('td.value')); 31669 $select.attr('name', $input.attr('name')); 31670 $input.after($select); 31671 } 31672 }); 31673 break; 31674 case 'membership_type': 31675 $.ajax({ 31676 type: 'GET', 31677 url: '/admin/membership_plans', 31678 context: $input, 31679 data: { 31680 scope: { 31681 type: ['PersonMembershipPlan', 'JointMembershipPlan', 'ProxyMembershipPlan'] 31682 } 31683 }, 31684 dataType: 'json', 31685 success: function($results) { 31686 $value = $(this).val(); 31687 $select = $('<select></select>'); 31688 $select.append('<option value="any">Any</option>'); 31689 $.each($results, function($index, $result){ 31690 $option = '<option value="'+$result.id+'"' 31691 if ($value == $result.id) { 31692 $option += ' selected="selected"' 31693 } 31694 $option += '>'+$result.name+'</option>' 31695 $select.append($option); 31696 }); 31697 $input = $('input', $(this).parents('td.value')); 31698 $select.attr('name', $input.attr('name')); 31699 $input.after($select); 31700 } 31701 }); 31702 break; 31703 case 'relationship_membership_type': 31704 $.ajax({ 31705 type: 'GET', 31706 url: '/admin/membership_plans', 31707 context: $input, 31708 data: { 31709 scope: { 31710 type: ['JointMembershipPlan', 'ProxyMembershipPlan'] 31711 } 31712 }, 31713 dataType: 'json', 31714 success: function($results) { 31715 $value = $(this).val(); 31716 $select = $('<select></select>'); 31717 $select.append('<option value="any">Any</option>'); 31718 $.each($results, function($index, $result){ 31719 $option = '<option value="'+$result.id+'"' 31720 if ($value == $result.id) { 31721 $option += ' selected="selected"' 31722 } 31723 $option += '>'+$result.name+'</option>' 31724 $select.append($option); 31725 }); 31726 $input = $('input', $(this).parents('td.value')); 31727 $select.attr('name', $input.attr('name')); 31728 $input.after($select); 31729 } 31730 }); 31731 break; 31732 case 'affiliation_membership_type': 31733 case 'organisation_membership_type': 31734 $.ajax({ 31735 type: 'GET', 31736 url: '/organisation_membership_plans', 31737 context: $input, 31738 dataType: 'json', 31739 success: function($results) { 31740 $value = $(this).val(); 31741 $select = $('<select></select>'); 31742 $select.append('<option value="any">Any</option>'); 31743 $.each($results, function($index, $result){ 31744 $option = '<option value="'+$result.id+'"' 31745 if ($value == $result.id) { 31746 $option += ' selected="selected"' 31747 } 31748 $option += '>'+$result.name+'</option>' 31749 $select.append($option); 31750 }); 31751 $input = $('input', $(this).parents('td.value')); 31752 $select.attr('name', $input.attr('name')); 31753 $input.after($select); 31754 } 31755 }); 31756 break; 31757 } 31758 break; 31759 case 'field-text': 31760 $input.attr('type', 'text'); 31761 if (($match_select.val() != 'present') && ($match_select.val() != 'absent')) { 31762 $input.show(); 31763 } 31764 $match_select.change(function(){ 31765 $filter = $(this).parents('tr.filter') 31766 $input = $('td.value input', $filter); 31767 if (($(this).val() != 'present') && ($(this).val() != 'absent')) { 31768 $input.show(); 31769 } else { 31770 $input.hide(); 31771 } 31772 }); 31773 break; 31774 case 'field-textarea': 31775 $input.attr('type', 'text'); 31776 if (($match_select.val() != 'present') && ($match_select.val() != 'absent')) { 31777 $input.show(); 31778 } 31779 $match_select.change(function(){ 31780 $filter = $(this).parents('tr.filter') 31781 $input = $('td.value input', $filter); 31782 if (($(this).val() != 'present') && ($(this).val() != 'absent')) { 31783 $input.show(); 31784 } else { 31785 $input.hide(); 31786 } 31787 }); 31788 break; 31789 case 'field-date': 31790 $input.attr('type', 'date'); 31791 if (($match_select.val() != 'present') && ($match_select.val() != 'absent')) { 31792 $input.show(); 31793 } 31794 $match_select.change(function(){ 31795 $filter = $(this).parents('tr.filter') 31796 $input = $('td.value input', $filter); 31797 if (($(this).val() != 'present') && ($(this).val() != 'absent')) { 31798 $input.show(); 31799 } else { 31800 $input.hide(); 31801 } 31802 }); 31803 break; 31804 case 'field-file': 31805 $input.hide(); 31806 break; 31807 case 'field-select': 31808 $field_id = $('td.field option:selected', $filter).val().replace('field-',''); 31809 $.ajax({ 31810 type: 'GET', 31811 url: '/field_options/for/'+$field_id, 31812 context: $input, 31813 dataType: 'json', 31814 success: function($results) { 31815 $value = $(this).val(); 31816 $select = $('<select></select>'); 31817 $select.append('<option value="any">Any</option>'); 31818 $.each($results, function($index, $result){ 31819 $option = '<option value="'+$result.id+'"' 31820 if ($value == $result.id) { 31821 $option += ' selected="selected"' 31822 } 31823 $option += '>'+$result.option+'</option>' 31824 $select.append($option); 31825 }); 31826 $input = $('input', $(this).parents('td.value')); 31827 $select.attr('name', $input.attr('name')); 31828 $input.after($select); 31829 } 31830 }); 31831 break; 31832 case 'field-radios': 31833 $field_id = $('td.field option:selected', $filter).val().replace('field-',''); 31834 $.ajax({ 31835 type: 'GET', 31836 url: '/field_options/for/'+$field_id, 31837 context: $input, 31838 dataType: 'json', 31839 success: function($results) { 31840 $value = $(this).val(); 31841 $select = $('<select></select>'); 31842 $select.append('<option value="any">Any</option>'); 31843 $.each($results, function($index, $result){ 31844 $option = '<option value="'+$result.id+'"' 31845 if ($value == $result.id) { 31846 $option += ' selected="selected"' 31847 } 31848 $option += '>'+$result.option+'</option>' 31849 $select.append($option); 31850 }); 31851 $input = $('input', $(this).parents('td.value')); 31852 $select.attr('name', $input.attr('name')); 31853 $input.after($select); 31854 } 31855 }); 31856 break; 31857 case 'field-checkboxes': 31858 $field_id = $('td.field option:selected', $filter).val().replace('field-',''); 31859 $.ajax({ 31860 type: 'GET', 31861 url: '/field_options/for/'+$field_id, 31862 context: $input, 31863 dataType: 'json', 31864 success: function($results) { 31865 $value = $(this).val(); 31866 $select = $('<select></select>'); 31867 $select.append('<option value="any">Any</option>'); 31868 $.each($results, function($index, $result){ 31869 $option = '<option value="'+$result.id+'"' 31870 if ($value == $result.id) { 31871 $option += ' selected="selected"' 31872 } 31873 $option += '>'+$result.option+'</option>' 31874 $select.append($option); 31875 }); 31876 $input = $('input', $(this).parents('td.value')); 31877 $select.attr('name', $input.attr('name')); 31878 $input.after($select); 31879 } 31880 }); 31881 break; 31882 } 31883 31884} 31885 31886function create_select($options, $value) { 31887 31888 $select = $('<select></select>'); 31889 $.each($options, function($index, $result){ 31890 $option = '<option value="'+$result[1]+'"' 31891 if ($value == $result[1]) { 31892 $option += ' selected="selected"' 31893 } 31894 $option += '>'+$result[0]+'</option>' 31895 $select.append($option); 31896 }); 31897 return $select 31898 31899} 31900 31901function refresh_filter_delete($filter) { 31902 31903 $('input.delete', $filter).each(function(){ 31904 if ($(this).is(':checked')) { 31905 $filter = $(this).parents('tr.filter'); 31906 $table = $filter.parents('table.segments'); 31907 if ($filter.prevAll('tr').first().hasClass('logic')) { 31908 $filter.prevAll('tr').first().remove(); 31909 } else if ($filter.nextAll('tr').first().hasClass('logic')) { 31910 $filter.nextAll('tr').first().remove(); 31911 } 31912 $filter.hide(); 31913 if ($('tr.filter:visible', $table).length == 0) { 31914 if ($table.parents('div.box').prev().hasClass('logic')) { 31915 $table.parents('div.box').prev().remove(); 31916 } else if ($table.parents('div.box').next().hasClass('logic')) { 31917 $table.parents('div.box').next().remove(); 31918 } 31919 $table.parents('div.box').hide(); 31920 } 31921// $('td select', $(this).parents('tr.filter')).css('opacity', '0.2'); 31922// $('td input[type=text]', $(this).parents('tr')).css('opacity', '0.2'); 31923// } else { 31924// $('td select', $(this).parents('tr.filter')).css('opacity', '1'); 31925// $('td input[type=text]', $(this).parents('tr')).css('opacity', '1'); 31926 } 31927 }); 31928 31929} 31930 31931function delete_filter($filter) { 31932 31933 $table = $filter.parents('table.segments'); 31934 if ($filter.prev().hasClass('logic')) { 31935 $filter.prev().remove(); 31936 } else if ($filter.next().hasClass('logic')) { 31937 $filter.next().remove(); 31938 } 31939 $filter.remove(); 31940 if ($('tr.filter:visible', $table).length == 0) { 31941 if ($table.parents('div.box').prev().hasClass('logic')) { 31942 $table.parents('div.box').prev().remove(); 31943 } else if ($table.parents('div.box').next().hasClass('logic')) { 31944 $table.parents('div.box').next().remove(); 31945 } 31946 $table.parents('div.box').hide(); 31947 } 31948 31949};
31950function fetchSubscription(subscription_hash_id) { 31951 return $.ajax({ 31952 type: 'GET', 31953 url: '/subscriptions/'+subscription_hash_id+'/intend', 31954 dataType: 'json' 31955 }); 31956}; 31957 31958function start_table($table) { 31959 31960 $('table.ajax').each(function(index){ 31961 $table = $(this); 31962 $input_query = $('input.query', $table.parents('div.data')); 31963 $form_search = $('form.search', $table.parents('div.data')); 31964 $form_search.submit(function(e){ 31965 $params = new URLSearchParams(window.location.search); 31966 $params.delete('search'); 31967 if ($input_query.val() != '') { 31968 $params.set('search', $input_query.val()); 31969 } 31970 $table.data('search', $input_query.val()); 31971 window.history.replaceState({}, '', window.location.pathname+'?'+$params); 31972 reset_export_links(); 31973 refresh_table_rows($table) 31974 e.preventDefault(); 31975 }); 31976 $('div.filter select', $table.parents('div.data')).change(function(){ 31977 $filter = $table.data('filter'); 31978 delete $filter[$(this).attr('class')]; 31979 $params = new URLSearchParams(window.location.search); 31980 $params.delete('filter['+$(this).attr('class')+']'); 31981 if ($(this).val() != '') { 31982 $filter[$(this).attr('class')] = $(this).val(); 31983 $params.set('filter['+$(this).attr('class')+']', $(this).val()); 31984 } 31985 $table.data('filter', $filter); 31986 window.history.replaceState({}, '', window.location.pathname+'?'+$params); 31987 reset_export_links(); 31988 refresh_table_rows($table) 31989 }); 31990 $('div.filter input[type=date]', $table.parents('div.data')).change(function(){ 31991 $filter = $table.data('filter'); 31992 delete $filter[$(this).attr('class')]; 31993 $params = new URLSearchParams(window.location.search); 31994 $params.delete('filter['+$(this).attr('class')+']'); 31995 if ($(this).val() != '') { 31996 $filter[$(this).attr('class')] = $(this).val(); 31997 $params.set('filter['+$(this).attr('class')+']', $(this).val()); 31998 } 31999 $table.data('filter', $filter); 32000 window.history.replaceState({}, '', window.location.pathname+'?'+$params); 32001 reset_export_links(); 32002 refresh_table_rows($table) 32003 }); 32004 $('th.sortable', $table).click(function(){ 32005 sort = {} 32006 if ($(this).hasClass('asc')) { 32007 $(this).removeClass('asc'); 32008 $(this).addClass('desc'); 32009 sort[$(this).data('key')] = 'desc'; 32010 } else { 32011 $('th.sortable', $(this).parents('table.ajax')).removeClass('asc'); 32012 $('th.sortable', $(this).parents('table.ajax')).removeClass('desc'); 32013 $(this).addClass('asc'); 32014 sort[$(this).data('key')] = 'asc'; 32015 } 32016 $table.data('sort', sort); 32017 $table.data('start', 1); 32018 refresh_table_rows($table); 32019 }); 32020 refresh_table_rows($(this)) 32021 }); 32022 32023 $('table.weight').each(function(){ 32024 $('select[id$="weight"]', $(this)).each(function(index){ 32025 $(this).val($(this).parents('tr').index()); 32026 }); 32027 }); 32028 32029 if ($($table).hasClass('admin')) { 32030 start_table_rowclick($table); 32031 start_table_head_operations($table); 32032 start_table_data_operations($table); 32033 start_table_actionsmenu($table); 32034 }; 32035 32036} 32037 32038function refresh_table_rows($table) { 32039 32040 $('tbody', $table).addClass('disable'); 32041 32042 var $outline_request = $.ajax({}); 32043 var $records_request = $.ajax({}); 32044 32045 $outline_request.abort(); 32046 $records_request.abort(); 32047 32048 $outline_request = $.ajax({ 32049 dataType: 'json', 32050 data: { 32051 scope: $table.data('scope'), 32052 filter: $table.data('filter'), 32053 search: $table.data('search') 32054 }, 32055 cache: false, 32056 url: $table.data('source')+'/count', 32057 success: $.proxy(function($outline) { 32058 32059 $('div.orientation', $table.parents('div.data')).html(''); 32060 if ($outline.count > 0) { 32061 $table.data('result_ids', $outline.pluck_ids) 32062 if ($outline.count <= $table.data('limit')) { 32063 if ($outline.count > 0) { 32064 $('div.orientation', $table.parents('div.data')).show(); 32065 $pagecount = Math.ceil($outline.count / $table.data('limit')) 32066 // $total = $('<div class="total">'+$table.data('start')+' to '+((($table.data('start')+$table.data('limit')-1)<$outline.count) ? ($table.data('start')+$table.data('limit')-1) : $outline.count)+' of '+$outline.count+' items</div>'); 32067 $pagination = $('<div class="pagination"></div>'); 32068 $pagination.append('<span class="spacer">'+$table.data('start')+' to '+((($table.data('start')+$table.data('limit')-1)<$outline.count) ? ($table.data('start')+$table.data('limit')-1) : $outline.count)+' of '+$outline.count+'<
32068/span>'); 32069 $('div.orientation', $table.parents('div.data')).append($pagination); 32070 } 32071 } else { 32072 $('div.orientation', $table.parents('div.data')).show(); 32073 $pagecount = Math.ceil($outline.count / $table.data('limit')) 32074 // $total = $('<div class="total">'+$table.data('start')+' to '+((($table.data('start')+$table.data('limit')-1)<$outline.count) ? ($table.data('start')+$table.data('limit')-1) : $outline.count)+' of '+$outline.count+' items</div>'); 32075 $pagination = $('<div class="pagination"></div>'); 32076 $pagination.append('<span class="spacer">'+$table.data('start')+' to '+((($table.data('start')+$table.data('limit')-1)<$outline.count) ? ($table.data('start')+$table.data('limit')-1) : $outline.count)+' of '+$outline.count+'</span>'); 32077 // for ($i = 1; $i <= $pagecount; $i++) { 32078 // if (($table.data('start') > (($i-1)*$table.data('limit'))) && ($table.data('start') < ($i*$table.data('limit')))) { 32079 // $pagination.append('<span class="spacer">'+$i+'</span>'); 32080 // } else { 32081 // $link = $('<a href="#" data-start="'+((($i-1)*$table.data('limit'))+1)+'">'+$i+'</a>') 32082 // $link.click(function(e){ 32083 // $table = $('table.ajax', $(this).parents('div.data')) 32084 // $table.data('start', $(this).data('start')); 32085 // refresh_table_rows($table); 32086 // e.preventDefault(); 32087 // }); 32088 // $pagination.append($link); 32089 // } 32090 // } 32091 if ($table.data('start') == 1) { 32092 $pagination.append('<span class="mdi mdi-chevron-left disabled button"></span>'); 32093 } else { 32094 $link = $('<a href="#" class="mdi mdi-chevron-left secondary button" data-start="'+($table.data('start')-$table.data('limit'))+'"></a>') 32095 $link.click(function(e){ 32096 $table = $('table.ajax', $(this).parents('div.data')) 32097 $table.data('start', $(this).data('start')); 32098 refresh_table_rows($table); 32099 e.preventDefault(); 32100 }); 32101 $pagination.append($link); 32102 } 32103 if ($table.data('start') < (($pagecount-1)*$table.data('limit'))) { 32104 $link = $('<a href="#" class="mdi mdi-chevron-right secondary button" data-start="'+($table.data('start')+$table.data('limit'))+'"></a>') 32105 $link.click(function(e){ 32106 $table = $('table.ajax', $(this).parents('div.data')) 32107 $table.data('start', $(this).data('start')); 32108 refresh_table_rows($table); 32109 e.preventDefault(); 32110 }); 32111 $pagination.append($link); 32112 } else { 32113 $pagination.append('<span class="mdi mdi-chevron-right disabled button"></span>'); 32114 } 32115 // $('div.orientation', $table.parents('div.data')).prepend($total); 32116 $('div.orientation', $table.parents('div.data')).append($pagination); 32117 if ($('tbody tr', $table).length < 1) { 32118 $('tbody', $table).append('<tr><td colspan="'+$('th', $table).length+'" class="textcenter">Loading...</td></tr>'); 32119 } 32120 } 32121 } 32122 32123 $('div.summary', $table.parents('div.data')).html('') 32124 $.each($outline.summary, function($key, $value){ 32125 $('div.summary', $table.parents('div.data')).append('<div class="panel"><div class="label small grey">'+$value['label']+'</div><div class="field xxlarge">'+$value['field']+'</div></div>'); 32126 }); 32127 32128 $records_request = $.ajax({ 32129 dataType: 'json', 32130 data: { 32131 scope: $table.data('scope'), 32132 filter: $table.data('filter'), 32133 search: $table.data('search'), 32134 sort: $table.data('sort'), 32135 start: $table.data('start'), 32136 limit: $table.data('limit') 32137 }, 32138 cache: false, 32139 url: $table.data('source'), 32140 success: $.proxy(function($records) { 32141 32142 $('tbody', $table).empty(); 32143 $('tbody', $table).removeClass('disable'); 32144 if ($records.length > 0) { 32145 $.each($records, $.proxy(function($key, $value) { 32146 if ($value['table_row']) { 32147 $('tbody', $table).append($value['table_row']) 32148 } else { 32149 console.log('table_row not found in index.json'); 32150 } 32151 }, this)); 32152 start_table_rowclick($table); 32153 start_table_data_operations($table); 32154 start_table_actionsmenu($table); 32155 } else { 32156 $('tbody', $table).append('<tr><td colspan="'+$('th', $table).length+'" class="textcenter">No items</td></tr>'); 32157 } 32158 32159 }, this) 32160 }); 32161 32162 }, this) 32163 }); 32164 32165} 32166 32167function start_table_order() { 32168 32169// $('div.overflow').nestable({ 32170// listNodeName : 'table', 32171// itemNodeName : 'tr.question', 32172// rootClass : 'overflow', 32173// listClass : 'dd-list', 32174// itemClass : 'dd-item', 32175// dragClass : 'dd-dragel', 32176// handleClass : 'dd-handle', 32177// collapsedClass : 'dd-collapsed', 32178// placeClass : 'dd-placeholder', 32179// noDragClass : 'dd-nodrag', 32180// emptyClass : 'dd-empty', 32181// expandBtnHTML : '<button data-action="expand" type="button">Expand</button>', 32182// collapseBtnHTML : '<button data-action="collapse" type="button">Collapse</button>', 32183// group : 0, 32184// maxDepth : 1, 32185// threshold : 20 32186// }); 32187 32188} 32189 32190function start_table_rowclick($table) { 32191 32192 $('tr.rowclick td:not(.select):not(.actions)', $table).click(function(){ 32193 $('a.rowclick', $(this).parents('tr.rowclick'))[0].click(); 32194 }); 32195 32196} 32197 32198function start_table_head_operations($table) { 32199 32200 if ($('th.select', $table).length > 0) { 32201 32202 $('div.operations', $table.parents('div.data')).hide(); 32203 32204 $('th.select input[type=checkbox]', $table).change(function(){ 32205 $result_ids = $table.data('result_ids'); 32206 if ($(this).is(':checked')) { 32207 $table.data('select_ids', $result_ids); 32208 $('td.select input[type=checkbox]').prop('checked', true); 32209 $label = $result_ids.length+' selected'; 32210 $('div.operations > ul > li > a', $table.parents('div.data')).text($label); 32211 $('div.operations', $table.parents('div.data')).show(); 32212 } else { 32213 $table.data('select_ids', []); 32214 $('td.select input[type=checkbox]').prop('checked', false); 32215 $('div.operations', $table.parents('div.data')).hide(); 32216 } 32217 }); 32218 32219 } 32220 32221} 32222 32223function start_table_data_operations($table) { 32224 32225 if ($('th.select', $table).length > 0) { 32226 32227 $select_ids = $table.data('select_ids'); 32228 $('td.select input[type=checkbox]', $table).each(function(){ 32229 $item_id = parseInt($(this).attr('name').replace('select-','')); 32230 if ($select_ids.includes($item_id)) { 32231 $(this).prop('checked', true); 32232 } 32233 }); 32234 32235 $('td.select input[type=checkbox]', $table).change(function(){ 32236 $('th.select input[type=checkbox]').prop('checked', false); 32237 $select_ids = []; 32238 $('td.select input[type=checkbox]').each(function(){ 32239 if ($(this).is(':checked')) { 32240 $item_id = parseInt($(this).attr('name').replace('select-','')); 32241 $select_ids.push($item_id); 32242 } 32243 }); 32244 if ($select_ids.length > 0) { 32245 $label = $select_ids.length+' selected'; 32246 $('div.operations > ul > li > a', $table.parents('div.data')).text($label); 32247 $('div.operations', $table.parents('div.data')).show(); 32248 } else { 32249 $('div.operations', $table.parents('div.data')).hide(); 32250 } 32251 $table.data('select_ids', $select_ids); 32252 }); 32253 32254 } 32255 32256} 32257 32258function start_table_actionsmenu($table) { 32259 32260 $('td.actions.menu', $table).each(function(){ 32261 $('ul', $(this)).hide(); 32262 $('a.toggle', $(this)).click(function(e){ 32263 $('ul', $('td.actions.menu', $table).not($(this).parents('td.menu'))).hide(); 32264 $('ul', $(this).parents('td.menu')).toggle(); 32265 e.preventDefault(); 32266 }); 32267 }); 32268 32269 $(document).click (function (e) { 32270 if ($(e.target).parents('td.menu').length < 1) { 32271 $('td.menu ul').hide(); 32272 } 32273 }); 32274 32275}; 32276/*! algoliasearch 3.20.3 | © 2014, 2015 Algolia SAS | github.com/algolia/algoliasearch-client-js */ 32277!function(e){var t;"undefined"!=typeof window?t=window:"undefined"!=typeof self&&(t=self),t.ALGOLIA_MIGRATION_LAYER=e()}(function(){return function e(t,r,n){function o(s,a){if(!r[s]){if(!t[s]){var c="function"==typeof require&&require;if(!a&&c)return c(s,!0);if(i)return i(s,!0);var u=new Error("Cannot find module '"+s+"'");throw u.code="MODULE_NOT_FOUND",u}var l=r[s]={exports:{}};t[s][0].call(l.exports,function(e){var r=t[s][1][e];return o(r?r:e)},l,l.exports,e,t,r,n)}return r[s].exports}for(var i="function"==typeof require&&require,s=0;s<n.length;s++)o(n[s]);return o}({1:[function(e,t,r){function n(e,t){for(var r in t)e.setAttribute(r,t[r])}function o(e,t){e.onload=function(){this.onerror=this.onload=null,t(null,e)},e.onerror=function(){this.onerror=this.onload=null,t(new Error("Failed to load "+this.src),e)}}function i(e,t){e.onreadystatechange=function(){"complete"!=this.readyState&&"loaded"!=this.readyState||(this.onreadystatechange=null,t(null,e))}}t.exports=function(e,t,r){var s=document.head||document.getElementsByTagName("head")[0],a=document.createElement("script");"function"==typeof t&&(r=t,t={}),t=t||{},r=r||function(){},a.type=t.type||"text/javascript",a.charset=t.charset||"utf8",a.async=!("async"in t)||!!t.async,a.src=e,t.attrs&&n(a,t.attrs),t.text&&(a.text=""+t.text);var c="onload"in a?o:i;c(a,r),a.onload||o(a,r),s.appendChild(a)}},{}],2:[function(e,t,r){"use strict";function n(e){for(var t=new RegExp("cdn\\.jsdelivr\\.net/algoliasearch/latest/"+e.replace(".","\\.")+"(?:\\.min)?\\.js$"),r=document.getElementsByTagName("script"),n=!1,o=0,i=r.length;o<i;o++)if(r[o].src&&t.test(r[o].src)){n=!0;break}return n}t.exports=n},{}],3:[function(e,t,r){"use strict";function n(t){var r=e(1),n="//cdn.jsdelivr.net/algoliasearch/2/"+t+".min.js",i="-- AlgoliaSearch `latest` warning --\nWarning, you are using the `latest` version string from jsDelivr to load the AlgoliaSearch library.\
32277nUsing `latest` is no more recommended, you should load //cdn.jsdelivr.net/algoliasearch/2/algoliasearch.min.js\n\nAlso, we updated the AlgoliaSearch JavaScript client to V3. If you want to upgrade,\nplease read our migration guide at https://github.com/algolia/algoliasearch-client-js/wiki/Migration-guide-from-2.x.x-to-3.x.x\n-- /AlgoliaSearch `latest` warning --";window.console&&(window.console.warn?window.console.warn(i):window.console.log&&window.console.log(i));try{document.write("<script>window.ALGOLIA_SUPPORTS_DOCWRITE = true</script>"),window.ALGOLIA_SUPPORTS_DOCWRITE===!0?(document.write('<script src="'+n+'"></script>'),o("document.write")()):r(n,o("DOMElement"))}catch(s){r(n,o("DOMElement"))}}function o(e){return function(){var t="AlgoliaSearch: loaded V2 script using "+e;window.console&&window.console.log&&window.console.log(t)}}t.exports=n},{1:1}],4:[function(e,t,r){"use strict";function n(){var e="-- AlgoliaSearch V2 => V3 error --\nYou are trying to use a new version of the AlgoliaSearch JavaScript client with an old notation.\nPlease read our migration guide at https://github.com/algolia/algoliasearch-client-js/wiki/Migration-guide-from-2.x.x-to-3.x.x\n-- /AlgoliaSearch V2 => V3 error --";window.AlgoliaSearch=function(){throw new Error(e)},window.AlgoliaSearchHelper=function(){throw new Error(e)},window.AlgoliaExplainResults=function(){throw new Error(e)}}t.exports=n},{}],5:[function(e,t,r){"use strict";function n(t){var r=e(2),n=e(3),o=e(4);r(t)?n(t):o()}n("algoliasearch")},{2:2,3:3,4:4}]},{},[5])(5)}),function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var t;t="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,t.algoliasearch=e()}}(function(){var e;return function t(e,r,n){function o(s,a){if(!r[s]){if(!e[s]){var c="function"==typeof require&&require;if(!a&&c)return c(s,!0);if(i)return i(s,!0);var u=new Error("Cannot find module '"+s+"'");throw u.code="MODULE_NOT_FOUND",u}var l=r[s]={exports:{}};e[s][0].call(l.exports,function(t){var r=e[s][1][t];return o(r?r:t)},l,l.exports,t,e,r,n)}return r[s].exports}for(var i="function"==typeof require&&require,s=0;s<n.length;s++)o(n[s]);return o}({1:[function(e,t,r){(function(n){function o(){return"undefined"!=typeof document&&"WebkitAppearance"in document.documentElement.style||window.console&&(console.firebug||console.exception&&console.table)||navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)&&parseInt(RegExp.$1,10)>=31}function i(){var e=arguments,t=this.useColors;if(e[0]=(t?"%c":"")+this.namespace+(t?" %c":" ")+e[0]+(t?"%c ":" ")+"+"+r.humanize(this.diff),!t)return e;var n="color: "+this.color;e=[e[0],n,"color: inherit"].concat(Array.prototype.slice.call(e,1));var o=0,i=0;return e[0].replace(/%[a-z%]/g,function(e){"%%"!==e&&(o++,"%c"===e&&(i=o))}),e.splice(i,0,n),e}function s(){return"object"==typeof console&&console.log&&Function.prototype.apply.call(console.log,console,arguments)}function a(e){try{null==e?r.storage.removeItem("debug"):r.storage.debug=e}catch(t){}}function c(){try{return r.storage.debug}catch(e){}if("undefined"!=typeof n&&"env"in n)return n.env.DEBUG}function u(){try{return window.localStorage}catch(e){}}r=t.exports=e(2),r.log=s,r.formatArgs=i,r.save=a,r.load=c,r.useColors=o,r.storage="undefined"!=typeof chrome&&"undefined"!=typeof chrome.storage?chrome.storage.local:u(),r.colors=["lightseagreen","forestgreen","goldenrod","dodgerblue","darkorchid","crimson"],r.formatters.j=function(e){try{return JSON.stringify(e)}catch(t){return"[UnexpectedJSONParseError]: "+t.message}},r.enable(c())}).call(this,e(12))},{12:12,2:2}],2:[function(e,t,r){function n(){return r.colors[l++%r.colors.length]}function o(e){function t(){}function o(){var e=o,t=+new Date,i=t-(u||t);e.diff=i,e.prev=u,e.curr=t,u=t,null==e.useColors&&(e.useColors=r.useColors()),null==e.color&&e.useColors&&(e.color=n());for(var s=new Array(arguments.length),a=0;a<s.length;a++)s[a]=arguments[a];s[0]=r.coerce(s[0]),"string"!=typeof s[0]&&(s=["%o"].concat(s));var c=0;s[0]=s[0].replace(/%([a-z%])/g,function(t,n){if("%%"===t)return t;c++;var o=r.formatters[n];if("function"==typeof o){var i=s[c];
32277t=o.call(e,i),s.splice(c,1),c--}return t}),s=r.formatArgs.apply(e,s);var l=o.log||r.log||console.log.bind(console);l.apply(e,s)}t.enabled=!1,o.enabled=!0;var i=r.enabled(e)?o:t;return i.namespace=e,i}function i(e){r.save(e);for(var t=(e||"").split(/[\s,]+/),n=t.length,o=0;o<n;o++)t[o]&&(e=t[o].replace(/[\\^$+?.()|[\]{}]/g,"\\$&").replace(/\*/g,".*?"),"-"===e[0]?r.skips.push(new RegExp("^"+e.substr(1)+"$")):r.names.push(new RegExp("^"+e+"$")))}function s(){r.enable("")}function a(e){var t,n;for(t=0,n=r.skips.length;t<n;t++)if(r.skips[t].test(e))return!1;for(t=0,n=r.names.length;t<n;t++)if(r.names[t].test(e))return!0;return!1}function c(e){return e instanceof Error?e.stack||e.message:e}r=t.exports=o.debug=o,r.coerce=c,r.disable=s,r.enable=i,r.enabled=a,r.humanize=e(9),r.names=[],r.skips=[],r.formatters={};var u,l=0},{9:9}],3:[function(t,r,n){(function(o,i){!function(t,o){"object"==typeof n&&"undefined"!=typeof r?r.exports=o():"function"==typeof e&&e.amd?e(o):t.ES6Promise=o()}(this,function(){"use strict";function e(e){return"function"==typeof e||"object"==typeof e&&null!==e}function r(e){return"function"==typeof e}function n(e){X=e}function s(e){W=e}function a(){return function(){return o.nextTick(h)}}function c(){return"undefined"!=typeof V?function(){V(h)}:p()}function u(){var e=0,t=new Z(h),r=document.createTextNode("");return t.observe(r,{characterData:!0}),function(){r.data=e=++e%2}}function l(){var e=new MessageChannel;return e.port1.onmessage=h,function(){return e.port2.postMessage(0)}}function p(){var e=setTimeout;return function(){return e(h,1)}}function h(){for(var e=0;e<G;e+=2){var t=re[e],r=re[e+1];t(r),re[e]=void 0,re[e+1]=void 0}G=0}function d(){try{var e=t,r=e("vertx");return V=r.runOnLoop||r.runOnContext,c()}catch(n){return p()}}function f(e,t){var r=arguments,n=this,o=new this.constructor(m);void 0===o[oe]&&C(o);var i=n._state;return i?!function(){var e=r[i-1];W(function(){return P(i,o,e,n._result)})}():O(n,o,e,t),o}function y(e){var t=this;if(e&&"object"==typeof e&&e.constructor===t)return e;var r=new t(m);return j(r,e),r}function m(){}function v(){return new TypeError("You cannot resolve a promise with itself")}function g(){return new TypeError("A promises callback cannot return that same promise.")}function b(e){try{return e.then}catch(t){return ce.error=t,ce}}function w(e,t,r,n){try{e.call(t,r,n)}catch(o){return o}}function _(e,t,r){W(function(e){var n=!1,o=w(r,t,function(r){n||(n=!0,t!==r?j(e,r):I(e,r))},function(t){n||(n=!0,k(e,t))},"Settle: "+(e._label||" unknown promise"));!n&&o&&(n=!0,k(e,o))},e)}function x(e,t){t._state===se?I(e,t._result):t._state===ae?k(e,t._result):O(t,void 0,function(t){return j(e,t)},function(t){return k(e,t)})}function T(e,t,n){t.constructor===e.constructor&&n===f&&t.constructor.resolve===y?x(e,t):n===ce?k(e,ce.error):void 0===n?I(e,t):r(n)?_(e,t,n):I(e,t)}function j(t,r){t===r?k(t,v()):e(r)?T(t,r,b(r)):I(t,r)}function S(e){e._onerror&&e._onerror(e._result),R(e)}function I(e,t){e._state===ie&&(e._result=t,e._state=se,0!==e._subscribers.length&&W(R,e))}function k(e,t){e._state===ie&&(e._state=ae,e._result=t,W(S,e))}function O(e,t,r,n){var o=e._subscribers,i=o.length;e._onerror=null,o[i]=t,o[i+se]=r,o[i+ae]=n,0===i&&e._state&&W(R,e)}function R(e){var t=e._subscribers,r=e._state;if(0!==t.length){for(var n=void 0,o=void 0,i=e._result,s=0;s<t.length;s+=3)n=t[s],o=t[s+r],n?P(r,n,o,i):o(i);e._subscribers.length=0}}function A(){this.error=null}function E(e,t){try{return e(t)}catch(r){return ue.error=r,ue}}function P(e,t,n,o){var i=r(n),s=void 0,a=void 0,c=void 0,u=void 0;if(i){if(s=E(n,o),s===ue?(u=!0,a=s.error,s=null):c=!0,t===s)return void k(t,g())}else s=o,c=!0;t._state!==ie||(i&&c?j(t,s):u?k(t,a):e===se?I(t,s):e===ae&&k(t,s))}function U(e,t){try{t(function(t){j(e,t)},function(t){k(e,t)})}catch(r){k(e,r)}}function q(){return le++}function C(e){e[oe]=le++,e._state=void 0,e._result=void 0,e._subscribers=[]}function N(e,t){this._instanceConstructor=e,this.promise=new e(m),this.promise[oe]||C(this.promise),Q(t)?(this._input=t,this.length=t.length,this._remaining=t.length,this._result=new Array(this.length),0===this.length?I(this.promise,this._result):(this.length=this.length||0,this._enumerate(),0===this._remaining&&I(this.promise,this._result))):k(this.promise,D())}function D(){return new Error("Array Methods must be provided an Array")}function L(e){return new N(this,e).promise}function H(e){var t=this;return new t(Q(e)?function(r,n){for(var o=e.length,i=0;i<o;i++)t.resolve(e[i]).then(r,n)}:function(e,t){return t(new TypeError("You must pass an array to race."))})}function M(e){var t=this,r=new t(m);return k(r,e),r}function J(){throw new TypeError("You must pass a resolver function as the first argument to the promise constructor")}function F(){throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object c
32277onstructor cannot be called as a function.")}function K(e){this[oe]=q(),this._result=this._state=void 0,this._subscribers=[],m!==e&&("function"!=typeof e&&J(),this instanceof K?U(this,e):F())}function B(){var e=void 0;if("undefined"!=typeof i)e=i;else if("undefined"!=typeof self)e=self;else try{e=Function("return this")()}catch(t){throw new Error("polyfill failed because global object is unavailable in this environment")}var r=e.Promise;if(r){var n=null;try{n=Object.prototype.toString.call(r.resolve())}catch(t){}if("[object Promise]"===n&&!r.cast)return}e.Promise=K}var $=void 0;$=Array.isArray?Array.isArray:function(e){return"[object Array]"===Object.prototype.toString.call(e)};var Q=$,G=0,V=void 0,X=void 0,W=function(e,t){re[G]=e,re[G+1]=t,G+=2,2===G&&(X?X(h):ne())},Y="undefined"!=typeof window?window:void 0,z=Y||{},Z=z.MutationObserver||z.WebKitMutationObserver,ee="undefined"==typeof self&&"undefined"!=typeof o&&"[object process]"==={}.toString.call(o),te="undefined"!=typeof Uint8ClampedArray&&"undefined"!=typeof importScripts&&"undefined"!=typeof MessageChannel,re=new Array(1e3),ne=void 0;ne=ee?a():Z?u():te?l():void 0===Y&&"function"==typeof t?d():p();var oe=Math.random().toString(36).substring(16),ie=void 0,se=1,ae=2,ce=new A,ue=new A,le=0;return N.prototype._enumerate=function(){for(var e=this.length,t=this._input,r=0;this._state===ie&&r<e;r++)this._eachEntry(t[r],r)},N.prototype._eachEntry=function(e,t){var r=this._instanceConstructor,n=r.resolve;if(n===y){var o=b(e);if(o===f&&e._state!==ie)this._settledAt(e._state,t,e._result);else if("function"!=typeof o)this._remaining--,this._result[t]=e;else if(r===K){var i=new r(m);T(i,e,o),this._willSettleAt(i,t)}else this._willSettleAt(new r(function(t){return t(e)}),t)}else this._willSettleAt(n(e),t)},N.prototype._settledAt=function(e,t,r){var n=this.promise;n._state===ie&&(this._remaining--,e===ae?k(n,r):this._result[t]=r),0===this._remaining&&I(n,this._result)},N.prototype._willSettleAt=function(e,t){var r=this;O(e,void 0,function(e){return r._settledAt(se,t,e)},function(e){return r._settledAt(ae,t,e)})},K.all=L,K.race=H,K.resolve=y,K.reject=M,K._setScheduler=n,K._setAsap=s,K._asap=W,K.prototype={constructor:K,then:f,"catch":function(e){return this.then(null,e)}},K.polyfill=B,K.Promise=K,K})}).call(this,t(12),"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{12:12}],4:[function(e,t,r){function n(){this._events=this._events||{},this._maxListeners=this._maxListeners||void 0}function o(e){return"function"==typeof e}function i(e){return"number"==typeof e}function s(e){return"object"==typeof e&&null!==e}function a(e){return void 0===e}t.exports=n,n.EventEmitter=n,n.prototype._events=void 0,n.prototype._maxListeners=void 0,n.defaultMaxListeners=10,n.prototype.setMaxListeners=function(e){if(!i(e)||e<0||isNaN(e))throw TypeError("n must be a positive number");return this._maxListeners=e,this},n.prototype.emit=function(e){var t,r,n,i,c,u;if(this._events||(this._events={}),"error"===e&&(!this._events.error||s(this._events.error)&&!this._events.error.length)){if(t=arguments[1],t instanceof Error)throw t;var l=new Error('Uncaught, unspecified "error" event. ('+t+")");throw l.context=t,l}if(r=this._events[e],a(r))return!1;if(o(r))switch(arguments.length){case 1:r.call(this);break;case 2:r.call(this,arguments[1]);break;case 3:r.call(this,arguments[1],arguments[2]);break;default:i=Array.prototype.slice.call(arguments,1),r.apply(this,i)}else if(s(r))for(i=Array.prototype.slice.call(arguments,1),u=r.slice(),n=u.length,c=0;c<n;c++)u[c].apply(this,i);return!0},n.prototype.addListener=function(e,t){var r;if(!o(t))throw TypeError("listener must be a function");return this._events||(this._events={}),this._events.newListener&&this.emit("newListener",e,o(t.listener)?t.listener:t),this._events[e]?s(this._events[e])?this._events[e].push(t):this._events[e]=[this._events[e],t]:this._events[e]=t,s(this._events[e])&&!this._events[e].warned&&(r=a(this._maxListeners)?n.defaultMaxListeners:this._maxListeners,r&&r>0&&this._events[e].length>r&&(this._events[e].warned=!0,console.error("(node) warning: possible EventEmitter memory leak detected. %d listeners added. Use emitter.setMaxListeners() to increase limit.",this._events[e].length),"function"==typeof console.trace&&console.trace())),this},n.prototype.on=n.prototype.addListener,n.prototype.once=function(e,t){function r(){this.removeListener(e,r),n||(n=!0,t.apply(this,arguments))}if(!o(t))throw TypeError("listener must be a function");var n=!1;return r.listener=t,this.on(e,r),this},n.prototype.removeListener=function(e,t){var r,n,i,a;if(!o(t))throw TypeError("listener must be a function");if(!this._events||!this._events[e])return this;if(r=this._events[e],i=r.length,n=-1,r===t||o(r.listener)&&r.listener===t)delete this._events[e],this._events.removeListener&&this.emit
32277("removeListener",e,t);else if(s(r)){for(a=i;a-- >0;)if(r[a]===t||r[a].listener&&r[a].listener===t){n=a;break}if(n<0)return this;1===r.length?(r.length=0,delete this._events[e]):r.splice(n,1),this._events.removeListener&&this.emit("removeListener",e,t)}return this},n.prototype.removeAllListeners=function(e){var t,r;if(!this._events)return this;if(!this._events.removeListener)return 0===arguments.length?this._events={}:this._events[e]&&delete this._events[e],this;if(0===arguments.length){for(t in this._events)"removeListener"!==t&&this.removeAllListeners(t);return this.removeAllListeners("removeListener"),this._events={},this}if(r=this._events[e],o(r))this.removeListener(e,r);else if(r)for(;r.length;)this.removeListener(e,r[r.length-1]);return delete this._events[e],this},n.prototype.listeners=function(e){var t;return t=this._events&&this._events[e]?o(this._events[e])?[this._events[e]]:this._events[e].slice():[]},n.prototype.listenerCount=function(e){if(this._events){var t=this._events[e];if(o(t))return 1;if(t)return t.length}return 0},n.listenerCount=function(e,t){return e.listenerCount(t)}},{}],5:[function(e,t,r){var n=Object.prototype.hasOwnProperty,o=Object.prototype.toString;t.exports=function(e,t,r){if("[object Function]"!==o.call(t))throw new TypeError("iterator must be a function");var i=e.length;if(i===+i)for(var s=0;s<i;s++)t.call(r,e[s],s,e);else for(var a in e)n.call(e,a)&&t.call(r,e[a],a,e)}},{}],6:[function(e,t,r){(function(e){"undefined"!=typeof window?t.exports=window:"undefined"!=typeof e?t.exports=e:"undefined"!=typeof self?t.exports=self:t.exports={}}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}],7:[function(e,t,r){"function"==typeof Object.create?t.exports=function(e,t){e.super_=t,e.prototype=Object.create(t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}})}:t.exports=function(e,t){e.super_=t;var r=function(){};r.prototype=t.prototype,e.prototype=new r,e.prototype.constructor=e}},{}],8:[function(e,t,r){var n={}.toString;t.exports=Array.isArray||function(e){return"[object Array]"==n.call(e)}},{}],9:[function(e,t,r){function n(e){if(e=String(e),!(e.length>1e4)){var t=/^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec(e);if(t){var r=parseFloat(t[1]),n=(t[2]||"ms").toLowerCase();switch(n){case"years":case"year":case"yrs":case"yr":case"y":return r*p;case"days":case"day":case"d":return r*l;case"hours":case"hour":case"hrs":case"hr":case"h":return r*u;case"minutes":case"minute":case"mins":case"min":case"m":return r*c;case"seconds":case"second":case"secs":case"sec":case"s":return r*a;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return r;default:return}}}}function o(e){return e>=l?Math.round(e/l)+"d":e>=u?Math.round(e/u)+"h":e>=c?Math.round(e/c)+"m":e>=a?Math.round(e/a)+"s":e+"ms"}function i(e){return s(e,l,"day")||s(e,u,"hour")||s(e,c,"minute")||s(e,a,"second")||e+" ms"}function s(e,t,r){if(!(e<t))return e<1.5*t?Math.floor(e/t)+" "+r:Math.ceil(e/t)+" "+r+"s"}var a=1e3,c=60*a,u=60*c,l=24*u,p=365.25*l;t.exports=function(e,t){t=t||{};var r=typeof e;if("string"===r&&e.length>0)return n(e);if("number"===r&&isNaN(e)===!1)return t["long"]?i(e):o(e);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(e))}},{}],10:[function(e,t,r){"use strict";var n=Object.prototype.hasOwnProperty,o=Object.prototype.toString,i=Array.prototype.slice,s=e(11),a=Object.prototype.propertyIsEnumerable,c=!a.call({toString:null},"toString"),u=a.call(function(){},"prototype"),l=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],p=function(e){var t=e.constructor;return t&&t.prototype===e},h={$console:!0,$external:!0,$frame:!0,$frameElement:!0,$frames:!0,$innerHeight:!0,$innerWidth:!0,$outerHeight:!0,$outerWidth:!0,$pageXOffset:!0,$pageYOffset:!0,$parent:!0,$scrollLeft:!0,$scrollTop:!0,$scrollX:!0,$scrollY:!0,$self:!0,$webkitIndexedDB:!0,$webkitStorageInfo:!0,$window:!0},d=function(){if("undefined"==typeof window)return!1;for(var e in window)try{if(!h["$"+e]&&n.call(window,e)&&null!==window[e]&&"object"==typeof window[e])try{p(window[e])}catch(t){return!0}}catch(t){return!0}return!1}(),f=function(e){if("undefined"==typeof window||!d)return p(e);try{return p(e)}catch(t){return!1}},y=function(e){var t=null!==e&&"object"==typeof e,r="[object Function]"===o.call(e),i=s(e),a=t&&"[object String]"===o.call(e),p=[];if(!t&&!r&&!i)throw new TypeError("Object.keys called on a non-object");var h=u&&r;if(a&&e.length>0&&!n.call(e,0))for(var d=0;d<e.length;++d)p.push(String(d));if(i&&e.length>0)for(var y=0;y<e.length;++y)p.push(String(y));else for(var m in e)h&&"prototype"===m||!n.call(e,m)||p.push(String(m));if(c)for(var v=f(e),g=0;g<l.length;++g)v&&"constructor"===l[g]||!n.call(e,l[g])||p.push(l[g]);return p};y.shim=function(){if(Object.keys){var e=function(){return 2===(Object.keys(arguments)||"").length}(1,2);if(!e){var t=Object.keys;
vendor: 7,601 bytes, line 32277
32277Object.keys=function(e){return t(s(e)?i.call(e):e)}}}else Object.keys=y;return Object.keys||y},t.exports=y},{11:11}],11:[function(e,t,r){"use strict";var n=Object.prototype.toString;t.exports=function(e){var t=n.call(e),r="[object Arguments]"===t;return r||(r="[object Array]"!==t&&null!==e&&"object"==typeof e&&"number"==typeof e.length&&e.length>=0&&"[object Function]"===n.call(e.callee)),r}},{}],12:[function(e,t,r){function n(){throw new Error("setTimeout has not been defined")}function o(){throw new Error("clearTimeout has not been defined")}function i(e){if(p===setTimeout)return setTimeout(e,0);if((p===n||!p)&&setTimeout)return p=setTimeout,setTimeout(e,0);try{return p(e,0)}catch(t){try{return p.call(null,e,0)}catch(t){return p.call(this,e,0)}}}function s(e){if(h===clearTimeout)return clearTimeout(e);if((h===o||!h)&&clearTimeout)return h=clearTimeout,clearTimeout(e);try{return h(e)}catch(t){try{return h.call(null,e)}catch(t){return h.call(this,e)}}}function a(){m&&f&&(m=!1,f.length?y=f.concat(y):v=-1,y.length&&c())}function c(){if(!m){var e=i(a);m=!0;for(var t=y.length;t;){for(f=y,y=[];++v<t;)f&&f[v].run();v=-1,t=y.length}f=null,m=!1,s(e)}}function u(e,t){this.fun=e,this.array=t}function l(){}var p,h,d=t.exports={};!function(){try{p="function"==typeof setTimeout?setTimeout:n}catch(e){p=n}try{h="function"==typeof clearTimeout?clearTimeout:o}catch(e){h=o}}();var f,y=[],m=!1,v=-1;d.nextTick=function(e){var t=new Array(arguments.length-1);if(arguments.length>1)for(var r=1;r<arguments.length;r++)t[r-1]=arguments[r];y.push(new u(e,t)),1!==y.length||m||i(c)},u.prototype.run=function(){this.fun.apply(null,this.array)},d.title="browser",d.browser=!0,d.env={},d.argv=[],d.version="",d.versions={},d.on=l,d.addListener=l,d.once=l,d.off=l,d.removeListener=l,d.removeAllListeners=l,d.emit=l,d.binding=function(e){throw new Error("process.binding is not supported")},d.cwd=function(){return"/"},d.chdir=function(e){throw new Error("process.chdir is not supported")},d.umask=function(){return 0}},{}],13:[function(e,t,r){"use strict";function n(e,t){if(e.map)return e.map(t);for(var r=[],n=0;n<e.length;n++)r.push(t(e[n],n));return r}var o=function(e){switch(typeof e){case"string":return e;case"boolean":return e?"true":"false";case"number":return isFinite(e)?e:"";default:return""}};t.exports=function(e,t,r,a){return t=t||"&",r=r||"=",null===e&&(e=void 0),"object"==typeof e?n(s(e),function(s){var a=encodeURIComponent(o(s))+r;return i(e[s])?n(e[s],function(e){return a+encodeURIComponent(o(e))}).join(t):a+encodeURIComponent(o(e[s]))}).join(t):a?encodeURIComponent(o(a))+r+encodeURIComponent(o(e)):""};var i=Array.isArray||function(e){return"[object Array]"===Object.prototype.toString.call(e)},s=Object.keys||function(e){var t=[];for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.push(r);return t}},{}],14:[function(e,t,r){function n(){c.apply(this,arguments)}function o(){var e="Not implemented in this environment.\nIf you feel this is a mistake, write to [email protected]";throw new l.AlgoliaSearchError(e)}t.exports=n;var i=e(16),s=e(26),a=e(27),c=e(15),u=e(7),l=e(28);u(n,c),n.prototype.deleteIndex=function(e,t){return this._jsonRequest({method:"DELETE",url:"/1/indexes/"+encodeURIComponent(e),hostType:"write",callback:t})},n.prototype.moveIndex=function(e,t,r){var n={operation:"move",destination:t};return this._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(e)+"/operation",body:n,hostType:"write",callback:r})},n.prototype.copyIndex=function(e,t,r){var n={operation:"copy",destination:t};return this._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(e)+"/operation",body:n,hostType:"write",callback:r})},n.prototype.getLogs=function(t,r,n){var o=e(25),i={};return"object"==typeof t?(i=o(t),n=r):0===arguments.length||"function"==typeof t?n=t:1===arguments.length||"function"==typeof r?(n=r,i.offset=t):(i.offset=t,i.length=r),void 0===i.offset&&(i.offset=0),void 0===i.length&&(i.length=10),this._jsonRequest({method:"GET",url:"/1/logs?"+this._getSearchParams(i,""),hostType:"read",callback:n})},n.prototype.listIndexes=function(e,t){var r="";return void 0===e||"function"==typeof e?t=e:r="?page="+e,this._jsonRequest({method:"GET",url:"/1/indexes"+r,hostType:"read",callback:t})},n.prototype.initIndex=function(e){return new i(this,e)},n.prototype.listUserKeys=function(e){return this._jsonRequest({method:"GET",url:"/1/keys",hostType:"read",callback:e})},n.prototype.getUserKeyACL=function(e,t){return this._jsonRequest({method:"GET",url:"/1/keys/"+e,hostType:"read",callback:t})},n.prototype.deleteUserKey=function(e,t){return this._jsonRequest({method:"DELETE",url:"/1/keys/"+e,hostType:"write",callback:t})},n.prototype.addUserKey=function(t,r,n){var o=e(8),i="Usage: client.addUserKey(arrayOfAcls[, params, callback])";if(!o(t))throw new Error(i);1!==arguments.length&&"function"!=typeof r||(n=r,r=null);var s={acl:t};return r&&(s.validity=r.validity,s.maxQueriesPerIPPerHour=r.maxQueriesPerIPPerHour,s.maxHitsPerQuery=r.maxHitsPerQuery,s.indexes=r.indexes,s.description=r.description,r.queryParameters&&(s.queryParameters=this._getSearchParams(r.queryParameters,"")),s.referers=r.referers),this._jsonRequest({method:"POST",url:"/1/keys",body:s,hostType:"write",callback:n})},n.prototype.addUserKeyWithValidity=s(function(e,t,r){return this.addUserKey(e,t,r)},a("client.addUserKeyWithValidity()","client.addUserKey()")),n.prototype.updateUserKey=function(t,r,n,o){var i=e(8),s="Usage: client.updateUserKey(key, arrayOfAcls[, params, callback])";if(!i(r))throw new Error(s);2!==arguments.length&&"function"!=typeof n||(o=n,n=null);var a={acl:r};return n&&(a.validity=n.validity,a.maxQueriesPerIPPerHour=n.maxQueriesPerIPPerHour,a.maxHitsPerQuery=n.maxHitsPerQuery,a.indexes=n.indexes,a.description=n.description,n.queryParameters&&(a.queryParameters=this._getSearchParams(n.queryParameters,"")),a.referers=n.referers),this._jsonRequest({method:"PUT",url:"/1/keys/"+t,body:a,hostType:"write",callback:o})},n.prototype.startQueriesBatch=s(function(){this._batch=[]},a("client.startQueriesBatch()","client.search()")),n.prototype.addQueryInBatch=s(function(e,t,r){this._batch.push({indexName:e,query:t,params:r})},a("client.addQueryInBatch()","client.search()")),n.prototype.sendQueriesBatch=s(function(e){return this.search(this._batch,e)},a("client.sendQueriesBatch()","client.search()")),n.prototype.batch=function(t,r){var n=e(8),o="Usage: client.batch(operations[, callback])";if(!n(t))throw new Error(o);return this._jsonRequest({method:"POST",url:"/1/indexes/*/batch",body:{requests:t},hostType:"write",callback:r})},n.prototype.destroy=o,n.prototype.enableRateLimitForward=o,n.prototype.disableRateLimitForward=o,n.prototype.useSecuredAPIKey=o,n.prototype.disableSecuredAPIKey=o,n.prototype.generateSecuredApiKey=o},{15:15,16:16,25:25,26:26,27:27,28:28,7:7,8:8}],15:[function(e,t,r){(function(r){function n(t,r,n){var i=e(1)("algoliasearch"),s=e(25),a=e(8),u=e(30),l="Usage: algoliasearch(applicationID, apiKey, opts)";if(n._allowEmptyCredentials!==!0&&!t)throw new c.AlgoliaSearchError("Please provide an application ID. "+l);if(n._allowEmptyCredentials!==!0&&!r)throw new c.AlgoliaSearchError("Please provide an API key. "+l);this.applicationID=t,this.apiKey=r,this.hosts={read:[],write:[]},n=n||{};var p=n.protocol||"https:";if(this._timeouts=n.timeouts||{connect:1e3,read:2e3,write:3e4},n.timeout&&(this._timeouts.connect=this._timeouts.read=this._timeouts.write=n.timeout),/:$/.test(p)||(p+=":"),"http:"!==n.protocol&&"https:"!==n.protocol)throw new c.AlgoliaSearchError("protocol must be `http:` or `https:`
32277(was `"+n.protocol+"`)");if(this._checkAppIdData(),n.hosts)a(n.hosts)?(this.hosts.read=s(n.hosts),this.hosts.write=s(n.hosts)):(this.hosts.read=s(n.hosts.read),this.hosts.write=s(n.hosts.write));else{var h=u(this._shuffleResult,function(e){return t+"-"+e+".algolianet.com"});this.hosts.read=[this.applicationID+"-dsn.algolia.net"].concat(h),this.hosts.write=[this.applicationID+".algolia.net"].concat(h)}this.hosts.read=u(this.hosts.read,o(p)),this.hosts.write=u(this.hosts.write,o(p)),this.extraHeaders=[],this.cache=n._cache||{},this._ua=n._ua,this._useCache=!(void 0!==n._useCache&&!n._cache)||n._useCache,this._useFallback=void 0===n.useFallback||n.useFallback,this._setTimeout=n._setTimeout,i("init done, %j",this)}function o(e){return function(t){return e+"//"+t.toLowerCase()}}function i(e){if(void 0===Array.prototype.toJSON)return JSON.stringify(e);var t=Array.prototype.toJSON;delete Array.prototype.toJSON;var r=JSON.stringify(e);return Array.prototype.toJSON=t,r}function s(e){for(var t,r,n=e.length;0!==n;)r=Math.floor(Math.random()*n),n-=1,t=e[n],e[n]=e[r],e[r]=t;return e}function a(e){var t={};for(var r in e)if(Object.prototype.hasOwnProperty.call(e,r)){var n;n="x-algolia-api-key"===r||"x-algolia-application-id"===r?"**hidden for security purposes**":e[r],t[r]=n}return t}t.exports=n;var c=e(28),u=e(29),l=e(18),p=e(34),h=500,d=r.env.RESET_APP_DATA_TIMER&&parseInt(r.env.RESET_APP_DATA_TIMER,10)||12e4;n.prototype.initIndex=function(e){return new l(this,e)},n.prototype.setExtraHeader=function(e,t){this.extraHeaders.push({name:e.toLowerCase(),value:t})},n.prototype.addAlgoliaAgent=function(e){this._ua.indexOf(";"+e)===-1&&(this._ua+=";"+e)},n.prototype._jsonRequest=function(t){function r(e,u){function h(e){var t=e&&e.body&&e.body.message&&e.body.status||e.statusCode||e&&e.body&&200;s("received response: statusCode: %s, computed statusCode: %d, headers: %j",e.statusCode,t,e.headers);var r=2===Math.floor(t/100),i=new Date;if(m.push({currentHost:x,headers:a(o),content:n||null,contentLength:void 0!==n?n.length:null,method:u.method,timeouts:u.timeouts,url:u.url,startTime:_,endTime:i,duration:i-_,statusCode:t}),r)return p._useCache&&l&&(l[w]=e.responseText),e.body;var h=4!==Math.floor(t/100);if(h)return d+=1,g();s("unrecoverable error");var f=new c.AlgoliaSearchError(e.body&&e.body.message,{debugData:m,statusCode:t});return p._promise.reject(f)}function v(e){s("error: %s, stack: %s",e.message,e.stack);var r=new Date;return m.push({currentHost:x,headers:a(o),content:n||null,contentLength:void 0!==n?n.length:null,method:u.method,timeouts:u.timeouts,url:u.url,startTime:_,endTime:r,duration:r-_}),e instanceof c.AlgoliaSearchError||(e=new c.Unknown(e&&e.message,e)),d+=1,e instanceof c.Unknown||e instanceof c.UnparsableJSON||d>=p.hosts[t.hostType].length&&(f||!y)?(e.debugData=m,p._promise.reject(e)):e instanceof c.RequestTimeout?b():g()}function g(){return s("retrying request"),p._incrementHostIndex(t.hostType),r(e,u)}function b(){return s("retrying request with higher timeout"),p._incrementHostIndex(t.hostType),p._incrementTimeoutMultipler(),u.timeouts=p._getTimeoutsForRequest(t.hostType),r(e,u)}p._checkAppIdData();var w,_=new Date;if(p._useCache&&(w=t.url),p._useCache&&n&&(w+="_body_"+u.body),p._useCache&&l&&void 0!==l[w])return s("serving response from cache"),p._promise.resolve(JSON.parse(l[w]));if(d>=p.hosts[t.hostType].length)return!y||f?(s("could not get any response"), 32278p._promise.reject(new c.AlgoliaSearchError("Cannot connect to the AlgoliaSearch API. Send an email to [email protected] to report and resolve the issue. Application id was: "+p.applicationID,{debugData:m}))):(s("switching to fallback"),d=0,u.method=t.fallback.method,u.url=t.fallback.url,u.jsonBody=t.fallback.body,u.jsonBody&&(u.body=i(u.jsonBody)),o=p._computeRequestHeaders(),u.timeouts=p._getTimeoutsForRequest(t.hostType),p._setHostIndexByType(0,t.hostType),f=!0,r(p._request.fallback,u));var x=p._getHostByType(t.hostType),T=x+u.url,j={body:u.body,jsonBody:u.jsonBody,method:u.method,headers:o,timeouts:u.timeouts,debug:s};return s("method: %s, url: %s, headers: %j, timeouts: %d",j.method,T,j.headers,j.timeouts),e===p._request.fallback&&s("using fallback"),e.call(p,T,j).then(h,v)}this._checkAppIdData();var n,o,s=e(1)("algoliasearch:"+t.url),l=t.cache,p=this,d=0,f=!1,y=p._useFallback&&p._request.fallback&&t.fallback;this.apiKey.length>h&&void 0!==t.body&&(void 0!==t.body.params||void 0!==t.body.requests)?(t.body.apiKey=this.apiKey,o=this._computeRequestHeaders(!1)):o=this._computeRequestHeaders(),void 0!==t.body&&(n=i(t.body)),s("request start");var m=[],v=r(p._request,{url:t.url,method:t.method,body:n,jsonBody:t.body,timeouts:p._getTimeoutsForRequest(t.hostType)});return t.callback?void v.then(function(e){u(function(){t.callback(null,e)},p._setTimeout||setTimeout)},function(e){u(function(){t.callback(e)},p._setTimeout||setTimeout)}):v},n.prototype._getSearchParams=function(e,t){if(void 0===e||null===e)return t;for(var r in e)null!==r&&void 0!==e[r]&&e.hasOwnProperty(r)&&(t+=""===t?"":"&",t+=r+"="+encodeURIComponent("[object Array]"===Object.prototype.toString.call(e[r])?i(e[r]):e[r]));return t},n.prototype._computeRequestHeaders=function(t){var r=e(5),n={"x-algolia-agent":this._ua,"x-algolia-application-id":this.applicationID};return t!==!1&&(n["x-algolia-api-key"]=this.apiKey),this.userToken&&(n["x-algolia-usertoken"]=this.userToken),this.securityTags&&(n["x-algolia-tagfilters"]=this.securityTags),this.extraHeaders&&r(this.extraHeaders,function(e){n[e.name]=e.value}),n},n.prototype.search=function(t,r,n){var o=e(8),i=e(30),s="Usage: client.search(arrayOfQueries[, callback])";if(!o(t))throw new Error(s);"function"==typeof r?(n=r,r={}):void 0===r&&(r={});var a=this,c={requests:i(t,function(e){var t="";return void 0!==e.query&&(t+="query="+encodeURIComponent(e.query)),{indexName:e.indexName,params:a._getSearchParams(e.params,t)}})},u=i(c.requests,function(e,t){return t+"="+encodeURIComponent("/1/indexes/"+encodeURIComponent(e.indexName)+"?"+e.params)}).join("&"),l="/1/indexes/*/queries";return void 0!==r.strategy&&(l+="?strategy="+r.strategy),this._jsonRequest({cache:this.cache,method:"POST",url:l,body:c,hostType:"read",fallback:{method:"GET",url:"/1/indexes/*",body:{params:u}},callback:n})},n.prototype.setSecurityTags=function(e){if("[object Array]"===Object.prototype.toString.call(e)){for(var t=[],r=0;r<e.length;++r)if("[object Array]"===Object.prototype.toString.call(e[r])){for(var n=[],o=0;o<e[r].length;++o)n.push(e[r][o]);t.push("("+n.join(",")+")")}else t.push(e[r]);e=t.join(",")}this.securityTags=e},n.prototype.setUserToken=function(e){this.userToken=e},n.prototype.clearCache=function(){this.cache={}},n.prototype.setRequestTimeout=function(e){e&&(this._timeouts.connect=this._timeouts.read=this._timeouts.write=e)},n.prototype.setTimeouts=function(e){this._timeouts=e},n.prototype.getTimeouts=function(){return this._timeouts},n.prototype._getAppIdData=function(){var e=p.get(this.applicationID);return null!==e&&this._cacheAppIdData(e),e},n.prototype._setAppIdData=function(e){return e.lastChange=(new Date).getTime(),this._cacheAppIdData(e),p.set(this.applicationID,e)},n.prototype._checkAppIdData=function(){var e=this._getAppIdData(),t=(new Date).getTime();return null===e||t-e.lastChange>d?this._resetInitialAppIdData(e):e},n.prototype._resetInitialAppIdData=function(e){var t=e||{};return t.hostIndexes={read:0,write:0},t.timeoutMultiplier=1,t.shuffleResult=t.shuffleResult||s([1,2,3]),this._setAppIdData(t)},n.prototype._cacheAppIdData=function(e){this._hostIndexes=e.hostIndexes,this._timeoutMultiplier=e.timeoutMultiplier,this._shuffleResult=e.shuffleResult},n.prototype._partialAppIdDataUpdate=function(t){var r=e(5),n=this._getAppIdData();return r(t,function(e,t){n[t]=e}),this._setAppIdData(n)},n.prototype._getHostByType=function(e){return this.hosts[e][this._getHostIndexByType(e)]},n.prototype._getTimeoutMultiplier=function(){return this._timeoutMultiplier},n.prototype._getHostIndexByType=function(e){return this._hostIndexes[e]},n.prototype._setHostIndexByType=function(t,r){var n=e(25),o=n(this._hostIndexes);return o[r]=t,this._partialAppIdDataUpdate({hostIndexes:o}),t},n.prototype._incrementHostIndex=function(e){return this._setHostIndexByType((this._getHostIndexByType(e)+1)%this.hosts[e].length,e)},n.prototype._incrementTimeoutMultipler=function(){var e=Math.max(this._timeoutMultiplier+1,4);return this._partialAppIdDataUpdate({timeoutMultiplier:e})},n.prototype._getTimeoutsForRequest=function(e){return{connect:this._timeouts.connect*this._timeoutMultiplier,complete:this._timeouts[e]*this._timeoutMultiplier}}}).call(this,e(12))},{1:1,12:12,18:18,25:25,28:28,29:29,30:30,34:34,5:5,8:8}],16:[function(e,t,r){function n(){i.apply(this,arguments)}var o=e(7),i=e(18),s=e(26),a=e(27),c=e(29),u=e(28);t.exports=n,o(n,i),n.prototype.addObject=function(e,t,r){var n=this;return 1!==arguments.length&&"function"!=typeof t||(r=t,t=void 0),this.as._jsonRequest({method:void 0!==t?"PUT":"POST",url:"/1/indexes/"+encodeURIComponent(n.indexName)+(void 0!==t?"/"+encodeURIComponent(t):""),body:e,hostType:"write",callback:r})},n.prototype.addObjects=function(t,r){var n=e(8),o="Usage: index.addObjects(arrayOfObjects[, callback])";if(!n(t))throw new Error(o);for(var i=this,s={requests:[]},a=0;a<t.length;++a){var c={action:"addObject",body:t[a]};s.requests.push(c)}return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(i.indexName)+"/batch",body:s,hostType:"write",callback:r})},n.prototype.partialUpdateObject=function(e,t,r){1!==arguments.length&&"function"!=typeof t||(r=t,t=void 0);var n=this,o="/1/indexes/"+encodeURIComponent(n.indexName)+"/"+encodeURIComponent(e.objectID)+"/partial";return t===!1&&(o+="?createIfNotExists=false"),this.as._jsonRequest({method:"POST",url:o,body:e,hostType:"write",callback:r})},n.prototype.partialUpdateObjects=function(t,r){var n=e(8),o="Usage: index.partialUpdateObjects(arrayOfObjects[, callback])";if(!n(t))throw new Error(o);for(var i=this,s={requests:[]},a=0;a<t.length;++a){var c={action:"partialUpdateObject",objectID:t[a].objectID,body:t[a]};s.requests.push(c)}return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(i.indexName)+"/batch",body:s,hostType:"write",callback:r})},n.prototype.saveObject=function(e,t){var r=this;return this.as._jsonRequest({method:"PUT",url:"/1/indexes/"+encodeURIComponent(r.indexName)+"/"+encodeURIComponent(e.objectID),body:e,hostType:"write",callback:t})},n.prototype.saveObjects=function(t,r){var n=e(8),o="Usage: index.saveObjects(arrayOfObjects[, callback])";if(!n(t))throw new Error(o);for(var i=this,s={requests:[]},a=0;a<t.length;++a){var c={action:"updateObject",objectID:t[a].objectID,body:t[a]};s.requests.push(c)}return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(i.indexName)+"/batch",body:s,hostType:"write",callback:r})},n.prototype.deleteObject=function(e,t){if("function"==typeof e||"string"!=typeof e&&"number"!=typeof e){var r=new u.AlgoliaSearchError("Cannot delete an object without an objectID");return t=e,"function"==typeof t?t(r):this.as._promise.reject(r)}var n=this;return this.as._jsonRequest({method:"DELETE",url:"/1/indexes/"+encodeURIComponent(n.indexName)+"/"+encodeURIComponent(e),hostType:"write",callback:t})},n.prototype.deleteObjects=function(t,r){var n=e(8),o=e(30),i="Usage: index.deleteObjects(arrayOfObjectIDs[, callback])";if(!n(t))throw new Error(i);var s=this,a={requests:o(t,function(e){return{action:"deleteObject",objectID:e,body:{objectID:e}}})};return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(s.indexName)+"/batch",body:a,hostType:"write",callback:r})},n.prototype.deleteByQuery=function(t,r,n){function o(e){if(0===e.nbHits)return e;var t=p(e.hits,function(e){return e.objectID});return h.deleteObjects(t).then(i).then(s)}function i(e){return h.waitTask(e.taskID)}function s(){return h.deleteByQuery(t,r)}function a(){c(function(){n(null)},d._setTimeout||setTimeout)}function u(e){c(function(){n(e)},d._setTimeout||setTimeout)}var l=e(25),p=e(30),h=this,d=h.as;1===arguments.length||"function"==typeof r?(n=r,r={}):r=l(r),r.attributesToRetrieve="objectID",r.hitsPerPage=1e3,r.distinct=!1,this.clearCache();var f=this.search(t,r).then(o);return n?void f.then(a,u):f},n.prototype.browseAll=function(t,r){function n(e){if(!a._stopped){var t;t=void 0!==e?"cursor="+encodeURIComponent(e):l,c._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(u.indexName)+"/browse?"+t,hostType:"read",callback:o})}}function o(e,t){if(!a._stopped)return e?void a._error(e):(a._result(t),void 0===t.cursor?void a._end():void n(t.cursor))}"object"==typeof t&&(r=t,t=void 0);var i=e(31),s=e(17),a=new s,c=this.as,u=this,l=c._getSearchParams(i({},r||{},{query:t}),"");return n(),a},n.prototype.ttAdapter=function(e){var t=this;return function(r,n,o){var i;i="function"==typeof o?o:n,t.search(r,e,function(e,t){return e?void i(e):void i(t.hits)})}},n.prototype.waitTask=function(e,t){function r(){return l._jsonRequest({method:"GET",hostType:"read",url:"/1/indexes/"+encodeURIComponent(u.indexName)+"/task/"+e}).then(function(e){a++;var t=i*a*a;return t>s&&(t=s),"published"!==e.status?l._promise.delay(t).then(r):e})}function n(e){c(function(){t(null,e)},l._setTimeout||setTimeout)}function o(e){c(function(){t(e)},l._setTimeout||setTimeout)}var i=100,s=5e3,a=0,u=this,l=u.as,p=r();return t?void p.then(n,o):p},n.prototype.clearIndex=function(e){var t=this;return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(t.indexName)+"/clear",hostType:"write",callback:e})},n.prototype.getSettings=function(e){var t=this;return this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(t.indexName)+"/settings?getVersion=2",hostType:"read",callback:e})},n.prototype.searchSynonyms=function(e,t){return"function"==typeof e?(t=e,e={}):void 0===e&&(e={}),this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/synonyms/search",body:e,hostType:"read",callback:t})},n.prototype.saveSynonym=function(e,t,r){return"function"==typeof t?(r=t,t={}):void 0===t&&(t={}),this.as._jsonRequest({method:"PUT",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/synonyms/"+encodeURIComponent(e.objectID)+"?forwardToSlaves="+(t.forwardToSlaves?"true":"false"),body:e,hostType:"write",callback:r})},n.prototype.getSynonym=function(e,t){return this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/synonyms/"+encodeURIComponent(e),hostType:"read",callback:t})},n.prototype.deleteSynonym=function(e,t,r){return"function"==typeof t?(r=t,t={}):void 0===t&&(t={}),this.as._jsonRequest({method:"DELETE",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/synonyms/"+encodeURIComponent(e)+"?forwardToSlaves="+(t.forwardToSlaves?"true":"false"),hostType:"write",callback:r})},n.prototype.clearSynonyms=function(e,t){return"function"==typeof e?(t=e,e={}):void 0===e&&(e={}),this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/synonyms/clear?forwardToSlaves="+(e.forwardToSlaves?"true":"false"),hostType:"write",callback:t})},n.prototype.batchSynonyms=function(e,t,r){return"function"==typeof t?(r=t,t={}):void 0===t&&(t={}),this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/synonyms/batch?forwardToSlaves="+(t.forwardToSlaves?"true":"false")+"&replaceExistingSynonyms="+(t.replaceExistingSynonyms?"true":"false"),hostType:"write",body:e,callback:r})},n.prototype.setSettings=function(e,t,r){1!==arguments.length&&"function"!=typeof t||(r=t,t={});var n=t.forwardToSlaves||!1,o=this;return this.as._jsonRequest({method:"PUT",url:"/1/indexes/"+encodeURIComponent(o.indexName)+"/settings?forwardToSlaves="+(n?"true":"false"),hostType:"write",body:e,callback:r})},n.prototype.listUserKeys=function(e){var t=this;return this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(t.indexName)+"/keys",hostType:"read",callback:e})},n.prototype.getUserKeyACL=function(e,t){var r=this;return this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(r.indexName)+"/keys/"+e,hostType:"read",callback:t})},n.prototype.deleteUserKey=function(e,t){var r=this;return this.as._jsonRequest({method:"DELETE",url:"/1/indexes/"+encodeURIComponent(r.indexName)+"/keys/"+e,hostType:"writ
32278e",callback:t})},n.prototype.addUserKey=function(t,r,n){var o=e(8),i="Usage: index.addUserKey(arrayOfAcls[, params, callback])";if(!o(t))throw new Error(i);1!==arguments.length&&"function"!=typeof r||(n=r,r=null);var s={acl:t};return r&&(s.validity=r.validity,s.maxQueriesPerIPPerHour=r.maxQueriesPerIPPerHour,s.maxHitsPerQuery=r.maxHitsPerQuery,s.description=r.description,r.queryParameters&&(s.queryParameters=this.as._getSearchParams(r.queryParameters,"")),s.referers=r.referers),this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/keys",body:s,hostType:"write",callback:n})},n.prototype.addUserKeyWithValidity=s(function(e,t,r){return this.addUserKey(e,t,r)},a("index.addUserKeyWithValidity()","index.addUserKey()")),n.prototype.updateUserKey=function(t,r,n,o){var i=e(8),s="Usage: index.updateUserKey(key, arrayOfAcls[, params, callback])";if(!i(r))throw new Error(s);2!==arguments.length&&"function"!=typeof n||(o=n,n=null);var a={acl:r};return n&&(a.validity=n.validity,a.maxQueriesPerIPPerHour=n.maxQueriesPerIPPerHour,a.maxHitsPerQuery=n.maxHitsPerQuery,a.description=n.description,n.queryParameters&&(a.queryParameters=this.as._getSearchParams(n.queryParameters,"")),a.referers=n.referers),this.as._jsonRequest({method:"PUT",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/keys/"+t,body:a,hostType:"write",callback:o})}},{17:17,18:18,25:25,26:26,27:27,28:28,29:29,30:30,31:31,7:7,8:8}],17:[function(e,t,r){"use strict";function n(){}t.exports=n;var o=e(7),i=e(4).EventEmitter;o(n,i),n.prototype.stop=function(){this._stopped=!0,this._clean()},n.prototype._end=function(){this.emit("end"),this._clean()},n.prototype._error=function(e){this.emit("error",e),this._clean()},n.prototype._result=function(e){this.emit("result",e)},n.prototype._clean=function(){this.removeAllListeners("stop"),this.removeAllListeners("end"),this.removeAllListeners("error"),this.removeAllListeners("result")}},{4:4,7:7}],18:[function(e,t,r){function n(e,t){this.indexName=t,this.as=e,this.typeAheadArgs=null,this.typeAheadValueOption=null,this.cache={}}var o=e(24),i=e(26),s=e(27);t.exports=n,n.prototype.clearCache=function(){this.cache={}},n.prototype.search=o("query"),n.prototype.similarSearch=o("similarQuery"),n.prototype.browse=function(t,r,n){var o,i,s=e(31),a=this;0===arguments.length||1===arguments.length&&"function"==typeof arguments[0]?(o=0,n=arguments[0],t=void 0):"number"==typeof arguments[0]?(o=arguments[0],"number"==typeof arguments[1]?i=arguments[1]:"function"==typeof arguments[1]&&(n=arguments[1],i=void 0),t=void 0,r=void 0):"object"==typeof arguments[0]?("function"==typeof arguments[1]&&(n=arguments[1]),r=arguments[0],t=void 0):"string"==typeof arguments[0]&&"function"==typeof arguments[1]&&(n=arguments[1],r=void 0),r=s({},r||{},{page:o,hitsPerPage:i,query:t});var c=this.as._getSearchParams(r,"");return this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(a.indexName)+"/browse?"+c,hostType:"read",callback:n})},n.prototype.browseFrom=function(e,t){return this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/browse?cursor="+encodeURIComponent(e),hostType:"read",callback:t})},n.prototype.searchForFacetValues=function(t,r){var n=e(25),o=e(32),i="Usage: index.searchForFacetValues({facetName, facetQuery, ...params}[, callback])";if(void 0===t.facetName||void 0===t.facetQuery)throw new Error(i);var s=t.facetName,a=o(n(t),function(e){return"facetName"===e}),c=this.as._getSearchParams(a,"");return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/facets/"+encodeURIComponent(s)+"/query",hostType:"read",body:{params:c},callback:r})},n.prototype.searchFacet=i(function(e,t){return this.searchForFacetValues(e,t)},s("index.searchFacet(params[, callback])","index.searchForFacetValues(params[, callback])")),n.prototype._search=function(e,t,r){return this.as._jsonRequest({cache:this.cache,method:"POST",url:t||"/1/indexes/"+encodeURIComponent(this.indexName)+"/query",body:{params:e},hostType:"read",fallback:{method:"GET",url:"/1/indexes/"+encodeURIComponent(this.indexName),body:{params:e}},callback:r})},n.prototype.getObject=function(e,t,r){var n=this;1!==arguments.length&&"function"!=typeof t||(r=t,t=void 0);var o="";if(void 0!==t){o="?attributes=";for(var i=0;i<t.length;++i)0!==i&&(o+=","),o+=t[i]}return this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(n.indexName)+"/"+encodeURIComponent(e)+o,hostType:"read",callback:r})},n.prototype.getObjects=function(t,r,n){var o=e(8),i=e(30),s="Usage: index.getObjects(arrayOfObjectIDs[, callback])";if(!o(t))throw new Error(s);var a=this;1!==arguments.length&&"function"!=typeof r||(n=r,r=void 0);var c={requests:i(t,function(e){var t={indexName:a.indexName,objectID:e};return r&&(t.attributesToRetrieve=r.join(",")),t})};return this.as._jsonRequest({method:"POST",url:"/1/indexes/*/objects",hostType:"read",body:c,callback:n})},n.prototype.as=null,n.prototype.indexName=null,n.prototype.typeAheadArgs=null,n.prototype.typeAheadValueOption=null},{24:24,25:25,26:26,27:27,30:30,31:31,32:32,8:8}],19:[function(e,t,r){"use strict";var n=e(14),o=e(20);t.exports=o(n)},{14:14,20:20}],20:[function(e,t,r){(function(r){"use strict";var n=e(6),o=n.Promise||e(3).Promise;t.exports=function(t,i){function s(t,r,n){var o=e(25),i=e(21);return n=o(n||{}),void 0===n.protocol&&(n.protocol=i()),n._ua=n._ua||s.ua,new a(t,r,n)}function a(){t.apply(this,arguments)}var c=e(7),u=e(28),l=e(22),p=e(23),h=e(33);i=i||"","debug"===r.env.NODE_ENV&&e(1).enable("algoliasearch*"),s.version=e(35),s.ua="Algolia for vanilla JavaScript "+i+s.version,s.initPlaces=h(s),n.__algolia={debug:e(1),algoliasearch:s};var d={hasXMLHttpRequest:"XMLHttpRequest"in n,hasXDomainRequest:"XDomainRequest"in n};return d.hasXMLHttpRequest&&(d.cors="withCredentials"in new XMLHttpRequest),c(a,t),a.prototype._request=function(e,t){return new o(function(r,n){function o(){if(!f){clearTimeout(h);var e;try{e={body:JSON.parse(m.responseText),responseText:m.responseText,statusCode:m.status,headers:m.getAllResponseHeaders&&m.getAllResponseHeaders()||{}}}catch(t){e=new u.UnparsableJSON({more:m.responseText})}e instanceof u.UnparsableJSON?n(e):r(e)}}function i(e){f||(clearTimeout(h),n(new u.Network({more:e})))}function s(){f=!0,m.abort(),n(new u.RequestTimeout)}
32278function a(){v=!0,clearTimeout(h),h=setTimeout(s,t.timeouts.complete)}function c(){v||a()}function p(){!v&&m.readyState>1&&a()}if(!d.cors&&!d.hasXDomainRequest)return void n(new u.Network("CORS not supported"));e=l(e,t.headers);var h,f,y=t.body,m=d.cors?new XMLHttpRequest:new XDomainRequest,v=!1;h=setTimeout(s,t.timeouts.connect),m.onprogress=c,"onreadystatechange"in m&&(m.onreadystatechange=p),m.onload=o,m.onerror=i,m instanceof XMLHttpRequest?m.open(t.method,e,!0):m.open(t.method,e),d.cors&&(y&&("POST"===t.method?m.setRequestHeader("content-type","application/x-www-form-urlencoded"):m.setRequestHeader("content-type","application/json")),m.setRequestHeader("accept","application/json")),m.send(y)})},a.prototype._request.fallback=function(e,t){return e=l(e,t.headers),new o(function(r,n){p(e,t,function(e,t){return e?void n(e):void r(t)})})},a.prototype._promise={reject:function(e){return o.reject(e)},resolve:function(e){return o.resolve(e)},delay:function(e){return new o(function(t){setTimeout(t,e)})}},s}}).call(this,e(12))},{1:1,12:12,21:21,22:22,23:23,25:25,28:28,3:3,33:33,35:35,6:6,7:7}],21:[function(e,t,r){"use strict";function n(){var e=window.document.location.protocol;return"http:"!==e&&"https:"!==e&&(e="http:"),e}t.exports=n},{}],22:[function(e,t,r){"use strict";function n(e,t){return e+=/\?/.test(e)?"&":"?",e+o(t)}t.exports=n;var o=e(13)},{13:13}],23:[function(e,t,r){"use strict";function n(e,t,r){function n(){t.debug("JSONP: success"),m||h||(m=!0,p||(t.debug("JSONP: Fail. Script loaded but did not call the callback"),a(),r(new o.JSONPScriptFail)))}function s(){"loaded"!==this.readyState&&"complete"!==this.readyState||n()}function a(){clearTimeout(v),f.onload=null,f.onreadystatechange=null,f.onerror=null,d.removeChild(f)}function c(){try{delete window[y],delete window[y+"_loaded"]}catch(e){window[y]=window[y+"_loaded"]=void 0}}function u(){t.debug("JSONP: Script timeout"),h=!0,a(),r(new o.RequestTimeout)}function l(){t.debug("JSONP: Script error"),m||h||(a(),r(new o.JSONPScriptError))}if("GET"!==t.method)return void r(new Error("Method "+t.method+" "+e+" is not supported by JSONP."));t.debug("JSONP: start");var p=!1,h=!1;i+=1;var d=document.getElementsByTagName("head")[0],f=document.createElement("script"),y="algoliaJSONP_"+i,m=!1;window[y]=function(e){return c(),h?void t.debug("JSONP: Late answer, ignoring"):(p=!0,a(),void r(null,{body:e}))},e+="&callback="+y,t.jsonBody&&t.jsonBody.params&&(e+="&"+t.jsonBody.params);var v=setTimeout(u,t.timeouts.complete);f.onreadystatechange=s,f.onload=n,f.onerror=l,f.async=!0,f.defer=!0,f.src=e,d.appendChild(f)}t.exports=n;var o=e(28),i=0},{28:28}],24:[function(e,t,r){function n(e,t){return function(r,n,i){if("function"==typeof r&&"object"==typeof n||"object"==typeof i)throw new o.AlgoliaSearchError("index.search usage is index.search(query, params, cb)");0===arguments.length||"function"==typeof r?(i=r,r=""):1!==arguments.length&&"function"!=typeof n||(i=n,n=void 0),"object"==typeof r&&null!==r?(n=r,r=void 0):void 0!==r&&null!==r||(r="");var s="";return void 0!==r&&(s+=e+"="+encodeURIComponent(r)),void 0!==n&&(s=this.as._getSearchParams(n,s)),this._search(s,t,i)}}t.exports=n;var o=e(28)},{28:28}],25:[function(e,t,r){t.exports=function(e){return JSON.parse(JSON.stringify(e))}},{}],26:[function(e,t,r){t.exports=function(e,t){function r(){return n||(console.log(t),n=!0),e.apply(this,arguments)}var n=!1;return r}},{}],27:[function(e,t,r){t.exports=function(e,t){var r=e.toLowerCase().replace(".","").replace("()","");return"algoliasearch: `"+e+"` was replaced by `"+t+"`. Please see https://github.com/algolia/algoliasearch-client-js/wiki/Deprecated#"+r}},{}],28:[function(e,t,r){"use strict";function n(t,r){var n=e(5),o=this;"function"==typeof Error.captureStackTrace?Error.captureStackTrace(this,this.constructor):o.stack=(new Error).stack||"Cannot get a stacktrace, browser is too old",this.name="AlgoliaSearchError",this.message=t||"Unknown error",r&&n(r,function(e,t){o[t]=e})}function o(e,t){function r(){var r=Array.prototype.slice.call(arguments,0);"string"!=typeof r[0]&&r.unshift(t),n.apply(this,r),this.name="AlgoliaSearch"+e+"Error"}return i(r,n),r}var i=e(7);
32278i(n,Error),t.exports={AlgoliaSearchError:n,UnparsableJSON:o("UnparsableJSON","Could not parse the incoming response as JSON, see err.more for details"),RequestTimeout:o("RequestTimeout","Request timedout before getting a response"),Network:o("Network","Network issue, see err.more for details"),JSONPScriptFail:o("JSONPScriptFail","<script> was loaded but did not call our provided callback"),JSONPScriptError:o("JSONPScriptError","<script> unable to load due to an `error` event on it"),Unknown:o("Unknown","Unknown error occured")}},{5:5,7:7}],29:[function(e,t,r){t.exports=function(e,t){t(e,0)}},{}],30:[function(e,t,r){var n=e(5);t.exports=function(e,t){var r=[];return n(e,function(n,o){r.push(t(n,o,e))}),r}},{5:5}],31:[function(e,t,r){var n=e(5);t.exports=function o(e){var t=Array.prototype.slice.call(arguments);return n(t,function(t){for(var r in t)t.hasOwnProperty(r)&&("object"==typeof e[r]&&"object"==typeof t[r]?e[r]=o({},e[r],t[r]):void 0!==t[r]&&(e[r]=t[r]))}),e}},{5:5}],32:[function(e,t,r){t.exports=function(t,r){var n=e(10),o=e(5),i={};return o(n(t),function(e){r(e)!==!0&&(i[e]=t[e])}),i}},{10:10,5:5}],33:[function(e,t,r){function n(t){return function(r,n,i){var s=e(25);i=i&&s(i)||{},i.hosts=i.hosts||["places-dsn.algolia.net","places-1.algolianet.com","places-2.algolianet.com","places-3.algolianet.com"],0!==arguments.length&&"object"!=typeof r&&void 0!==r||(r="",n="",i._allowEmptyCredentials=!0);var a=t(r,n,i),c=a.initIndex("places");return c.search=o("query","/1/places/query"),c}}t.exports=n;var o=e(24)},{24:24,25:25}],34:[function(e,t,r){(function(r){function n(e,t){return 1===arguments.length?s.get(e):s.set(e,t)}function o(){try{return"localStorage"in r&&null!==r.localStorage&&!r.localStorage[c]&&(r.localStorage.setItem(c,JSON.stringify({})),!0)}catch(e){return!1}}function i(){try{r.localStorage.removeItem(c)}catch(e){}}var s,a=e(1)("algoliasearch:src/hostIndexState.js"),c="algoliasearch-client-js",u={state:{},set:function(e,t){return this.state[e]=t,this.state[e]},get:function(e){return this.state[e]||null}},l={set:function(e,t){try{var n=JSON.parse(r.localStorage[c]);return n[e]=t,r.localStorage[c]=JSON.stringify(n),n[e]}catch(o){return a("localStorage set failed with",o),i(),s=u,s.set(e,t)}},get:function(e){return JSON.parse(r.localStorage[c])[e]||null}};s=o()?l:u,t.exports={get:n,set:n}}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{1:1}],35:[function(e,t,r){"use strict";t.exports="3.20.3"},{}]},{},[19])(19)}); 32279// This is a manifest file that'll be compiled into application.js, which will include all the files 32280// listed below. 32281// 32282// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, 32283// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path. 32284// 32285// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the 32286// compiled file. JavaScript code in this file should be added after the last require_* statement. 32287// 32288// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details 32289// about supported directives. 32290// 32291 32292 32293 32294 32295 32296 32297 32298 32299 32300 32301 32302 32303 32304 32305function start_theme() { 32306 32307 $('input[id^=theme_colour_header_back]').change(function(){ 32308 refresh_header_theme(); 32309 }) 32310 32311 $('input#header_links_buttons').change(function(){ 32312 if ($('input#header_links_buttons').is(':checked')) { 32313 $('div#colour_menu_text').hide(); 32314 $('div#colour_menu_back').show(); 32315 } else { 32316 $('div#colour_menu_text').show(); 32317 $('div#colour_menu_back').hide(); 32318 } 32319 refresh_header_theme(); 32320 }) 32321 32322 if ($('input#header_links_buttons').is(':checked')) { 32323 $('div#colour_menu_text').hide(); 32324 } else { 32325 $('div#colour_menu_back').hide(); 32326 } 32327 32328 refresh_header_theme(); 32329 32330} 32331 32332function refresh_header_theme() { 32333 32334 if ($('input[id^=theme_colour_header_back]:checked').val() == '#FFFFFF') { 32335 $('input[id^=theme_colour_header_text]').val('#4C4C4C'); 32336 if ($('input#header_links_buttons').is(':checked')) { 32337 $set = false; 32338 $('input[id^=theme_colour_menu_back]').each(function(){ 32339 $(this).prop('disabled', false); 32340 if ($(this).val() != $('input[id^=theme_colour_header_back]:checked').val()) { 32341 if (!$set) { 32342 if ($('input[id^=theme_colour_menu_text]:checked').val() != $('input[id^=theme_colour_header_back]:checked').val()) { 32343 if ($(this).val() == $('input[id^=theme_colour_menu_text]:checked').val()) { 32344 $(this).prop('checked', true); 32345 $set = true; 32346 } 32347 } 32348 } 32349 } else { 32350 $(this).prop('disabled', true); 32351 } 32352 }); 32353 $('input[id^=theme_colour_menu_text]').each(function(){ 32354 $(this).prop('disabled', false); 32355 if ($(this).val() == '#FFFFFF') { 32356 $(this).prop('checked', true); 32357 } else { 32358 $(this).prop('disabled', true); 32359 } 32360 }); 32361 } else { 32362 $set = false;
32363 $('input[id^=theme_colour_menu_text]').each(function(){ 32364 $(this).prop('disabled', false); 32365 if ($(this).val() != $('input[id^=theme_colour_header_back]:checked').val()) { 32366 if (!$set) { 32367 if ($('input[id^=theme_colour_menu_back]:checked').val() != $('input[id^=theme_colour_header_back]:checked').val()) { 32368 if ($(this).val() == $('input[id^=theme_colour_menu_back]:checked').val()) { 32369 $(this).prop('checked', true); 32370 $set = true; 32371 } 32372 } 32373 } 32374 } else { 32375 $(this).prop('disabled', true); 32376 } 32377 }); 32378 $('input[id^=theme_colour_menu_back]').each(function(){ 32379 $(this).prop('disabled', false); 32380 if ($(this).val() == '#FFFFFF') { 32381 $(this).prop('checked', true); 32382 } else { 32383 $(this).prop('disabled', true); 32384 } 32385 }); 32386 } 32387 } else { 32388 $('input[id^=theme_colour_header_text]').val('#FFFFFF'); 32389 if ($('input#header_links_buttons').is(':checked')) { 32390 $('input[id^=theme_colour_menu_text]').each(function(){ 32391 $(this).prop('disabled', false); 32392 if ($(this).val() == $('input[id^=theme_colour_header_back]:checked').val()) { 32393 $(this).prop('checked', true); 32394 } else { 32395 $(this).prop('disabled', true); 32396 } 32397 }); 32398 $('input[id^=theme_colour_menu_back]').each(function(){ 32399 $(this).prop('disabled', false); 32400 if ($(this).val() == '#FFFFFF') { 32401 $(this).prop('checked', true); 32402 } else { 32403 $(this).prop('disabled', true); 32404 } 32405 }); 32406 } else { 32407 $('input[id^=theme_colour_menu_text]').each(function(){ 32408 $(this).prop('disabled', false); 32409 if ($(this).val() == '#FFFFFF') { 32410 $(this).prop('checked', true); 32411 } else { 32412 $(this).prop('disabled', true); 32413 } 32414 }); 32415 $('input[id^=theme_colour_menu_back]').each(function(){ 32416 $(this).prop('disabled', false); 32417 if ($(this).val() == $('input[id^=theme_colour_header_back]:checked').val()) { 32418 $(this).prop('checked', true); 32419 } else { 32420 $(this).prop('disabled', true); 32421 } 32422 }); 32423 } 32424 } 32425 32426} 32427 32428function start_fonts() { 32429 32430 refresh_fonts(); 32431 32432 $preferred_fonts = [ 32433 'Libre Baskerville', 32434 'Montserrat', 32435 'Oswald', 32436 'Raleway', 32437 'Roboto Slab', 32438 'Rubik', 32439 'Signika', 32440 'Ubuntu', 32441 'Volkhov' 32442 ]; 32443 $('select[id^=theme_font] option').each(function(){ 32444 $(this).addClass('expanded'); 32445 if ($preferred_fonts.indexOf($(this).html())>-1) { 32446 $(this).addClass('standard'); 32447 } 32448 }); 32449 $('select[id^=theme_font]').parents('div.field').each(function(){ 32450 $(this).addClass('fonts'); 32451 if ($preferred_fonts.indexOf($('option:selected', $(this)).html())>-1) { 32452 $('a.toggle.standard', $(this)).addClass('selected'); 32453 } else { 32454 $('select', $(this)).addClass('expanded'); 32455 $('a.toggle.expanded', $(this)).addClass('selected'); 32456 } 32457 $('a.toggle', $(this)).click(function(e){ 32458 $('a.toggle', $(this).parents('div.field')).removeClass('selected'); 32459 $(this).addClass('selected'); 32460 if ($(this).hasClass('expanded')) { 32461 $('select', $(this).parents('div.field')).addClass('expanded'); 32462 } else { 32463 $('select', $(this).parents('div.field')).removeClass('expanded'); 32464 } 32465 e.preventDefault(); 32466 }); 32467 }); 32468 32469 $('select[id^=theme_font]').change(function(){ 32470 $('head').append($('<link href="https://fonts.googleapis.com/css?family='+$(this).val().replace(' ','+')+':400,400i,700,700i" rel="stylesheet" />')); 32471 refresh_fonts(); 32472 }); 32473 32474} 32475 32476function refresh_fonts() { 32477 32478 var $trim_length = 15; 32479 32480 $font_1_name = $('select#theme_font_1').val(); 32481 $font_1_trim = ($font_1_name.length > ($trim_length+3)) ? $font_1_name.substring(0, $trim_length)+'...' : $font_1_name; 32482// $font_2_name = $('select#theme_font_2').val(); 32483// $font_2_trim = ($font_2_name.length > ($trim_length+3)) ? $font_2_name.substring(0, $trim_length)+'...' : $font_2_name; 32484// $font_3_name = $('select#theme_font_3').val(); 32485// $font_3_trim = ($font_3_name.length > ($trim_length+3)) ? $font_3_name.substring(0, $trim_length)+'...' : $font_3_name; 32486 $font_4_name = $('input#theme_font_4').val(); 32487 $font_4_trim = ($font_4_name.length > ($trim_length+3)) ? $font_4_name.substring(0, $trim_length)+'...' : $font_4_name; 32488 32489// $font_1_trim = $font_1_name.val().trim().substring(0, 20).split(" ").slice(0, -1).join(" ") + "..."; 32490 32491 $('label.font_1').html($font_1_trim); 32492// $('label.font_2').html($font_2_trim); 32493// $('label.font_3').html($font_3_trim); 32494 $('label.font_4').html($font_4_trim); 32495 $('input.font_1').val($font_1_name); 32496// $('input.font_2').val($font_2_name); 32497// $('input.font_3').val($font_3_name); 32498 $('input.font_4').val($font_4_name); 32499 $('option.font_1').val($font_1_name); 32500// $('option.font_2').val($font_2_name); 32501// $('option.font_3').val($font_3_name); 32502 $('option.font_4').val($font_4_name); 32503 32504 refresh_preview(); 32505 32506} 32507 32508function start_colours() { 32509 32510 refresh_colours(); 32511 32512 $('div').click(refresh_colours); 32513 32514 $('input.colour.hex').change(refresh_colours); 32515 32516} 32517 32518function refresh_colours() { 32519
32520 $('input.colour_1').val($('input#theme_colour_1').val()); 32521 $('input.colour_2').val($('input#theme_colour_2').val()); 32522 $('input.colour_3').val($('input#theme_colour_3').val()); 32523 $('input.colour_4').val($('input#theme_colour_4').val()); 32524 $('option.colour_1').val($('input#theme_colour_1').val()); 32525 $('option.colour_2').val($('input#theme_colour_2').val()); 32526 $('option.colour_3').val($('input#theme_colour_3').val()); 32527 $('option.colour_4').val($('input#theme_colour_4').val()); 32528 32529 $('label.colour').each(function(){ 32530 $(this).css('color', '#FFFFFF'); 32531 $(this).css('background-color', $('#'+$(this).attr('for')).val()); 32532 }); 32533 32534 $('input[type="hidden"]').each(function(){ 32535 var $back = $('input[name="'+$(this).attr('name').replace('text','back')+'"]:checked').val(); 32536 }); 32537 32538 refresh_preview(); 32539 32540} 32541 32542function start_images() { 32543 32544 $('div.row.image').each(function(){ 32545 $('input[id*=remove_]', $(this)).each(function(){ 32546 $(this).change(function(){ 32547 if (this.checked) { 32548 $('div.thumb', $(this).parents('div.row.image')).hide(); 32549 $('div.field', $(this).parents('div.row.image')).show(); 32550 } else { 32551 $('div.field', $(this).parents('div.row.image')).hide(); 32552 $('div.thumb', $(this).parents('div.row.image')).show(); 32553 } 32554 }); 32555 $('input#'+$('label', $(this).parents('div.row.image')).attr('for')).change(function(){ 32556 if (this.files.length == 0) { 32557 $('input[id*=remove_]', $(this).parents('div.row.image')).prop('checked', true); 32558 } else { 32559 $('input[id*=remove_]', $(this).parents('div.row.image')).prop('checked', false); 32560 } 32561 }); 32562 $(this).hide(); 32563 $('div.field', $(this).parents('div.row.image')).hide(); 32564 }); 32565 }); 32566 32567} 32568 32569function refresh_template(id, content) { 32570 32571 $('#'+id).html(content); 32572 32573} 32574 32575function start_editor() { 32576 32577 $('textarea.editor').each(function(){ 32578 32579 $(this).hide(); 32580 32581 $toolbar = $('<div class="toolbar"></div>'); 32582 $iframe = $('<iframe id="editor1" class="editor"></iframe>'); 32583 32584 $editor = $('<div class="editor"></div>'); 32585 $editor.append($toolbar); 32586 $editor.append($iframe); 32587 32588 $(this).parent().append($editor); 32589 32590 refresh_toolbar(); 32591 32592 $contents = $(this).val(); 32593 $iframe.contents().get(0).write($contents); 32594 $iframe.contents().get(0).close(); 32595 $iframe.contents().find('body').addClass('editor'); 32596 $('head link').each(function(e){ 32597 $iframe.contents().find('head').append($(this).clone()); 32598 }); 32599 $('head style').each(function(e){ 32600 $iframe.contents().find('head').append($(this).clone()); 32601 }); 32602 $iframe.contents().attr('designMode', 'on'); 32603 32604 $iframe.contents().find('body').keyup(function(e){ 32605 refresh_toolbar(); 32606 }); 32607 $iframe.contents().find('body').mouseup(function(e){ 32608 refresh_toolbar(); 32609 }); 32610 32611 $(this).parents('form').submit(function(e){ 32612 $('textarea.editor').val($iframe.contents().find('body').html()); 32613 }); 32614 32615 }); 32616 32617 $('textarea.editor-mailer').redactor({ 32618 structure: true, 32619 minHeight: 300, 32620 maxHeight: 600, 32621 imageUpload: '/redactor2_rails/images', 32622 imageUploadFields: '[name="authenticity_token"]', 32623 imageCaption: true, 32624 imagePosition: true, 32625 imageResizable: true, 32626 imageFloatMargin: '0', 32627 linkify: false, 32628 linkValidation: false, 32629 plugins: [ 32630 'source', 32631 'alignment', 32632// 'hubblebutton', 32633 'hubbletoken', 32634 'imagemanager' 32635 ], 32636 buttons: [ 32637 'format', 32638 'lists', 32639 'bold', 32640 'italic', 32641// 'deleted', 32642 'horizontalrule', 32643 'image', 32644 'link' 32645 ], 32646 formatting: [ 32647 'p', 32648 'blockquote', 32649 'h1', 32650 'h2', 32651 'h3', 32652 'h4' 32653 ], 32654 formattingAdd: { 32655 "notation": { 32656 title: 'Notation', 32657 api: 'module.block.format', 32658 args: [ 32659 'p', 'class', 'small grey', 'toggle' 32660 ] 32661 } 32662 }, 32663 pastePlainText: true, 32664 pasteImages: false, 32665 pasteLinks: false, 32666 callbacks: { 32667 imageUploadError: function(json) 32668 { 32669 console.log(json); 32670 }, 32671 fileUploadError: function(json) 32672 { 32673 console.log(json); 32674 } 32675 } 32676 }); 32677 32678 $('textarea.editor-complex').redactor({ 32679 structure: true, 32680 minHeight: 300, 32681 maxHeight: 600, 32682 fileUpload: '/redactor2_rails/files', 32683 fileUploadFields: '[name="authenticity_token"]', 32684 imageUpload: '/redactor2_rails/images', 32685 imageUploadFields: '[name="authenticity_token"]', 32686 imageCaption: true, 32687 imagePosition: true, 32688 imageResizable: true, 32689 imageFloatMargin: '0', 32690 linkify: false, 32691 linkValidation: false, 32692 plugins: [ 32693 'source', 32694 'alignment', 32695 'table', 32696 'video', 32697// 'hubblebutton', 32698 'hubblesubsup', 32699 'hubbleimage', 32700 'hubblelink', 32701 'imagemanager', 32702 'filemanager' 32703 ], 32704 buttons: [ 32705 'format', 32706 'lists', 32707 'bold', 32708 'italic', 32709// 'deleted', 32710 'horizontalrule', 32711 'image', 32712 'file', 32713 'link' 32714 ], 32715 formatting: [ 32716 'p', 32717 'blockquote', 32718 'h2', 32719 'h3', 32720 'h4' 32721 ], 32722 formattingAdd: { 32723 "notation": { 32724 title: 'Notation', 32725 api: 'module.block.format', 32726 args: [ 32727 'p', 'class', 'small grey', 'toggle' 32728 ] 32729 } 32730 }, 32731 pastePlainText: true, 32732 pasteImages: false, 32733 pasteLinks: false, 32734 callbacks: { 32735 imageUploadError: function(json) 32736 { 32737 console.log(json); 32738 }, 32739 fileUploadError: function(json) 32740 { 32741 console.log(json); 32742 } 32743 } 32744 }); 32745 32746 $('textarea.editor-content').redactor({ 32747 structure: true, 32748 minHeight: 300, 32749 maxHeight: 600, 32750 linkify: false, 32751 linkValidation: false, 32752 plugins: [ 32753 'source', 32754 'alignment', 32755 'table', 32756 'hubblesubsup', 32757 'hubbledo', 32758 'hubblelink' 32759 ], 32760 buttons: [ 32761 'format', 32762 'lists', 32763 'bold', 32764 'italic', 32765 'link' 32766 ], 32767 formatting: [ 32768 'p', 32769 'blockquote', 32770 'h2', 32771 'h3', 32772 'h4' 32773 ], 32774 formattingAdd: { 32775 "notation": { 32776 title: 'Notation', 32777 api: 'module.block.format', 32778 args: [ 32779 'p', 'class', 'small grey', 'toggle' 32780 ] 32781 } 32782 }, 32783 pastePlainText: true, 32784 pasteImages: false, 32785 pasteLinks: false 32786 }); 32787 32788 $('textarea.editor-transmission').redactor({ 32789 structure: true, 32790 minHeight: 300, 32791 maxHeight: 600, 32792 linkify: false, 32793 linkValidation: false, 32794 plugins: [ 32795 'source', 32796 'alignment', 32797 'hubbletoken', 32798 'hubblesubsup', 32799 'hubbledo' 32800 ], 32801 buttons: [ 32802 'format', 32803 'lists', 32804 'bold', 32805 'italic', 32806 'link' 32807 ], 32808 formatting: [ 32809 'p', 32810 'blockquote', 32811 'h1', 32812 'h2', 32813 'h3', 32814 'h4' 32815 ], 32816 formattingAdd: { 32817 "notation": { 32818 title: 'Notation', 32819 api: 'module.block.format', 32820 args: [ 32821 'p', 'class', 'small grey', 'toggle' 32822 ] 32823 } 32824 }, 32825 pastePlainText: true, 32826 pasteImages: false, 32827 pasteLinks: false 32828 }); 32829 32830 $('textarea.editor-grid').redactor({ 32831 structure: true, 32832 minHeight: 300, 32833 maxHeight: 600, 32834 linkify: false, 32835 linkValidation: false, 32836 plugins: [ 32837 'source', 32838 'alignment', 32839 'hubblesubsup', 32840 'hubbledo', 32841 'hubblelink' 32842 ], 32843 buttons: [ 32844 'format', 32845 'lists', 32846 'bold', 32847 'italic', 32848 'link' 32849 ], 32850 formatting: [ 32851 'p', 32852 'blockquote', 32853 'h2', 32854 'h3', 32855 'h4' 32856 ], 32857 formattingAdd: { 32858 "notation": { 32859 title: 'Notation', 32860 api: 'module.block.format', 32861 args: [ 32862 'p', 'class', 'small grey', 'toggle' 32863 ] 32864 } 32865 }, 32866 pastePlainText: true, 32867 pasteImages: false, 32868 pasteLinks: false 32869 }); 32870 32871 $('textarea.editor-simple').redactor({ 32872 structure: true, 32873 toolbar: false, 32874 minHeight: 200, 32875 maxHeight: 600, 32876 linkify: false, 32877 linkValidation: false, 32878 buttons: [ 32879 'bold', 32880 'italic' 32881 ], 32882 formatting: [ 32883 'p', 32884 'blockquote', 32885 'h2', 32886 'h3', 32887 'h4' 32888 ], 32889 pastePlainText: true, 32890 pasteImages: false, 32891 pasteLinks: false, 32892 }); 32893 32894} 32895 32896function refresh_toolbar() { 32897 32898 $toolbar.html(''); 32899 32900 $toolbar.append($('<select class="format"><option value="<p>" selected="selected">Paragraph</option><option value="<h2>">Large heading</option><option value="<h3>">Small heading</option><option value="<div>">Empty (DIV)</option></select>')); 32901 $toolbar.append($('<a href="" class="button olist"># List</a>')); 32902 $toolbar.append($('<a href="" class="button ulist">• List</a>')); 32903 $toolbar.append($('<a href="" class="button bold">B</a>')); 32904 $toolbar.append($('<a href="" class="button italic">I</a>')); 32905 $toolbar.append($('<a href="" class="button link ready">Link</a>')); 32906 32907 $selection = document.getElementById('editor1').contentWindow.getSelection(); 32908 $parents = []; 32909 if ($selection.rangeCount) { 32910 $ancestor = $selection.getRangeAt(0).commonAncestorContainer; 32911 while ($ancestor.parentNode.tagName != 'BODY') { 32912 $parents.push($ancestor.parentNode); 32913 $ancestor = $ancestor.parentNode; 32914 } 32915 } 32916 32917 for (var $i = 0; $i < $parents.length; $i++) { 32918 switch($parents[$i].tagName) { 32919 case 'P': 32920 $('div.toolbar select.format', $editor).val('<p>'); 32921 break; 32922 case 'H2': 32923 $('div.toolbar select.format', $editor).val('<h2>'); 32924 break; 32925 case 'H3': 32926 $('div.toolbar select.format', $editor).val('<h3>'); 32927 break; 32928 case 'DIV': 32929 $('div.toolbar select.format', $editor).val('<div>'); 32930 break; 32931 case 'OL': 32932 $('div.toolbar a.button.olist', $editor).addClass('active'); 32933 break; 32934 case 'UL': 32935 $('div.toolbar a.button.ulist', $editor).addClass('active'); 32936 break; 32937 case 'STRONG': 32938 $('div.toolbar a.button.bold', $editor).addClass('active'); 32939 break; 32940 case 'EM': 32941 $('div.toolbar a.button.italic', $editor).addClass('active'); 32942 break; 32943 case 'A': 32944 $('div.toolbar a.button.link', $editor).removeClass('ready'); 32945 $('div.toolbar a.button.link', $editor).addClass('active'); 32946 break; 32947 } 32948 } 32949 32950 $('div.toolbar select.format', $editor).change(function(e){ 32951 $('iframe',$(this).parents('div.field')).contents().get(0).execCommand('formatBlock', false, $(this).val()); 32952 refresh_toolbar(); 32953 e.preventDefault(); 32954 }); 32955 $('div.toolbar a.button.olist', $editor).click(function(e){ 32956 $('iframe',$(this).parents('div.field')).contents().get(0).execCommand('insertOrderedList',false,null); 32957 refresh_toolbar(); 32958 e.preventDefault(); 32959 }); 32960 $('div.toolbar a.button.ulist', $editor).click(function(e){ 32961 $('iframe',$(this).parents('div.field')).contents().get(0).execCommand('insertUnorderedList',false,null); 32962 refresh_toolbar(); 32963 e.preventDefault(); 32964 }); 32965 $('div.toolbar a.button.bold', $editor).click(function(e){ 32966 $('iframe',$(this).parents('div.field')).contents().get(0).execCommand('bold',fal
32966se,null); 32967 $('iframe',$(this).parents('div.field')).contents().find('b').replaceWith(function(){ 32968 return $('<strong />').append($(this).contents()); 32969 }); 32970 refresh_toolbar(); 32971 e.preventDefault(); 32972 }); 32973 $('div.toolbar a.button.italic', $editor).click(function(e){ 32974 $('iframe',$(this).parents('div.field')).contents().get(0).execCommand('Italic',false,null); 32975 $('iframe',$(this).parents('div.field')).contents().find('i').replaceWith(function(){ 32976 return $('<em />').append($(this).contents()); 32977 }); 32978 refresh_toolbar(); 32979 e.preventDefault(); 32980 }); 32981 $('div.toolbar a.button.link.ready', $editor).click(function(e){ 32982 $form = $('<form></form>'); 32983 $form.append($('<div class="field"><label for="modal_href">URL</label><input type="text" id="modal_href" /></div>')); 32984// $form.append($('<div class="field"><label for="modal_target">Target</label><select id="modal_target"><option value="_self" selected="selected">Same window</option><option value="_blank">New window</option></select></div>')); 32985 $form.append($('<div class="actions"><input type="submit" value="Create link" /></div>')); 32986 $form.submit(function(e){ 32987 $('iframe').contents().get(0).execCommand('CreateLink',false,$('input#modal_href').val()); 32988 close_modal(); 32989 e.preventDefault(); 32990 }); 32991 start_modal($form); 32992 refresh_toolbar(); 32993 e.preventDefault(); 32994 }); 32995 $('div.toolbar a.button.link.active', $editor).click(function(e){ 32996 $('iframe',$(this).parents('div.field')).contents().get(0).execCommand('UnLink',false,null); 32997 refresh_toolbar(); 32998 e.preventDefault(); 32999 }); 33000 33001} 33002 33003function start_menu_sort() { 33004 33005 $('form.menusort').prepend('<div class="cover"></div>'); 33006 $('form.menusort div.cover').hide(); 33007 $('form.menusort input[type="submit"]').hide(); 33008 33009 $('form.menusort').each(function(){ 33010 refresh_menu_sort($('ol.dd-list', this).first()); 33011 }); 33012 33013 $('.dd').nestable({ maxDepth: 5 }); 33014 $('.dd').on('change', function() { 33015 var $list = $('ol.dd-list', this).first(); 33016 refresh_menu_sort($list); 33017 save_menu_sort($list); 33018 }); 33019 33020} 33021 33022function refresh_menu_sort(menu) { 33023 33024 $('select[id$="menu"]', menu).each(function(index){ 33025 $(this).val($(this).parents('form.menusort').data('menu')); 33026 $(this).hide(); 33027 }); 33028 33029 $('select[id$="weight"]', menu).each(function(index){ 33030 $(this).val($(this).parent().index()+1); 33031 $(this).hide(); 33032 }); 33033 33034 $('input[id$="parent_id"], select[id$="parent_id"]', menu).each(function(index){ 33035 $parent_id = 0; 33036 if ($(this).parent().parents('li').length > 0) { 33037 $parent_id = $(this).parent().parents('li').data('id'); 33038 } 33039 $(this).val($parent_id); 33040 $(this).hide(); 33041 }); 33042 33043} 33044 33045function save_menu_sort(menu) { 33046 $('div.cover', menu.parents('form')).show(); 33047 menu.parents('form').submit(); 33048} 33049 33050function start_menulinks_actionsmenu($menulinks) { 33051 33052 $('div.actions', $menulinks).each(function(){ 33053 $('ul', $(this)).hide(); 33054 $('a.toggle', $(this)).click(function(e){ 33055 $('ul', $(this).parents('div.actions')).toggle(); 33056 e.preventDefault(); 33057 }); 33058 }); 33059 33060 $(document).click (function (e) { 33061 if ($(e.target).parents('div.actions').length < 1) { 33062 $('form.menusort div.actions ul').hide(); 33063 } 33064 }); 33065 33066} 33067 33068function start_progress() { 33069 33070 reset_progress(); 33071 33072 $('form').submit(function(){ 33073 33074 remove_errors($(this)); 33075 33076 $('input[type="submit"]', $(this)).attr('disabled', true); 33077 $('input[type="submit"]', $(this)).css('opacity', '0.5'); 33078 $('div.progress', $(this)).fadeIn(); 33079 33080 }); 33081 33082} 33083 33084function start_form_ajax_errors() { 33085 33086 // scoped to <form> submissions only - remote links (the more common 33087 // ajax:remote pattern in this app) aren't covered by this handler 33088 33089 $(document).on('ajax:error', 'form', function(){ 33090 33091 reset_progress(); 33092 33093 $errors = $('<div class="info errors"></div>'); 33094 $errors.append('<p>Sorry, something went wrong submitting this form. Please try again.</p>'); 33095 $(this).prepend($errors); 33096 $('html, body').animate({ scrollTop: $errors.offset().top - 20 }, 300); 33097 33098 }); 33099 33100} 33101 33102function reset_progress() { 33103 33104 $('div.progress').hide(); 33105 $('input[type="submit"]').attr('disabled', false); 33106 $('input[type="submit"]').css('opacity', '1'); 33107 33108} 33109 33110function start_delete() { 33111 33112 if ($('div.admin.delete form').length > 0) { 33113 var $form = $('div.admin.delete form'); 33114 } else if ($('div.admin.delete_all form').length > 0) { 33115 var $form = $('div.admin.delete_all form'); 33116 } 33117 33118 $('input[type="submit"]', $form).attr('disabled', true); 33119 $('input[type="submit"]', $form).css('opacity', '0.5'); 33120 33121 $('input#delete_confirm').keyup(function(){ 33122 33123 if ($('input#delete_confirm').val() == 'DELETE') { 33124 $('input[type="submit"]', $form).attr('disabled', false); 33125 $('input[type="submit"]', $form).css('opacity', '1'); 33126 } else { 33127 $('input[type="submit"]', $form).attr('disabled', true); 33128 $('input[type="submit"]', $form).css('opacity', '0.5'); 33129 } 33130 33131 }); 33132 33133} 33134 33135function scroll_target($target, $offset=0) { 33136 33137 $('html, body').animate({ 33138 scrollTop: $target.offset().top-$offset 33139 }, 500); 33140 33141} 33142 33143function start_flash_scroll() { 33144 33145 var $flash = $('#flash-message'); 33146 33147 if ($flash.length === 0 || $flash.children().length === 0) { return; } 33148 if (window.location.hash && window.location.hash.length > 1) { return; } 33149 33150 var flashTop = $flash.offset().top; 33151 var flashBottom = flashTop + $flash.outerHeight(); 33152 var viewportTop = $(window).scrollTop(); 33153 var viewportBottom = viewportTop + $(window).height(); 33154 33155 if (flashTop < viewportTop || flashBottom > viewportBottom) { 33156 scroll_target($flash, 100); 33157 } 33158 33159} 33160 33161function getParameterByName(name, url) { 33162 if (!url) { 33163 url = window.location.href; 33164 } 33165 name = name.replace(/[\[\]]/g, "\\$&"); 33166 var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"), 33167 results = regex.exec(url); 33168 if (!results) return null; 33169 if (!results[2]) return ''; 33170 return decodeURIComponent(results[2].replace(/\+/g, " ")); 33171} 33172 33173function start_mobile() { 33174 33175 /* Scrollable navbar */ 33176 menu_width = -5; 33177 $('div#primary ul.menu li:not(.highlight)').each(function(){ 33178 menu_width += $(this).width()+5; 33179 }); 33180 reset_mobile_navbar(menu_width); 33181 $(window).resize(function(){ 33182 reset_mobile_navbar(menu_width); 33183 }); 33184
33185 /* Scrollable tables */ 33186 $('div#content table:not(.admin):not(.noscroll)').each(function(){ 33187 $(this).wrap('<div class="overflow"></div>'); 33188 }); 33189 33190} 33191 33192function reset_mobile_navbar(menu_width) { 33193 33194 if ($('div#primary').width() < menu_width) { 33195 $('div#primary').addClass('scroll'); 33196 reset_mobile_navbar_scroll(); 33197 $('div#primary ul.menu').scroll(function(){ 33198 reset_mobile_navbar_scroll(); 33199 }); 33200 } else { 33201 $('div#primary').removeClass('scroll'); 33202 $('div#primary').removeClass('scroll-left'); 33203 $('div#primary').removeClass('scroll-right'); 33204 } 33205 33206} 33207 33208function reset_mobile_navbar_scroll() { 33209 33210 if ($('div#primary ul.menu li:first').position().left < 0) { 33211 $('div#primary').addClass('scroll-left'); 33212 } else { 33213 $('div#primary').removeClass('scroll-left'); 33214 } 33215 if (($('div#primary ul.menu').width() - Math.floor($('div#primary ul.menu li:not(.highlight):last').position().left) - $('div#primary ul.menu li:not(.highlight):last').width() - 5) < 0) { 33216 $('div#primary').addClass('scroll-right'); 33217 } else { 33218 $('div#primary').removeClass('scroll-right'); 33219 } 33220 33221} 33222 33223function start_contextual() { 33224 33225 if ($('div#contextual').length > 0) { 33226 reset_contextual(); 33227 $(window).resize(function(){ 33228 reset_contextual(); 33229 }); 33230 $(window).scroll(function(){ 33231 reset_contextual(); 33232 }); 33233 } 33234 33235} 33236 33237function reset_contextual() { 33238 33239 $('div#contextual').css('min-height', ($('div#contextual ul').height()+2)+'px'); 33240 $('div#contextual ul').css('max-width', ($('div#contextual').width()-8)); 33241 if ($('div#contextual')[0].getBoundingClientRect().top < 10) { 33242 $('div#contextual').addClass('fixed'); 33243 } else { 33244 $('div#contextual').removeClass('fixed'); 33245 } 33246 33247} 33248 33249function reset_export_links() { 33250 33251 $('a.export').each(function(){ 33252 href = $(this).attr('href').split('?')[0]; 33253 $(this).attr('href', href+window.location.search); 33254 }); 33255 33256} 33257 33258function start_tabs() { 33259 33260 $('ul.tabs').each(function(){ 33261 if (window.location.hash) { 33262 $('a[href="'+window.location.hash+'"]').addClass('active'); 33263 } 33264 if ($('li a.active', $(this)).length == 0) { 33265 $anchor = $('li:first-child a', $(this)).addClass('active'); 33266 } 33267 $anchor = $('li a.active:first', $(this)); 33268 set_tab_for($anchor); 33269 $('li a', $tabs).each(function(){ 33270 $(this).click(function(e){ 33271 set_tab_for($(this)); 33272 e.preventDefault(); 33273 }); 33274 }); 33275 }); 33276 33277 $('div.radio.tabs div.radios').each(function(){ 33278 if ($('div.option input[type="radio"]:checked', $(this)).length == 0) { 33279 $('div.option:first-child input[type="radio"]', $(this)).prop('checked', true); 33280 } 33281 $('div.option input[type="radio"]', $(this)).each(function(){ 33282 if ($(this).prop('checked')) { 33283 $('div#'+$(this).attr('id')).show(); 33284 } else { 33285 $('div#'+$(this).attr('id')).hide(); 33286 } 33287 }); 33288 $('div.option input[type="radio"]', $(this)).change(function(e){ 33289 $('div.option input[type="radio"]', $(this).parents('div.radios')).each(function(){ 33290 if ($(this).prop('checked')) { 33291 $('div#'+$(this).attr('id')).show(); 33292 } else { 33293 $('div#'+$(this).attr('id')).hide(); 33294 } 33295 }); 33296 }); 33297 }); 33298 33299} 33300 33301function set_tab_for($anchor) { 33302 33303 $tabs = $anchor.parents('ul.tabs'); 33304 $('li a', $tabs).removeClass('active'); 33305 $anchor.addClass('active'); 33306 $('li a', $tabs).each(function(){ 33307 $('div'+$(this).attr('href')).hide(); 33308 if ($(this).hasClass('active')) { 33309 $('div'+$(this).attr('href')).show(); 33310 } 33311 }); 33312 33313} 33314 33315function start_reveal($checkbox) { 33316 33317 $checkbox.change(function(){ 33318 refresh_reveal($(this)); 33319 }); 33320 refresh_reveal($checkbox); 33321 33322} 33323 33324function refresh_reveal($checkbox) { 33325 33326 if ($checkbox.prop('checked')) { 33327 $('div.content', $checkbox.parents('div.reveal')).show(); 33328 } else { 33329 $('div.content', $checkbox.parents('div.reveal')).hide(); 33330 } 33331 33332} 33333 33334function start_section_toggle() { 33335 33336 $('section div.label').each(function(){
33337 $('ul.options', $(this)).hide(); 33338 $('h2.toggle', $(this)).click(function(e){ 33339 $('ul.options', $(this).parents('div.label')).toggle(); 33340 e.preventDefault(); 33341 }); 33342 }); 33343 33344 $(document).click (function (e) { 33345 if ($(e.target).parents('div.label').length < 1) { 33346 $('div.label ul.options').hide(); 33347 } 33348 }); 33349 33350} 33351 33352function start_options() { 33353 33354 $('ul.options').each(function(){ 33355 if (window.location.hash) { 33356 $('a[href="'+window.location.hash+'"]').addClass('active'); 33357 } 33358 if ($('li a.active', $(this)).length == 0) { 33359 $anchor = $('li:first-child a', $(this)).addClass('active'); 33360 } 33361 $anchor = $('li a.active:first', $(this)); 33362 $('h2.toggle', $anchor.parents('div.label')).text($anchor.text()); 33363 set_option_for($anchor); 33364 $('li a', $options).each(function(){ 33365 $(this).click(function(e){ 33366 set_option_for($(this)); 33367 $('div.label ul.options').hide(); 33368 $('h2.toggle', $(this).parents('div.label')).text($(this).text()); 33369 e.preventDefault(); 33370 }); 33371 }); 33372 }); 33373 33374} 33375 33376function set_option_for($anchor) { 33377 33378 $options = $anchor.parents('ul.options'); 33379 $('li a', $options).removeClass('active'); 33380 $anchor.addClass('active'); 33381 $('li a', $options).each(function(){ 33382 $('div'+$(this).attr('href')).hide(); 33383 if ($(this).hasClass('active')) { 33384 $('div'+$(this).attr('href')).show(); 33385 } 33386 }); 33387 33388} 33389 33390function start_reveal_select($select) { 33391 33392 $select.change(function(){ 33393 refresh_reveal_select($(this)); 33394 }); 33395 refresh_reveal_select($select); 33396 33397} 33398 33399function refresh_reveal_select($select) { 33400 33401 $('option', $select).each(function(){ 33402 $('#'+$(this).attr('class')).hide(); 33403 }); 33404 $('#'+$('option:selected', $select).attr('class')).show(); 33405 33406} 33407 33408function start_toggle(menu) { 33409 33410 $('.toggle', menu).click(function(e){ 33411 $('li.parent', menu).not($(this).parents('li.parent')).removeClass('expanded'); 33412 $(this).parents('li.parent').toggleClass('expanded'); 33413 e.preventDefault(); 33414 }); 33415 33416 $('li.parent ul li a').click(function(e){ 33417 $(this).parents('li.parent').removeClass('expanded'); 33418 }); 33419 33420 $(document).click (function (e) { 33421 if ($(e.target).parents(menu).length < 1) { 33422 $('li.parent', menu).removeClass('expanded'); 33423 } 33424 }); 33425 33426} 33427 33428function start_accordion(accordion) { 33429 33430 $('.toggle', accordion).click(function(e){ 33431 $(this).parents('div.panel').toggleClass('expanded'); 33432 e.preventDefault(); 33433 }); 33434 33435} 33436 33437function start_date_notice($input) { 33438 33439 console.log('Start date notice'); 33440 $input.change(function(){ 33441 refresh_date_notice($input); 33442 }); 33443 refresh_date_notice($input); 33444 33445} 33446 33447function refresh_date_notice($input) { 33448 33449 if ($input.val() != '') { 33450 $date = new Date($input.val()); 33451 $now = new Date(); 33452 $now.setHours(0,0,0,0); 33453 if ($date < $now) { 33454 $('div.notice', $input.parents('div.field')).show(); 33455 } else { 33456 $('div.notice', $input.parents('div.field')).hide(); 33457 } 33458 } else { 33459 $('div.notice', $input.parents('div.field')).hide(); 33460 } 33461 33462} 33463 33464function start_trial() { 33465 33466 var $trial = getParameterByName('trial'); 33467 if ($trial) { 33468 $modal = ''; 33469 $modal += '<div class="large" role="dialog" aria-labelledby="Welcome to your membership website">'; 33470 $modal += '<button class="close mdi mdi-close" aria-label="Close" />'; 33471 $modal += '<div class="textcenter xxxlarge grey mdi mdi-check-circle"></div>'; 33472 $modal += '<h1 class="textcenter">Welcome to your<br />membership website</h1>'; 33473 $modal += '<hr />'; 33474 $modal += '<p class="textcenter">Use the toolbar at the top of the screen<br />to explore the software.</p>'; 33475 $modal += '<p class="textcenter"><a href="/users/checklist" class="button">Get started</a></p>'; 33476 $modal += '</div>'; 33477 start_modal($modal); 33478 } 33479 33480} 33481 33482$(document).bind('ready', function() { 33483 33484 console.log('Start ready scripts.'); 33485 33486 start_mobile(); 33487 start_contextual(); 33488 start_forms(); 33489 start_tabs(); 33490 start_options(); 33491 start_trial(); 33492 reset_export_links(); 33493 show_cookie_notice(); 33494 start_show_password(); 33495 start_form_ajax_errors(); 33496 start_flash_scroll(); 33497 33498});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.