Elementor Essential Addons - Version 2.3.1

Version Description

  • Facebook Feed element added
  • Twitter Feed element added
  • Few minor bug fixed and improvements
Download this release

Release Info

Developer re_enter_rupok
Plugin Icon 128x128 Elementor Essential Addons
Version 2.3.1
Comparing to
See all releases

Code changes from version 2.3.0 to 2.3.1

admin/assets/css/admin.css CHANGED
@@ -251,19 +251,20 @@ textarea.eael-form-control {
251
  color: #fff;
252
  }
253
 
 
254
  .eael-btn.eael-license-btn {
255
  background-color: #0dc9c3;
256
  }
257
  .eael-btn.eael-license-btn:hover, .eael-btn.eael-license-btn:focus {
258
  background-color: #08d1ca;
259
  }
260
- .eael-btn.eael-demo-btn, .eael-btn.eael-license-btn {
261
- padding: 20px;
262
  display: block;
263
  max-width: 250px;
264
- margin-bottom: 20px;
265
  text-align: center;
266
- font-size: 15px;
267
  }
268
 
269
  .premium-elements-title {
@@ -345,4 +346,4 @@ textarea.eael-form-control {
345
  .eael-save-btn-wrap .eael-btn.save-now:hover,
346
  .eael-header-bar .eael-btn.save-now:hover {
347
  background: #ff5544;
348
- }
251
  color: #fff;
252
  }
253
 
254
+
255
  .eael-btn.eael-license-btn {
256
  background-color: #0dc9c3;
257
  }
258
  .eael-btn.eael-license-btn:hover, .eael-btn.eael-license-btn:focus {
259
  background-color: #08d1ca;
260
  }
261
+ .eael-btn.eael-demo-btn, .eael-btn.eael-license-btn, .eael-btn.eael-review-btn {
262
+ padding: 10px;
263
  display: block;
264
  max-width: 250px;
265
+ margin-bottom: 15px;
266
  text-align: center;
267
+ font-size: 13px;
268
  }
269
 
270
  .premium-elements-title {
346
  .eael-save-btn-wrap .eael-btn.save-now:hover,
347
  .eael-header-bar .eael-btn.save-now:hover {
348
  background: #ff5544;
349
+ }
admin/assets/js/admin.js CHANGED
@@ -8,7 +8,7 @@
8
  title: '<h2><span>Go</span> Premium',
9
  type: 'warning',
10
  html:
11
- 'Purchase our <b><a href="https://essential-addons.com/elementor/buy.php" rel="nofollow">premium version</a></b> to unlock these pro components!',
12
  showCloseButton: true,
13
  showCancelButton: false,
14
  focusConfirm: true,
8
  title: '<h2><span>Go</span> Premium',
9
  type: 'warning',
10
  html:
11
+ 'Purchase our <b><a href="https://wpdeveloper.net/in/upgrade-essential-addons-elementor" rel="nofollow">premium version</a></b> to unlock these pro components!',
12
  showCloseButton: true,
13
  showCancelButton: false,
14
  focusConfirm: true,
admin/settings.php CHANGED
@@ -14,7 +14,7 @@ class Eael_Admin_Settings {
14
  * @var array
15
  * @since 2.3.0
16
  */
17
- public $eael_default_keys = [ 'contact-form-7', 'count-down', 'creative-btn', 'fancy-text', 'img-comparison', 'instagram-gallery', 'interactive-promo', 'lightbox', 'post-block', 'post-grid', 'post-timeline', 'product-grid', 'team-members', 'testimonial-slider', 'testimonials', 'testimonials', 'weforms', 'static-product', 'call-to-action', 'flip-box', 'info-box', 'dual-header', 'price-table', 'flip-carousel', 'interactive-cards', 'ninja-form', 'gravity-form', 'caldera-form', 'wisdom_registered_setting' ];
18
 
19
  /**
20
  * Will Contain All Components Default Values
@@ -144,6 +144,7 @@ class Eael_Admin_Settings {
144
  </div>
145
  <div class="col-half">
146
  <a href="https://essential-addons.com/elementor/" target="_blank" class="button eael-btn eael-demo-btn">Explore Demos</a>
 
147
  <a href="https://wpdeveloper.net/in/upgrade-essential-addons-elementor" target="_blank" class="button eael-btn eael-license-btn">Get Pro License</a>
148
 
149
  <div class="eael-notice">
@@ -307,6 +308,22 @@ class Eael_Admin_Settings {
307
  <p class="desc"><?php _e( 'Activate / Deactivate Caldera Form', 'essential-addons-elementor' ); ?></p>
308
  <input type="checkbox" id="caldera-form" name="caldera-form" <?php checked( 1, $this->eael_get_settings['caldera-form'], true ); ?> >
309
  <label for="caldera-form"></label>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
310
  </div>
311
  </td>
312
  </tr>
@@ -455,6 +472,30 @@ class Eael_Admin_Settings {
455
  <label for="data-table" class="<?php if( (bool) $this->is_pro === false ) : echo 'eael-get-pro'; endif; ?>"></label>
456
  </div>
457
  </td>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
458
  </tr>
459
  </table>
460
  <div class="eael-save-btn-wrap">
@@ -539,6 +580,8 @@ class Eael_Admin_Settings {
539
  'ninja-form' => intval( $settings['ninja-form'] ? 1 : 0 ),
540
  'gravity-form' => intval( $settings['gravity-form'] ? 1 : 0 ),
541
  'caldera-form' => intval( $settings['gravity-form'] ? 1 : 0 ),
 
 
542
  'wisdom_registered_setting' => 1,
543
  );
544
  update_option( 'eael_save_settings', $this->eael_settings );
14
  * @var array
15
  * @since 2.3.0
16
  */
17
+ public $eael_default_keys = [ 'contact-form-7', 'count-down', 'creative-btn', 'fancy-text', 'img-comparison', 'instagram-gallery', 'interactive-promo', 'lightbox', 'post-block', 'post-grid', 'post-timeline', 'product-grid', 'team-members', 'testimonial-slider', 'testimonials', 'testimonials', 'weforms', 'static-product', 'call-to-action', 'flip-box', 'info-box', 'dual-header', 'price-table', 'flip-carousel', 'interactive-cards', 'ninja-form', 'gravity-form', 'caldera-form', 'wisdom_registered_setting', 'twitter-feed', 'facebook-feed', 'twitter-feed-carousel', 'facebook-feed-carousel' ];
18
 
19
  /**
20
  * Will Contain All Components Default Values
144
  </div>
145
  <div class="col-half">
146
  <a href="https://essential-addons.com/elementor/" target="_blank" class="button eael-btn eael-demo-btn">Explore Demos</a>
147
+ <a href="https://wpdeveloper.net/review-essential-addons-elementor" target="_blank" class="button eael-btn eael-review-btn">Leave a review</a>
148
  <a href="https://wpdeveloper.net/in/upgrade-essential-addons-elementor" target="_blank" class="button eael-btn eael-license-btn">Get Pro License</a>
149
 
150
  <div class="eael-notice">
308
  <p class="desc"><?php _e( 'Activate / Deactivate Caldera Form', 'essential-addons-elementor' ); ?></p>
309
  <input type="checkbox" id="caldera-form" name="caldera-form" <?php checked( 1, $this->eael_get_settings['caldera-form'], true ); ?> >
310
  <label for="caldera-form"></label>
311
+ </div>
312
+ </td>
313
+ <td>
314
+ <div class="eael-checkbox">
315
+ <p class="title"><?php _e( 'Twitter Feed', 'essential-addons-elementor' ) ?></p>
316
+ <p class="desc"><?php _e( 'Activate / Deactivate Twitter Feed', 'essential-addons-elementor' ); ?></p>
317
+ <input type="checkbox" id="twitter-feed" name="twitter-feed" <?php checked( 1, $this->eael_get_settings['twitter-feed'], true ); ?> >
318
+ <label for="twitter-feed"></label>
319
+ </div>
320
+ </td>
321
+ <td>
322
+ <div class="eael-checkbox">
323
+ <p class="title"><?php _e( 'Facebook Feed', 'essential-addons-elementor' ) ?></p>
324
+ <p class="desc"><?php _e( 'Activate / Deactivate Facebook Feed', 'essential-addons-elementor' ); ?></p>
325
+ <input type="checkbox" id="facebook-feed" name="facebook-feed" <?php checked( 1, $this->eael_get_settings['facebook-feed'], true ); ?> >
326
+ <label for="facebook-feed"></label>
327
  </div>
328
  </td>
329
  </tr>
472
  <label for="data-table" class="<?php if( (bool) $this->is_pro === false ) : echo 'eael-get-pro'; endif; ?>"></label>
473
  </div>
474
  </td>
475
+ <td>
476
+ <div class="eael-checkbox">
477
+ <p class="title">
478
+ <?php _e( 'Twitter Feed Carousel', 'essential-addons-elementor' ) ?>
479
+ </p>
480
+ <p class="desc">
481
+ <?php _e( 'Activate / Deactivate Twitter Feed Carousel', 'essential-addons-elementor' ); ?>
482
+ </p>
483
+ <input type="checkbox" id="twitter-feed-carousel" name="twitter-feed-carousel" disabled>
484
+ <label for="twitter-feed-carousel" class="<?php if( (bool) $this->is_pro === false ) : echo 'eael-get-pro'; endif; ?>"></label>
485
+ </div>
486
+ </td>
487
+ <td>
488
+ <div class="eael-checkbox">
489
+ <p class="title">
490
+ <?php _e( 'Facebook Feed Carousel', 'essential-addons-elementor' ) ?>
491
+ </p>
492
+ <p class="desc">
493
+ <?php _e( 'Activate / Deactivate Facebook Feed Carousel', 'essential-addons-elementor' ); ?>
494
+ </p>
495
+ <input type="checkbox" id="facebook-feed-carousel" name="facebook-feed-carousel" disabled>
496
+ <label for="facebook-feed-carousel" class="<?php if( (bool) $this->is_pro === false ) : echo 'eael-get-pro'; endif; ?>"></label>
497
+ </div>
498
+ </td>
499
  </tr>
500
  </table>
501
  <div class="eael-save-btn-wrap">
580
  'ninja-form' => intval( $settings['ninja-form'] ? 1 : 0 ),
581
  'gravity-form' => intval( $settings['gravity-form'] ? 1 : 0 ),
582
  'caldera-form' => intval( $settings['gravity-form'] ? 1 : 0 ),
583
+ 'twitter-feed' => intval( $settings['twitter-feed'] ? 1 : 0 ),
584
+ 'facebook-feed' => intval( $settings['facebook-feed'] ? 1 : 0 ),
585
  'wisdom_registered_setting' => 1,
586
  );
587
  update_option( 'eael_save_settings', $this->eael_settings );
assets/css/essential-addons-elementor.css CHANGED
@@ -2826,3 +2826,280 @@ h2.eael-elements-flip-box-heading {
2826
  .eael-caldera-form-btn-align-center {
2827
  text-align: center;
2828
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2826
  .eael-caldera-form-btn-align-center {
2827
  text-align: center;
2828
  }
2829
+
2830
+ /**
2831
+ * Social Feeds
2832
+ */
2833
+ /* Twitter Feed Styles */
2834
+ .eael-social-feed-container {}
2835
+ .eael-social-feed-element.hidden {
2836
+ background-color:red !important;
2837
+ }
2838
+
2839
+ .eael-facebook-feed-wrapper::before, .eael-facebook-feed-wrapper::after,
2840
+ .eael-facebook-feed-container::before, .eael-facebook-feed-container::after,
2841
+ .eael-twitter-feed-wrapper::before, .eael-twitter-feed-wrapper::after,
2842
+ .eael-twitter-feed-container::before, .eael-twitter-feed-container::after {
2843
+ content: "";
2844
+ clear: both;
2845
+ }
2846
+ .eael-facebook-feed-container:not(.masonry-view), .eael-twitter-feed-container:not(.masonry-view) {
2847
+ height: auto!important;
2848
+ }
2849
+
2850
+ .eael-social-feed-element .pull-left {
2851
+ float:left;
2852
+ margin-right: 10px;
2853
+ }
2854
+ .eael-social-feed-element .pull-right {
2855
+ margin-left: 10px;
2856
+ }
2857
+ .eael-social-feed-element img {
2858
+ width: 100%;
2859
+ width: auto;
2860
+ height: auto;
2861
+ border: 0;
2862
+ vertical-align: middle;
2863
+ -ms-interpolation-mode: bicubic;
2864
+ }
2865
+ .eael-social-feed-element .attachment {
2866
+ vertical-align: middle;
2867
+ -ms-interpolation-mode: bicubic;
2868
+ }
2869
+
2870
+ /* Link styles */
2871
+ .eael-social-feed-element a {
2872
+ color: #0088cc;
2873
+ text-decoration: none;
2874
+ }
2875
+ .eael-social-feed-element a:focus {
2876
+ outline: thin dotted #333;
2877
+ outline: 5px auto -webkit-focus-ring-color;
2878
+ outline-offset: -2px;
2879
+ }
2880
+ .eael-social-feed-element a:hover,
2881
+ .eael-social-feed-element a:active {
2882
+ outline: 0;
2883
+ color: #005580;
2884
+ text-decoration: underline;
2885
+ }
2886
+
2887
+ /* Text styles */
2888
+ .eael-social-feed-element small {
2889
+ font-size: 85%;
2890
+ }
2891
+ .eael-social-feed-element strong {
2892
+ font-weight: bold;
2893
+ }
2894
+ .eael-social-feed-element em {
2895
+ font-style: italic;
2896
+ }
2897
+ .eael-social-feed-element p {
2898
+ margin: 0 0 10px;
2899
+ }
2900
+ .eael-social-feed-element .media-body > p{
2901
+ margin-bottom:4px;
2902
+ min-height:20px;
2903
+ }
2904
+ .eael-social-feed-element p.social-feed-text {
2905
+ margin: 0;
2906
+ overflow: hidden;
2907
+ text-overflow: ellipsis;
2908
+ -webkit-line-clamp: 5;
2909
+ -webkit-box-orient: vertical;
2910
+ }
2911
+
2912
+ /* Message styles */
2913
+ .eael-social-feed-element,
2914
+ .eael-social-feed-element .media-body {
2915
+ overflow: hidden;
2916
+ zoom: 1;
2917
+ *overflow: visible;
2918
+ }
2919
+ .eael-social-feed-element {
2920
+ padding: 10px;
2921
+ background: none;
2922
+ }
2923
+ .eael-social-feed-element .media-body .social-network-icon{
2924
+ margin-top: -3px;
2925
+ margin-right:5px;
2926
+ width:16px;
2927
+ }
2928
+ .eael-social-feed-element .media-body div{
2929
+ color:#666;
2930
+ line-height: 20px;
2931
+ clear: both;
2932
+ }
2933
+ .eael-social-feed-element:first-child {
2934
+ margin-top: 0;
2935
+ }
2936
+ .eael-social-feed-element .media-object {
2937
+ display: block;
2938
+ width:48px;
2939
+ border-radius:50%;
2940
+ }
2941
+ .eael-social-feed-element .media-heading {
2942
+ margin: 0 0 5px;
2943
+ }
2944
+ .eael-social-feed-element .media-list {
2945
+ margin-left: 0;
2946
+ list-style: none;
2947
+ }
2948
+
2949
+ .eael-social-feed-element .muted {
2950
+ color: #999;
2951
+ }
2952
+ .eael-social-feed-element a.muted:hover,
2953
+ .eael-social-feed-element a.muted:focus {
2954
+ color: #808080;
2955
+ }
2956
+
2957
+ .eael-social-feed-element {
2958
+ transition: 0.25s;
2959
+ -webkit-backface-visibility: hidden;
2960
+ margin:-1px;
2961
+ margin-top:25px;
2962
+ color: #333;
2963
+ text-align:left;
2964
+ font-size: 14px;
2965
+ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
2966
+ line-height: 16px;
2967
+ }
2968
+ .eael-social-feed-element .eael-content {
2969
+ padding: 20px 15px 15px;
2970
+ transition: .4s;
2971
+ background: #fff;
2972
+ }
2973
+ .eael-social-feed-element:hover .eael-content {
2974
+ box-shadow: 0 0 10px 0 rgba(10, 10, 10, 0.2);
2975
+ }
2976
+ .eael-social-feed-element .social-network-icon {
2977
+ opacity:0.7;
2978
+ }
2979
+ .eael-social-feed-element .author-title {
2980
+ color: #444;
2981
+ line-height: 1.5em;
2982
+ font-weight: 500;
2983
+ }
2984
+ /* Icon Color */
2985
+ .media-body .fa-twitter{
2986
+ color: #1da1f2;
2987
+ margin-right: 8px;
2988
+ }
2989
+ .media-body .fa-facebook {
2990
+ color: #3b5998;
2991
+ margin-right: 8px;
2992
+ }
2993
+ /* Read More Link */
2994
+ .text-wrapper p .read-more-link {
2995
+ margin-top: 9px;
2996
+ display: block;
2997
+ }
2998
+ /* Navigation Links */
2999
+ .eael-social-feed-wrapper .slick-prev, .eael-social-feed-element .slick-next {
3000
+ background: #1da1f2;
3001
+ }
3002
+ /* Loading Loader */
3003
+ .eael-social-feed-wrapper {
3004
+ width: 100%;
3005
+ height: auto;
3006
+ position: relative;
3007
+ z-index: 0;
3008
+ }
3009
+ .eael-loading-feed {
3010
+ display: none;
3011
+ position: absolute;
3012
+ width: 100%;
3013
+ height: 100%;
3014
+ top: 0px;
3015
+ left: 0px;
3016
+ bottom: 0px;
3017
+ right: 0px;
3018
+ }
3019
+ .eael-loading-feed.show-loading {
3020
+ display: block;
3021
+ /*background: #fff;*/
3022
+ text-align: center;
3023
+ z-index: 10;
3024
+ display: flex;
3025
+ align-items: center;
3026
+ justify-content: center;
3027
+ transition: .5s;
3028
+ }
3029
+ .eael-loading-feed .loader {
3030
+ border: 3px solid #f3f3f3;
3031
+ border-radius: 50%;
3032
+ border-top: 3px solid #3498db;
3033
+ width: 30px;
3034
+ height: 30px;
3035
+ -webkit-animation: spin 2s linear infinite; /* Safari */
3036
+ animation: spin 2s linear infinite;
3037
+ margin: 0 auto;
3038
+ }
3039
+ /* Safari */
3040
+ @-webkit-keyframes spin {
3041
+ 0% { -webkit-transform: rotate(0deg); }
3042
+ 100% { -webkit-transform: rotate(360deg); }
3043
+ }
3044
+
3045
+ @keyframes spin {
3046
+ 0% { transform: rotate(0deg); }
3047
+ 100% { transform: rotate(360deg); }
3048
+ }
3049
+ /*====================================================*/
3050
+
3051
+ /* List View */
3052
+ .eael-social-feed-container.list-view .eael-social-feed-element {
3053
+ margin: 15px;
3054
+ border: 1px solid rgba( 0,0,0,0.1 );
3055
+ background: none;
3056
+ }
3057
+ /* Carousel View */
3058
+ .eael-social-feed-container.carousel-view {
3059
+ width: 100%;
3060
+ height: auto;
3061
+ }
3062
+ .eael-social-feed-container.carousel-view .eael-social-feed-element.slick-slide {
3063
+ flex-basis: 30%;
3064
+ margin: 15px;
3065
+ border: 1px solid rgba( 0,0,0,0.1 );
3066
+ }
3067
+
3068
+ /* Masonry View */
3069
+ .eael-twitter-feed-container.masonry-view .eael-social-feed-element,
3070
+ .eael-facebook-feed-container.masonry-view .eael-social-feed-element {
3071
+ width: 33.33%;
3072
+ margin-top: 0px;
3073
+ float: left;
3074
+ }
3075
+ .eael-social-feed-element .eael-content {
3076
+ border: 1px solid rgba( 0,0,0,0.1 );
3077
+ }
3078
+
3079
+ /* Editor Related Style */
3080
+ .eael-social-feed-avatar-circle .eael-social-feed-element .media-object {
3081
+ border-radius: 50%;
3082
+ }
3083
+ .eael-social-feed-avatar-square .eael-social-feed-element .media-object {
3084
+ border-radius: 0%;
3085
+ }
3086
+ .eael-social-feed-masonry-col-4 .eael-social-feed-element .social-feed-date
3087
+ .eael-social-feed-masonry-col-4 .eael-social-feed-element .social-feed-date {
3088
+ text-align: left !important;
3089
+ }
3090
+
3091
+ /* Media Query */
3092
+ @media only screen and ( min-width: 768px ) and (max-width: 992px) {
3093
+
3094
+ .eael-twitter-feed-container.masonry-view .eael-social-feed-element,
3095
+ .eael-facebook-feed-container.masonry-view .eael-social-feed-element {
3096
+ width: 50% !important;
3097
+ }
3098
+ }
3099
+ @media only screen and (max-width: 480px) {
3100
+
3101
+ .eael-twitter-feed-container.masonry-view .eael-social-feed-element,
3102
+ .eael-facebook-feed-container.masonry-view .eael-social-feed-element {
3103
+ width: 100% !important;
3104
+ }
3105
+ }
assets/social-feeds/codebird.js ADDED
@@ -0,0 +1,1591 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "use strict";
2
+
3
+ var _slicedToArray = (function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; })();
4
+
5
+ var _createClass = (function () { function 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); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
6
+
7
+ function _typeof(obj) { return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj; }
8
+
9
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
10
+
11
+ /**
12
+ * A Twitter library in JavaScript
13
+ *
14
+ * @package codebird
15
+ * @version 3.0.0-dev
16
+ * @author Jublo Solutions <support@jublo.net>
17
+ * @copyright 2010-2016 Jublo Solutions <support@jublo.net>
18
+ * @license http://opensource.org/licenses/GPL-3.0 GNU Public License 3.0
19
+ * @link https://github.com/jublonet/codebird-php
20
+ */
21
+
22
+ /* global window,
23
+ document,
24
+ navigator,
25
+ Ti,
26
+ ActiveXObject,
27
+ module,
28
+ define,
29
+ require */
30
+
31
+ (function () {
32
+ /**
33
+ * A Twitter library in JavaScript
34
+ *
35
+ * @package codebird
36
+ * @subpackage codebird-js
37
+ */
38
+
39
+ var Codebird = (function () {
40
+ function Codebird() {
41
+ _classCallCheck(this, Codebird);
42
+
43
+ /**
44
+ * The OAuth consumer key of your registered app
45
+ */
46
+ this._oauth_consumer_key = null;
47
+
48
+ /**
49
+ * The corresponding consumer secret
50
+ */
51
+ this._oauth_consumer_secret = null;
52
+
53
+ /**
54
+ * The app-only bearer token. Used to authorize app-only requests
55
+ */
56
+ this._oauth_bearer_token = null;
57
+
58
+ /**
59
+ * The API endpoint base to use
60
+ */
61
+ this._endpoint_base = "https://api.twitter.com/";
62
+
63
+ /**
64
+ * The media API endpoint base to use
65
+ */
66
+ this._endpoint_base_media = "https://upload.twitter.com/";
67
+
68
+ /**
69
+ * The API endpoint to use
70
+ */
71
+ this._endpoint = this._endpoint_base + "1.1/";
72
+
73
+ /**
74
+ * The media API endpoint to use
75
+ */
76
+ this._endpoint_media = this._endpoint_base_media + "1.1/";
77
+
78
+ /**
79
+ * The publish API endpoint to use
80
+ */
81
+ this._endpoint_publish = "https://publish.twitter.com/";
82
+
83
+ /**
84
+ * The API endpoint base to use
85
+ */
86
+ this._endpoint_oauth = this._endpoint_base;
87
+
88
+ /**
89
+ * API proxy endpoint
90
+ */
91
+ this._endpoint_proxy = "https://api.jublo.net/codebird/";
92
+
93
+ /**
94
+ * Whether to access the API via a proxy that is allowed by CORS
95
+ * Assume that CORS is only necessary in browsers
96
+ */
97
+ this._use_proxy = typeof navigator !== "undefined" && typeof navigator.userAgent !== "undefined";
98
+
99
+ /**
100
+ * The Request or access token. Used to sign requests
101
+ */
102
+ this._oauth_token = null;
103
+
104
+ /**
105
+ * The corresponding request or access token secret
106
+ */
107
+ this._oauth_token_secret = null;
108
+
109
+ /**
110
+ * The current Codebird version
111
+ */
112
+ this._version = "3.0.0-dev";
113
+
114
+ this.b64_alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
115
+ }
116
+
117
+ /**
118
+ * Sets the OAuth consumer key and secret (App key)
119
+ *
120
+ * @param string key OAuth consumer key
121
+ * @param string secret OAuth consumer secret
122
+ *
123
+ * @return void
124
+ */
125
+
126
+ _createClass(Codebird, [{
127
+ key: "setConsumerKey",
128
+ value: function setConsumerKey(key, secret) {
129
+ this._oauth_consumer_key = key;
130
+ this._oauth_consumer_secret = secret;
131
+ }
132
+
133
+ /**
134
+ * Sets the OAuth2 app-only auth bearer token
135
+ *
136
+ * @param string token OAuth2 bearer token
137
+ *
138
+ * @return void
139
+ */
140
+
141
+ }, {
142
+ key: "setBearerToken",
143
+ value: function setBearerToken(token) {
144
+ this._oauth_bearer_token = token;
145
+ }
146
+
147
+ /**
148
+ * Gets the current Codebird version
149
+ *
150
+ * @return string The version number
151
+ */
152
+
153
+ }, {
154
+ key: "getVersion",
155
+ value: function getVersion() {
156
+ return this._version;
157
+ }
158
+
159
+ /**
160
+ * Sets the OAuth request or access token and secret (User key)
161
+ *
162
+ * @param string token OAuth request or access token
163
+ * @param string secret OAuth request or access token secret
164
+ *
165
+ * @return void
166
+ */
167
+
168
+ }, {
169
+ key: "setToken",
170
+ value: function setToken(token, secret) {
171
+ this._oauth_token = token;
172
+ this._oauth_token_secret = secret;
173
+ }
174
+
175
+ /**
176
+ * Forgets the OAuth request or access token and secret (User key)
177
+ *
178
+ * @return bool
179
+ */
180
+
181
+ }, {
182
+ key: "logout",
183
+ value: function logout() {
184
+ this._oauth_token = this._oauth_token_secret = null;
185
+
186
+ return true;
187
+ }
188
+
189
+ /**
190
+ * Enables or disables CORS proxy
191
+ *
192
+ * @param bool use_proxy Whether to use CORS proxy or not
193
+ *
194
+ * @return void
195
+ */
196
+
197
+ }, {
198
+ key: "setUseProxy",
199
+ value: function setUseProxy(use_proxy) {
200
+ this._use_proxy = !!use_proxy;
201
+ }
202
+
203
+ /**
204
+ * Sets custom CORS proxy server
205
+ *
206
+ * @param string proxy Address of proxy server to use
207
+ *
208
+ * @return void
209
+ */
210
+
211
+ }, {
212
+ key: "setProxy",
213
+ value: function setProxy(proxy) {
214
+ // add trailing slash if missing
215
+ if (!proxy.match(/\/$/)) {
216
+ proxy += "/";
217
+ }
218
+ this._endpoint_proxy = proxy;
219
+ }
220
+
221
+ /**
222
+ * Signing helpers
223
+ */
224
+
225
+ /**
226
+ * URL-encodes the given data
227
+ *
228
+ * @param mixed data
229
+ *
230
+ * @return mixed The encoded data
231
+ */
232
+
233
+ }, {
234
+ key: "_url",
235
+ value: function _url(data) {
236
+ if (/boolean|number|string/.test(typeof data === "undefined" ? "undefined" : _typeof(data))) {
237
+ return encodeURIComponent(data).replace(/!/g, "%21").replace(/'/g, "%27").replace(/\(/g, "%28").replace(/\)/g, "%29").replace(/\*/g, "%2A");
238
+ } else {
239
+ return "";
240
+ }
241
+ }
242
+
243
+ /**
244
+ * Gets the base64-encoded SHA1 hash for the given data
245
+ *
246
+ * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined
247
+ * in FIPS PUB 180-1
248
+ * Based on version 2.1 Copyright Paul Johnston 2000 - 2002.
249
+ * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
250
+ * Distributed under the BSD License
251
+ * See http://pajhome.org.uk/crypt/md5 for details.
252
+ *
253
+ * @param string data The data to calculate the hash from
254
+ *
255
+ * @return string The hash
256
+ */
257
+
258
+ }, {
259
+ key: "_sha1",
260
+ value: function _sha1(e) {
261
+ function n(e, b) {
262
+ e[b >> 5] |= 128 << 24 - b % 32;
263
+ e[(b + 64 >> 9 << 4) + 15] = b;
264
+ for (var c = new Array(80), a = 1732584193, d = -271733879, h = -1732584194, k = 271733878, g = -1009589776, p = 0; p < e.length; p += 16) {
265
+ for (var o = a, q = d, r = h, s = k, t = g, f = 0; 80 > f; f++) {
266
+ var m = undefined;
267
+
268
+ if (f < 16) {
269
+ m = e[p + f];
270
+ } else {
271
+ m = c[f - 3] ^ c[f - 8] ^ c[f - 14] ^ c[f - 16];
272
+ m = m << 1 | m >>> 31;
273
+ }
274
+
275
+ c[f] = m;
276
+ m = l(l(a << 5 | a >>> 27, 20 > f ? d & h | ~d & k : 40 > f ? d ^ h ^ k : 60 > f ? d & h | d & k | h & k : d ^ h ^ k), l(l(g, c[f]), 20 > f ? 1518500249 : 40 > f ? 1859775393 : 60 > f ? -1894007588 : -899497514));
277
+ g = k;
278
+ k = h;
279
+ h = d << 30 | d >>> 2;
280
+ d = a;
281
+ a = m;
282
+ }
283
+ a = l(a, o);
284
+ d = l(d, q);
285
+ h = l(h, r);
286
+ k = l(k, s);
287
+ g = l(g, t);
288
+ }
289
+ return [a, d, h, k, g];
290
+ }
291
+
292
+ function l(e, b) {
293
+ var c = (e & 65535) + (b & 65535);
294
+ return (e >> 16) + (b >> 16) + (c >> 16) << 16 | c & 65535;
295
+ }
296
+
297
+ function q(e) {
298
+ for (var b = [], c = (1 << g) - 1, a = 0; a < e.length * g; a += g) {
299
+ b[a >> 5] |= (e.charCodeAt(a / g) & c) << 24 - a % 32;
300
+ }
301
+ return b;
302
+ }
303
+ var g = 8;
304
+
305
+ var b = this._oauth_consumer_secret + "&" + (null !== this._oauth_token_secret ? this._oauth_token_secret : "");
306
+ if (this._oauth_consumer_secret === null) {
307
+ throw "To generate a hash, the consumer secret must be set.";
308
+ }
309
+ var c = q(b);
310
+ if (c.length > 16) {
311
+ c = n(c, b.length * g);
312
+ }
313
+ var bb = new Array(16);
314
+ for (var a = new Array(16), d = 0; d < 16; d++) {
315
+ a[d] = c[d] ^ 909522486;
316
+ bb[d] = c[d] ^ 1549556828;
317
+ }
318
+ c = n(a.concat(q(e)), 512 + e.length * g);
319
+ bb = n(bb.concat(c), 672);
320
+ b = "";
321
+ for (g = 0; g < 4 * bb.length; g += 3) {
322
+ for (d = (bb[g >> 2] >> 8 * (3 - g % 4) & 255) << 16 | (bb[g + 1 >> 2] >> 8 * (3 - (g + 1) % 4) & 255) << 8 | bb[g + 2 >> 2] >> 8 * (3 - (g + 2) % 4) & 255, e = 0; 4 > e; e++) {
323
+ b = 8 * g + 6 * e > 32 * bb.length ? b + "=" : b + this.b64_alphabet.charAt(d >> 6 * (3 - e) & 63);
324
+ }
325
+ }
326
+ return b;
327
+ }
328
+
329
+ /*
330
+ * Gets the base64 representation for the given data
331
+ *
332
+ * http://phpjs.org
333
+ * + original by: Tyler Akins (http://rumkin.com)
334
+ * + improved by: Bayron Guevara
335
+ * + improved by: Thunder.m
336
+ * + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
337
+ * + bugfixed by: Pellentesque Malesuada
338
+ * + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
339
+ * + improved by: Rafał Kukawski (http://kukawski.pl)
340
+ *
341
+ * @param string data The data to calculate the base64 representation from
342
+ *
343
+ * @return string The base64 representation
344
+ */
345
+
346
+ }, {
347
+ key: "_base64_encode",
348
+ value: function _base64_encode(a) {
349
+ var d = undefined,
350
+ e = undefined,
351
+ f = undefined,
352
+ b = undefined,
353
+ g = 0,
354
+ h = 0,
355
+ i = this.b64_alphabet,
356
+ c = [];
357
+ if (!a) {
358
+ return a;
359
+ }
360
+ do {
361
+ d = a.charCodeAt(g++);
362
+ e = a.charCodeAt(g++);
363
+ f = a.charCodeAt(g++);
364
+ b = d << 16 | e << 8 | f;
365
+ d = b >> 18 & 63;
366
+ e = b >> 12 & 63;
367
+ f = b >> 6 & 63;
368
+ b &= 63;
369
+ c[h++] = i.charAt(d) + i.charAt(e) + i.charAt(f) + i.charAt(b);
370
+ } while (g < a.length);
371
+ i = c.join("");
372
+ a = a.length % 3;
373
+ return (a ? i.slice(0, a - 3) : i) + "===".slice(a || 3);
374
+ }
375
+
376
+ /*
377
+ * Builds a HTTP query string from the given data
378
+ *
379
+ * http://phpjs.org
380
+ * + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
381
+ * + improved by: Legaev Andrey
382
+ * + improved by: Michael White (http://getsprink.com)
383
+ * + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
384
+ * + improved by: Brett Zamir (http://brett-zamir.me)
385
+ * + revised by: stag019
386
+ * + input by: Dreamer
387
+ * + bugfixed by: Brett Zamir (http://brett-zamir.me)
388
+ * + bugfixed by: MIO_KODUKI (http://mio-koduki.blogspot.com/)
389
+ *
390
+ * @param string data The data to concatenate
391
+ *
392
+ * @return string The HTTP query
393
+ */
394
+
395
+ }, {
396
+ key: "_http_build_query",
397
+ value: function _http_build_query(e, f, b) {
398
+ function g(c, a, d) {
399
+ var b = undefined,
400
+ e = [];
401
+ if (a === true) {
402
+ a = "1";
403
+ } else if (a === false) {
404
+ a = "0";
405
+ }
406
+ if (null !== a) {
407
+ if ((typeof a === "undefined" ? "undefined" : _typeof(a)) === "object") {
408
+ for (b in a) {
409
+ if (a.hasOwnProperty(b) && a[b] !== null) {
410
+ e.push(g.call(this, c + "[" + b + "]", a[b], d));
411
+ }
412
+ }
413
+ return e.join(d);
414
+ }
415
+ if (typeof a !== "function") {
416
+ return this._url(c) + "=" + this._url(a);
417
+ }
418
+ throw "There was an error processing for http_build_query().";
419
+ } else {
420
+ return "";
421
+ }
422
+ }
423
+ var d,
424
+ c,
425
+ h = [];
426
+ if (!b) {
427
+ b = "&";
428
+ }
429
+ for (c in e) {
430
+ if (!e.hasOwnProperty(c)) {
431
+ continue;
432
+ }
433
+ d = e[c];
434
+ if (f && !isNaN(c)) {
435
+ c = String(f) + c;
436
+ }
437
+ d = g.call(this, c, d, b);
438
+ if (d !== "") {
439
+ h.push(d);
440
+ }
441
+ }
442
+ return h.join(b);
443
+ }
444
+
445
+ /**
446
+ * Generates a (hopefully) unique random string
447
+ *
448
+ * @param int optional length The length of the string to generate
449
+ *
450
+ * @return string The random string
451
+ */
452
+
453
+ }, {
454
+ key: "_nonce",
455
+ value: function _nonce() {
456
+ var length = arguments.length <= 0 || arguments[0] === undefined ? 8 : arguments[0];
457
+
458
+ if (length < 1) {
459
+ throw "Invalid nonce length.";
460
+ }
461
+ var nonce = "";
462
+ for (var i = 0; i < length; i++) {
463
+ var character = Math.floor(Math.random() * 61);
464
+ nonce += this.b64_alphabet.substring(character, character + 1);
465
+ }
466
+ return nonce;
467
+ }
468
+
469
+ /**
470
+ * Sort array elements by key
471
+ *
472
+ * @param array input_arr The array to sort
473
+ *
474
+ * @return array The sorted keys
475
+ */
476
+
477
+ }, {
478
+ key: "_ksort",
479
+ value: function _ksort(input_arr) {
480
+ var keys = [],
481
+ sorter = undefined,
482
+ k = undefined;
483
+
484
+ sorter = function (a, b) {
485
+ var a_float = parseFloat(a),
486
+ b_float = parseFloat(b),
487
+ a_numeric = a_float + "" === a,
488
+ b_numeric = b_float + "" === b;
489
+ if (a_numeric && b_numeric) {
490
+ return a_float > b_float ? 1 : a_float < b_float ? -1 : 0;
491
+ } else if (a_numeric && !b_numeric) {
492
+ return 1;
493
+ } else if (!a_numeric && b_numeric) {
494
+ return -1;
495
+ }
496
+ return a > b ? 1 : a < b ? -1 : 0;
497
+ };
498
+
499
+ // Make a list of key names
500
+ for (k in input_arr) {
501
+ if (input_arr.hasOwnProperty(k)) {
502
+ keys.push(k);
503
+ }
504
+ }
505
+ keys.sort(sorter);
506
+ return keys;
507
+ }
508
+
509
+ /**
510
+ * Clone objects
511
+ *
512
+ * @param object obj The object to clone
513
+ *
514
+ * @return object clone The cloned object
515
+ */
516
+
517
+ }, {
518
+ key: "_clone",
519
+ value: function _clone(obj) {
520
+ var clone = {};
521
+ for (var i in obj) {
522
+ if (_typeof(obj[i]) === "object") {
523
+ clone[i] = this._clone(obj[i]);
524
+ } else {
525
+ clone[i] = obj[i];
526
+ }
527
+ }
528
+ return clone;
529
+ }
530
+
531
+ /**
532
+ * Gets the XML HTTP Request object, trying to load it in various ways
533
+ *
534
+ * @return object The XMLHttpRequest object instance
535
+ */
536
+
537
+ }, {
538
+ key: "_getXmlRequestObject",
539
+ value: function _getXmlRequestObject() {
540
+ var xml = null;
541
+ // first, try the W3-standard object
542
+ if ((typeof window === "undefined" ? "undefined" : _typeof(window)) === "object" && window && typeof window.XMLHttpRequest !== "undefined") {
543
+ xml = new window.XMLHttpRequest();
544
+ // then, try Titanium framework object
545
+ } else if ((typeof Ti === "undefined" ? "undefined" : _typeof(Ti)) === "object" && Ti && typeof Ti.Network.createHTTPClient !== "undefined") {
546
+ xml = Ti.Network.createHTTPClient();
547
+ // are we in an old Internet Explorer?
548
+ } else if (typeof ActiveXObject !== "undefined") {
549
+ try {
550
+ xml = new ActiveXObject("Microsoft.XMLHTTP");
551
+ } catch (e) {
552
+ throw "ActiveXObject object not defined.";
553
+ }
554
+ // now, consider RequireJS and/or Node.js objects
555
+ } else if (typeof require === "function") {
556
+ var XMLHttpRequest;
557
+ // look for xmlhttprequest module
558
+ try {
559
+ XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest;
560
+ xml = new XMLHttpRequest();
561
+ } catch (e1) {
562
+ // or maybe the user is using xhr2
563
+ try {
564
+ XMLHttpRequest = require("xhr2");
565
+ xml = new XMLHttpRequest();
566
+ } catch (e2) {
567
+ throw "xhr2 object not defined, cancelling.";
568
+ }
569
+ }
570
+ }
571
+ return xml;
572
+ }
573
+
574
+ /**
575
+ * Parse URL-style parameters into object
576
+ *
577
+ * version: 1109.2015
578
+ * discuss at: http://phpjs.org/functions/parse_str
579
+ * + original by: Cagri Ekin
580
+ * + improved by: Michael White (http://getsprink.com)
581
+ * + tweaked by: Jack
582
+ * + bugfixed by: Onno Marsman
583
+ * + reimplemented by: stag019
584
+ * + bugfixed by: Brett Zamir (http://brett-zamir.me)
585
+ * + bugfixed by: stag019
586
+ * - depends on: urldecode
587
+ * + input by: Dreamer
588
+ * + bugfixed by: Brett Zamir (http://brett-zamir.me)
589
+ * % note 1: When no argument is specified, will put variables in global scope.
590
+ *
591
+ * @param string str String to parse
592
+ * @param array array to load data into
593
+ *
594
+ * @return object
595
+ */
596
+
597
+ }, {
598
+ key: "_parse_str",
599
+ value: function _parse_str(str, array) {
600
+ var glue1 = "=",
601
+ glue2 = "&",
602
+ array2 = String(str).replace(/^&?([\s\S]*?)&?$/, "$1").split(glue2),
603
+ i,
604
+ j,
605
+ chr,
606
+ tmp,
607
+ key,
608
+ value,
609
+ bracket,
610
+ keys,
611
+ evalStr,
612
+ fixStr = function fixStr(str) {
613
+ return decodeURIComponent(str).replace(/([\\"'])/g, "\\$1").replace(/\n/g, "\\n").replace(/\r/g, "\\r");
614
+ };
615
+ if (!array) {
616
+ array = this.window;
617
+ }
618
+
619
+ for (i = 0; i < array2.length; i++) {
620
+ tmp = array2[i].split(glue1);
621
+ if (tmp.length < 2) {
622
+ tmp = [tmp, ""];
623
+ }
624
+ key = fixStr(tmp[0]);
625
+ value = fixStr(tmp[1]);
626
+ while (key.charAt(0) === " ") {
627
+ key = key.substr(1);
628
+ }
629
+ if (key.indexOf("\0") > -1) {
630
+ key = key.substr(0, key.indexOf("\0"));
631
+ }
632
+ if (key && key.charAt(0) !== "[") {
633
+ keys = [];
634
+ bracket = 0;
635
+ for (j = 0; j < key.length; j++) {
636
+ if (key.charAt(j) === "[" && !bracket) {
637
+ bracket = j + 1;
638
+ } else if (key.charAt(j) === "]") {
639
+ if (bracket) {
640
+ if (!keys.length) {
641
+ keys.push(key.substr(0, bracket - 1));
642
+ }
643
+ keys.push(key.substr(bracket, j - bracket));
644
+ bracket = 0;
645
+ if (key.charAt(j + 1) !== "[") {
646
+ break;
647
+ }
648
+ }
649
+ }
650
+ }
651
+ if (!keys.length) {
652
+ keys = [key];
653
+ }
654
+ for (j = 0; j < keys[0].length; j++) {
655
+ chr = keys[0].charAt(j);
656
+ if (chr === " " || chr === "." || chr === "[") {
657
+ keys[0] = keys[0].substr(0, j) + "_" + keys[0].substr(j + 1);
658
+ }
659
+ if (chr === "[") {
660
+ break;
661
+ }
662
+ }
663
+ evalStr = "array";
664
+ for (j = 0; j < keys.length; j++) {
665
+ key = keys[j];
666
+ if (key !== "" && key !== " " || j === 0) {
667
+ key = "'" + key + "'";
668
+ } else {
669
+ key = eval(evalStr + ".push([]);") - 1;
670
+ }
671
+ evalStr += "[" + key + "]";
672
+ if (j !== keys.length - 1 && eval("typeof " + evalStr) === "undefined") {
673
+ eval(evalStr + " = [];");
674
+ }
675
+ }
676
+ evalStr += " = '" + value + "';\n";
677
+ eval(evalStr);
678
+ }
679
+ }
680
+ }
681
+
682
+ /**
683
+ * Get allowed API methods, sorted by GET or POST
684
+ * Watch out for multiple-method "account/settings"!
685
+ *
686
+ * @return array $apimethods
687
+ */
688
+
689
+ }, {
690
+ key: "getApiMethods",
691
+ value: function getApiMethods() {
692
+ var httpmethods = {
693
+ GET: ["account/settings", "account/verify_credentials", "application/rate_limit_status", "blocks/ids", "blocks/list", "collections/entries", "collections/list", "collections/show", "direct_messages", "direct_messages/sent", "direct_messages/show", "favorites/list", "followers/ids", "followers/list", "friends/ids", "friends/list", "friendships/incoming", "friendships/lookup", "friendships/lookup", "friendships/no_retweets/ids", "friendships/outgoing", "friendships/show", "geo/id/:place_id", "geo/reverse_geocode", "geo/search", "geo/similar_places", "help/configuration", "help/languages", "help/privacy", "help/tos", "lists/list", "lists/members", "lists/members/show", "lists/memberships", "lists/ownerships", "lists/show", "lists/statuses", "lists/subscribers", "lists/subscribers/show", "lists/subscriptions", "mutes/users/ids", "mutes/users/list", "oauth/authenticate", "oauth/authorize", "saved_searches/list", "saved_searches/show/:id", "search/tweets", "site", "statuses/firehose", "statuses/home_timeline", "statuses/mentions_timeline", "statuses/oembed", "statuses/retweeters/ids", "statuses/retweets/:id", "statuses/retweets_of_me", "statuses/sample", "statuses/show/:id", "statuses/user_timeline", "trends/available", "trends/closest", "trends/place", "user", "users/contributees", "users/contributors", "users/profile_banner", "users/search", "users/show", "users/suggestions", "users/suggestions/:slug", "users/suggestions/:slug/members"],
694
+ POST: ["account/remove_profile_banner", "account/settings__post", "account/update_delivery_device", "account/update_profile", "account/update_profile_background_image", "account/update_profile_banner", "account/update_profile_colors", "account/update_profile_image", "blocks/create", "blocks/destroy", "collections/create", "collections/destroy", "collections/entries/add", "collections/entries/curate", "collections/entries/move", "collections/entries/remove", "collections/update", "direct_messages/destroy", "direct_messages/new", "favorites/create", "favorites/destroy", "friendships/create", "friendships/destroy", "friendships/update", "lists/create", "lists/destroy", "lists/members/create", "lists/members/create_all", "lists/members/destroy", "lists/members/destroy_all", "lists/subscribers/create", "lists/subscribers/destroy", "lists/update", "media/upload", "mutes/users/create", "mutes/users/destroy", "oauth/access_token", "oauth/request_token", "oauth2/invalidate_token", "oauth2/token", "saved_searches/create", "saved_searches/destroy/:id", "statuses/destroy/:id", "statuses/filter", "statuses/lookup", "statuses/retweet/:id", "statuses/unretweet/:id", "statuses/update", "statuses/update_with_media", // deprecated, use media/upload
695
+ "users/lookup", "users/report_spam"]
696
+ };
697
+ return httpmethods;
698
+ }
699
+
700
+ /**
701
+ * Promise helpers
702
+ */
703
+
704
+ /**
705
+ * Get a deferred object
706
+ */
707
+
708
+ }, {
709
+ key: "_getDfd",
710
+ value: function _getDfd() {
711
+ if (typeof window !== "undefined") {
712
+ if (typeof window.jQuery !== "undefined" && window.jQuery.Deferred) {
713
+ return window.jQuery.Deferred();
714
+ }
715
+ if (typeof window.Q !== "undefined" && window.Q.defer) {
716
+ return window.Q.defer();
717
+ }
718
+ if (typeof window.RSVP !== "undefined" && window.RSVP.defer) {
719
+ return window.RSVP.defer();
720
+ }
721
+ if (typeof window.when !== "undefined" && window.when.defer) {
722
+ return window.when.defer();
723
+ }
724
+ }
725
+ if (typeof require !== "undefined") {
726
+ var promise_class = false;
727
+ try {
728
+ promise_class = require("jquery");
729
+ } catch (e) {}
730
+ if (promise_class) {
731
+ return promise_class.Deferred();
732
+ }
733
+ try {
734
+ promise_class = require("q");
735
+ } catch (e) {}
736
+ if (!promise_class) {
737
+ try {
738
+ promise_class = require("rsvp");
739
+ } catch (e) {}
740
+ }
741
+ if (!promise_class) {
742
+ try {
743
+ promise_class = require("when");
744
+ } catch (e) {}
745
+ }
746
+ if (promise_class) {
747
+ try {
748
+ return promise_class.defer();
749
+ } catch (e) {}
750
+ }
751
+ }
752
+ return false;
753
+ }
754
+
755
+ /**
756
+ * Get a promise from the dfd object
757
+ */
758
+
759
+ }, {
760
+ key: "_getPromise",
761
+ value: function _getPromise(dfd) {
762
+ if (typeof dfd.promise === "function") {
763
+ return dfd.promise();
764
+ }
765
+ return dfd.promise; // object
766
+ }
767
+
768
+ /**
769
+ * __call() helpers
770
+ */
771
+
772
+ /**
773
+ * Parse given params, detect query-style params
774
+ *
775
+ * @param array|string params Parameters to parse
776
+ *
777
+ * @return array apiparams
778
+ */
779
+
780
+ }, {
781
+ key: "_parseApiParams",
782
+ value: function _parseApiParams(params) {
783
+ var apiparams = {};
784
+ if ((typeof params === "undefined" ? "undefined" : _typeof(params)) === "object") {
785
+ apiparams = params;
786
+ } else {
787
+ this._parse_str(params, apiparams); //TODO
788
+ }
789
+
790
+ return apiparams;
791
+ }
792
+
793
+ /**
794
+ * Replace null and boolean parameters with their string representations
795
+ *
796
+ * @param array apiparams Parameter array to replace in
797
+ *
798
+ * @return array apiparams
799
+ */
800
+
801
+ }, {
802
+ key: "_stringifyNullBoolParams",
803
+ value: function _stringifyNullBoolParams(apiparams) {
804
+ for (var key in apiparams) {
805
+ if (!apiparams.hasOwnProperty(key)) {
806
+ continue;
807
+ }
808
+ var value = apiparams[key];
809
+ if (value === null) {
810
+ apiparams[key] = "null";
811
+ } else if (value === true || value === false) {
812
+ apiparams[key] = value ? "true" : "false";
813
+ }
814
+ }
815
+
816
+ return apiparams;
817
+ }
818
+
819
+ /**
820
+ * API method mapping: Replaces _ with / character
821
+ *
822
+ * @param string fn Function called
823
+ *
824
+ * @return string API method to call
825
+ */
826
+
827
+ }, {
828
+ key: "_mapFnInsertSlashes",
829
+ value: function _mapFnInsertSlashes(fn) {
830
+ return fn.split("_").join("/");
831
+ }
832
+
833
+ /**
834
+ * API method mapping: Restore _ character in named parameters
835
+ *
836
+ * @param string method API method to call
837
+ *
838
+ * @return string API method with restored underscores
839
+ */
840
+
841
+ }, {
842
+ key: "_mapFnRestoreParamUnderscores",
843
+ value: function _mapFnRestoreParamUnderscores(method) {
844
+ var url_parameters_with_underscore = ["screen_name", "place_id"];
845
+ var i = undefined,
846
+ param = undefined,
847
+ replacement_was = undefined;
848
+ for (i = 0; i < url_parameters_with_underscore.length; i++) {
849
+ param = url_parameters_with_underscore[i].toUpperCase();
850
+ replacement_was = param.split("_").join("/");
851
+ method = method.split(replacement_was).join(param);
852
+ }
853
+
854
+ return method;
855
+ }
856
+
857
+ /**
858
+ * Maps called PHP magic method name to Twitter API method
859
+ *
860
+ * @param string $fn Function called
861
+ * @param array $apiparams byref API parameters
862
+ *
863
+ * @return string[] (string method, string method_template)
864
+ */
865
+
866
+ }, {
867
+ key: "_mapFnToApiMethod",
868
+ value: function _mapFnToApiMethod(fn, apiparams) {
869
+ var method = "",
870
+ param = undefined,
871
+ i = undefined,
872
+ j = undefined;
873
+
874
+ // replace _ by /
875
+ method = this._mapFnInsertSlashes(fn);
876
+
877
+ // undo replacement for URL parameters
878
+ method = this._mapFnRestoreParamUnderscores(method);
879
+
880
+ // replace AA by URL parameters
881
+ var method_template = method;
882
+ var match = method.match(/[A-Z_]{2,}/);
883
+ if (match) {
884
+ for (i = 0; i < match.length; i++) {
885
+ param = match[i];
886
+ var param_l = param.toLowerCase();
887
+ method_template = method_template.split(param).join(":" + param_l);
888
+ if (typeof apiparams[param_l] === "undefined") {
889
+ for (j = 0; j < 26; j++) {
890
+ method_template = method_template.split(String.fromCharCode(65 + j)).join("_" + String.fromCharCode(97 + j));
891
+ }
892
+ throw "To call the templated method \"" + method_template + "\", specify the parameter value for \"" + param_l + "\".";
893
+ }
894
+ method = method.split(param).join(apiparams[param_l]);
895
+ delete apiparams[param_l];
896
+ }
897
+ }
898
+
899
+ // replace A-Z by _a-z
900
+ for (i = 0; i < 26; i++) {
901
+ method = method.split(String.fromCharCode(65 + i)).join("_" + String.fromCharCode(97 + i));
902
+ method_template = method_template.split(String.fromCharCode(65 + i)).join("_" + String.fromCharCode(97 + i));
903
+ }
904
+
905
+ return [method, method_template];
906
+ }
907
+
908
+ /**
909
+ * Detects HTTP method to use for API call
910
+ *
911
+ * @param string method The API method to call
912
+ * @param array params The parameters to send along
913
+ *
914
+ * @return string The HTTP method that should be used
915
+ */
916
+
917
+ }, {
918
+ key: "_detectMethod",
919
+ value: function _detectMethod(method, params) {
920
+ if (typeof params.httpmethod !== "undefined") {
921
+ var httpmethod = params.httpmethod;
922
+ delete params.httpmethod;
923
+ return httpmethod;
924
+ }
925
+
926
+ // multi-HTTP method endpoints
927
+ switch (method) {
928
+ case "account/settings":
929
+ case "account/login_verification_enrollment":
930
+ case "account/login_verification_request":
931
+ method = Object.keys(params).length ? method + "__post" : method;
932
+ break;
933
+ }
934
+
935
+ var apimethods = this.getApiMethods();
936
+ for (var httpmethod in apimethods) {
937
+ if (apimethods.hasOwnProperty(httpmethod) && apimethods[httpmethod].indexOf(method) > -1) {
938
+ return httpmethod;
939
+ }
940
+ }
941
+ throw "Can't find HTTP method to use for \"" + method + "\".";
942
+ }
943
+
944
+ /**
945
+ * Detects if API call should use multipart/form-data
946
+ *
947
+ * @param string method The API method to call
948
+ *
949
+ * @return bool Whether the method should be sent as multipart
950
+ */
951
+
952
+ }, {
953
+ key: "_detectMultipart",
954
+ value: function _detectMultipart(method) {
955
+ var multiparts = [
956
+ // Tweets
957
+ "statuses/update_with_media", "media/upload",
958
+
959
+ // Users
960
+ "account/update_profile_background_image", "account/update_profile_image", "account/update_profile_banner"];
961
+ return multiparts.indexOf(method) > -1;
962
+ }
963
+
964
+ /**
965
+ * Signature helper
966
+ *
967
+ * @param string httpmethod Usually either 'GET' or 'POST' or 'DELETE'
968
+ * @param string method The API method to call
969
+ * @param array base_params The signature base parameters
970
+ *
971
+ * @return string signature
972
+ */
973
+
974
+ }, {
975
+ key: "_getSignature",
976
+ value: function _getSignature(httpmethod, method, keys, base_params) {
977
+ // convert params to string
978
+ var base_string = "",
979
+ key = undefined,
980
+ value = undefined;
981
+ for (var i = 0; i < keys.length; i++) {
982
+ key = keys[i];
983
+ value = base_params[key];
984
+ base_string += key + "=" + this._url(value) + "&";
985
+ }
986
+ base_string = base_string.substring(0, base_string.length - 1);
987
+ return this._sha1(httpmethod + "&" + this._url(method) + "&" + this._url(base_string));
988
+ }
989
+
990
+ /**
991
+ * Generates the UNIX timestamp
992
+ */
993
+
994
+ }, {
995
+ key: "_time",
996
+ value: function _time() {
997
+ return Math.round(new Date().getTime() / 1000);
998
+ }
999
+
1000
+ /**
1001
+ * Generates an OAuth signature
1002
+ *
1003
+ * @param string httpmethod Usually either 'GET' or 'POST' or 'DELETE'
1004
+ * @param string method The API method to call
1005
+ * @param array optional params The API call parameters, associative
1006
+ *
1007
+ * @return string Authorization HTTP header
1008
+ */
1009
+
1010
+ }, {
1011
+ key: "_sign",
1012
+ value: function _sign(httpmethod, method) {
1013
+ var params = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2];
1014
+
1015
+ if (this._oauth_consumer_key === null) {
1016
+ throw "To generate a signature, the consumer key must be set.";
1017
+ }
1018
+ var sign_params = {
1019
+ consumer_key: this._oauth_consumer_key,
1020
+ version: "1.0",
1021
+ timestamp: this._time(),
1022
+ nonce: this._nonce(),
1023
+ signature_method: "HMAC-SHA1"
1024
+ };
1025
+ var sign_base_params = {};
1026
+ for (var key in sign_params) {
1027
+ if (!sign_params.hasOwnProperty(key)) {
1028
+ continue;
1029
+ }
1030
+ var value = sign_params[key];
1031
+ sign_base_params["oauth_" + key] = this._url(value);
1032
+ }
1033
+ if (this._oauth_token !== null) {
1034
+ sign_base_params.oauth_token = this._url(this._oauth_token);
1035
+ }
1036
+ var oauth_params = this._clone(sign_base_params);
1037
+ for (key in params) {
1038
+ if (!params.hasOwnProperty(key)) {
1039
+ continue;
1040
+ }
1041
+ sign_base_params[key] = params[key];
1042
+ }
1043
+ var keys = this._ksort(sign_base_params);
1044
+
1045
+ var signature = this._getSignature(httpmethod, method, keys, sign_base_params);
1046
+
1047
+ params = oauth_params;
1048
+ params.oauth_signature = signature;
1049
+ keys = this._ksort(params);
1050
+ var authorization = "OAuth ";
1051
+ for (var i = 0; i < keys.length; i++) {
1052
+ key = keys[i];
1053
+ authorization += key + "=\"" + this._url(params[key]) + "\", ";
1054
+ }
1055
+ return authorization.substring(0, authorization.length - 2);
1056
+ }
1057
+
1058
+ /**
1059
+ * Build multipart request from upload params
1060
+ *
1061
+ * @param string method The API method to call
1062
+ * @param array params The parameters to send along
1063
+ *
1064
+ * @return null|string The built multipart request body
1065
+ */
1066
+
1067
+ }, {
1068
+ key: "_buildMultipart",
1069
+ value: function _buildMultipart(method, params) {
1070
+ // well, files will only work in multipart methods
1071
+ if (!this._detectMultipart(method)) {
1072
+ return;
1073
+ }
1074
+
1075
+ // only check specific parameters
1076
+ var possible_methods = [
1077
+ // Tweets
1078
+ "media/upload", "statuses/update_with_media",
1079
+ // Accounts
1080
+ "account/update_profile_background_image", "account/update_profile_image", "account/update_profile_banner"];
1081
+ var possible_files = {
1082
+ // Tweets
1083
+ "media/upload": "media",
1084
+ "statuses/update_with_media": "media[]",
1085
+ // Accounts
1086
+ "account/update_profile_background_image": "image",
1087
+ "account/update_profile_image": "image",
1088
+ "account/update_profile_banner": "banner"
1089
+ };
1090
+ // method might have files?
1091
+ if (possible_methods.indexOf(method) === -1) {
1092
+ return;
1093
+ }
1094
+
1095
+ // check for filenames
1096
+ possible_files = possible_files[method].split(" ");
1097
+
1098
+ var multipart_border = "--------------------" + this._nonce();
1099
+ var multipart_request = "";
1100
+ for (var key in params) {
1101
+ if (!params.hasOwnProperty(key)) {
1102
+ continue;
1103
+ }
1104
+ multipart_request += "--" + multipart_border + "\r\nContent-Disposition: form-data; name=\"" + key + "\"";
1105
+ if (possible_files.indexOf(key) === -1) {
1106
+ multipart_request += "\r\nContent-Transfer-Encoding: base64";
1107
+ }
1108
+ multipart_request += "\r\n\r\n" + params[key] + "\r\n";
1109
+ }
1110
+ multipart_request += "--" + multipart_border + "--";
1111
+ return multipart_request;
1112
+ }
1113
+
1114
+ /**
1115
+ * Detects if API call should use media endpoint
1116
+ *
1117
+ * @param string method The API method to call
1118
+ *
1119
+ * @return bool Whether the method is defined in media API
1120
+ */
1121
+
1122
+ }, {
1123
+ key: "_detectMedia",
1124
+ value: function _detectMedia(method) {
1125
+ var medias = ["media/upload"];
1126
+ return medias.indexOf(method) > -1;
1127
+ }
1128
+
1129
+ /**
1130
+ * Detects if API call should use JSON body
1131
+ *
1132
+ * @param string method The API method to call
1133
+ *
1134
+ * @return bool Whether the method is defined as accepting JSON body
1135
+ */
1136
+
1137
+ }, {
1138
+ key: "_detectJsonBody",
1139
+ value: function _detectJsonBody(method) {
1140
+ var json_bodies = ["collections/entries/curate"];
1141
+ return json_bodies.indexOf(method) > -1;
1142
+ }
1143
+
1144
+ /**
1145
+ * Builds the complete API endpoint url
1146
+ *
1147
+ * @param string method The API method to call
1148
+ *
1149
+ * @return string The URL to send the request to
1150
+ */
1151
+
1152
+ }, {
1153
+ key: "_getEndpoint",
1154
+ value: function _getEndpoint(method) {
1155
+ var url = undefined;
1156
+ if (method.substring(0, 5) === "oauth") {
1157
+ url = this._endpoint_oauth + method;
1158
+ } else if (this._detectMedia(method)) {
1159
+ url = this._endpoint_media + method + ".json";
1160
+ } else if (method === "statuses/oembed") {
1161
+ url = this._endpoint_publish + "oembed";
1162
+ } else {
1163
+ url = this._endpoint + method + ".json";
1164
+ }
1165
+ return url;
1166
+ }
1167
+
1168
+ /**
1169
+ * Parses the API reply to encode it in the set return_format
1170
+ *
1171
+ * @param string reply The actual reply, JSON-encoded or URL-encoded
1172
+ *
1173
+ * @return array|object The parsed reply
1174
+ */
1175
+
1176
+ }, {
1177
+ key: "_parseApiReply",
1178
+ value: function _parseApiReply(reply) {
1179
+ if (typeof reply !== "string" || reply === "") {
1180
+ return {};
1181
+ }
1182
+ if (reply === "[]") {
1183
+ return [];
1184
+ }
1185
+ var parsed = undefined;
1186
+ try {
1187
+ parsed = JSON.parse(reply);
1188
+ } catch (e) {
1189
+ parsed = {};
1190
+ // assume query format
1191
+ var elements = reply.split("&");
1192
+ for (var i = 0; i < elements.length; i++) {
1193
+ var element = elements[i].split("=", 2);
1194
+ if (element.length > 1) {
1195
+ parsed[element[0]] = decodeURIComponent(element[1]);
1196
+ } else {
1197
+ parsed[element[0]] = null;
1198
+ }
1199
+ }
1200
+ }
1201
+ return parsed;
1202
+ }
1203
+
1204
+ /**
1205
+ * Uncommon API methods
1206
+ */
1207
+
1208
+ /**
1209
+ * Gets the OAuth authenticate URL for the current request token
1210
+ *
1211
+ * @return object Promise
1212
+ */
1213
+
1214
+ }, {
1215
+ key: "oauth_authenticate",
1216
+ value: function oauth_authenticate() {
1217
+ var params = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
1218
+ var callback = arguments.length <= 1 || arguments[1] === undefined ? undefined : arguments[1];
1219
+ var type = arguments.length <= 2 || arguments[2] === undefined ? "authenticate" : arguments[2];
1220
+
1221
+ var dfd = this._getDfd();
1222
+ if (typeof params.force_login === "undefined") {
1223
+ params.force_login = null;
1224
+ }
1225
+ if (typeof params.screen_name === "undefined") {
1226
+ params.screen_name = null;
1227
+ }
1228
+ if (["authenticate", "authorize"].indexOf(type) === -1) {
1229
+ type = "authenticate";
1230
+ }
1231
+ if (this._oauth_token === null) {
1232
+ var error = "To get the " + type + " URL, the OAuth token must be set.";
1233
+ if (dfd) {
1234
+ dfd.reject({ error: error });
1235
+ return this._getPromise(dfd);
1236
+ }
1237
+ throw error;
1238
+ }
1239
+ var url = this._endpoint_oauth + "oauth/" + type + "?oauth_token=" + this._url(this._oauth_token);
1240
+ if (params.force_login === true) {
1241
+ url += "&force_login=1";
1242
+ }
1243
+ if (params.screen_name !== null) {
1244
+ url += "&screen_name=" + params.screen_name;
1245
+ }
1246
+ if (typeof callback === "function") {
1247
+ callback(url);
1248
+ }
1249
+ if (dfd) {
1250
+ dfd.resolve({ reply: url });
1251
+ return this._getPromise(dfd);
1252
+ }
1253
+ // no promises
1254
+ return true;
1255
+ }
1256
+
1257
+ /**
1258
+ * Gets the OAuth authorize URL for the current request token
1259
+ *
1260
+ * @return string The OAuth authorize URL
1261
+ */
1262
+
1263
+ }, {
1264
+ key: "oauth_authorize",
1265
+ value: function oauth_authorize(params, callback) {
1266
+ return this.oauth_authenticate(params, callback, "authorize");
1267
+ }
1268
+
1269
+ /**
1270
+ * Gets the OAuth bearer token
1271
+ *
1272
+ * @return object Promise
1273
+ */
1274
+
1275
+ }, {
1276
+ key: "oauth2_token",
1277
+ value: function oauth2_token(callback) {
1278
+ var _this = this;
1279
+
1280
+ var dfd = this._getDfd();
1281
+
1282
+ if (this._oauth_consumer_key === null) {
1283
+ var error = "To obtain a bearer token, the consumer key must be set.";
1284
+ if (dfd) {
1285
+ dfd.reject({ error: error });
1286
+ return this._getPromise(dfd);
1287
+ }
1288
+ throw error;
1289
+ }
1290
+
1291
+ if (!dfd && typeof callback === "undefined") {
1292
+ callback = function () {};
1293
+ }
1294
+
1295
+ var post_fields = "grant_type=client_credentials";
1296
+ var url = this._endpoint_oauth + "oauth2/token";
1297
+
1298
+ if (this._use_proxy) {
1299
+ url = url.replace(this._endpoint_base, this._endpoint_proxy);
1300
+ }
1301
+
1302
+ var xml = this._getXmlRequestObject();
1303
+ if (xml === null) {
1304
+ return;
1305
+ }
1306
+ xml.open("POST", url, true);
1307
+ xml.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
1308
+ xml.setRequestHeader((this._use_proxy ? "X-" : "") + "Authorization", "Basic " + this._base64_encode(this._oauth_consumer_key + ":" + this._oauth_consumer_secret));
1309
+
1310
+ xml.onreadystatechange = function () {
1311
+ if (xml.readyState >= 4) {
1312
+ var httpstatus = 12027;
1313
+ try {
1314
+ httpstatus = xml.status;
1315
+ } catch (e) {}
1316
+ var response = "";
1317
+ try {
1318
+ response = xml.responseText;
1319
+ } catch (e) {}
1320
+ var reply = _this._parseApiReply(response);
1321
+ reply.httpstatus = httpstatus;
1322
+ if (httpstatus === 200) {
1323
+ _this.setBearerToken(reply.access_token);
1324
+ }
1325
+ if (typeof callback === "function") {
1326
+ callback(reply);
1327
+ }
1328
+ if (dfd) {
1329
+ dfd.resolve({ reply: reply });
1330
+ }
1331
+ }
1332
+ };
1333
+ // function called when an error occurs, including a timeout
1334
+ xml.onerror = function (e) {
1335
+ if (typeof callback === "function") {
1336
+ callback(null, e);
1337
+ }
1338
+ if (dfd) {
1339
+ dfd.reject(e);
1340
+ }
1341
+ };
1342
+ xml.timeout = 30000; // in milliseconds
1343
+
1344
+ xml.send(post_fields);
1345
+ if (dfd) {
1346
+ return this._getPromise(dfd);
1347
+ }
1348
+ }
1349
+
1350
+ /**
1351
+ * Calls the API using cURL
1352
+ *
1353
+ * @param string httpmethod The HTTP method to use for making the request
1354
+ * @param string method The API method to call
1355
+ * @param array optional params The parameters to send along
1356
+ * @param bool optional multipart Whether to use multipart/form-data
1357
+ * @param bool optional app_only_auth Whether to use app-only bearer authentication
1358
+ * @param function callback The function to call with the API call result
1359
+ *
1360
+ * @return mixed The API reply, encoded in the set return_format
1361
+ */
1362
+
1363
+ }, {
1364
+ key: "_callApi",
1365
+ value: function _callApi(httpmethod, method) {
1366
+ var params = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2];
1367
+ var multipart = arguments.length <= 3 || arguments[3] === undefined ? false : arguments[3];
1368
+
1369
+ var _this2 = this;
1370
+
1371
+ var app_only_auth = arguments.length <= 4 || arguments[4] === undefined ? false : arguments[4];
1372
+ var callback = arguments.length <= 5 || arguments[5] === undefined ? function () {} : arguments[5];
1373
+
1374
+ var dfd = this._getDfd();
1375
+
1376
+ var url = this._getEndpoint(method),
1377
+ authorization = null;
1378
+
1379
+ var xml = this._getXmlRequestObject();
1380
+ if (xml === null) {
1381
+ return;
1382
+ }
1383
+ var post_fields = undefined;
1384
+
1385
+ if (httpmethod === "GET") {
1386
+ var url_with_params = url;
1387
+ if (JSON.stringify(params) !== "{}") {
1388
+ url_with_params += "?" + this._http_build_query(params);
1389
+ }
1390
+ if (!app_only_auth) {
1391
+ authorization = this._sign(httpmethod, url, params);
1392
+ }
1393
+
1394
+ if (this._use_proxy) {
1395
+ url_with_params = url_with_params.replace(this._endpoint_base, this._endpoint_proxy).replace(this._endpoint_base_media, this._endpoint_proxy);
1396
+ }
1397
+ xml.open(httpmethod, url_with_params, true);
1398
+ } else {
1399
+ if (multipart) {
1400
+ if (!app_only_auth) {
1401
+ authorization = this._sign(httpmethod, url, {});
1402
+ }
1403
+ params = this._buildMultipart(method, params);
1404
+ } else if (this._detectJsonBody(method)) {
1405
+ authorization = this._sign(httpmethod, url, {});
1406
+ params = JSON.stringify(params);
1407
+ } else {
1408
+ if (!app_only_auth) {
1409
+ authorization = this._sign(httpmethod, url, params);
1410
+ }
1411
+ params = this._http_build_query(params);
1412
+ }
1413
+ post_fields = params;
1414
+ if (this._use_proxy || multipart) {
1415
+ // force proxy for multipart base64
1416
+ url = url.replace(this._endpoint_base, this._endpoint_proxy).replace(this._endpoint_base_media, this._endpoint_proxy);
1417
+ }
1418
+ xml.open(httpmethod, url, true);
1419
+ if (multipart) {
1420
+ xml.setRequestHeader("Content-Type", "multipart/form-data; boundary=" + post_fields.split("\r\n")[0].substring(2));
1421
+ } else if (this._detectJsonBody(method)) {
1422
+ xml.setRequestHeader("Content-Type", "application/json");
1423
+ } else {
1424
+ xml.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
1425
+ }
1426
+ }
1427
+ if (app_only_auth) {
1428
+ if (this._oauth_consumer_key === null && this._oauth_bearer_token === null) {
1429
+ var error = "To make an app-only auth API request, consumer key or bearer token must be set.";
1430
+ if (dfd) {
1431
+ dfd.reject({ error: error });
1432
+ return this._getPromise(dfd);
1433
+ }
1434
+ throw error;
1435
+ }
1436
+ // automatically fetch bearer token, if necessary
1437
+ if (this._oauth_bearer_token === null) {
1438
+ if (dfd) {
1439
+ return this.oauth2_token().then(function () {
1440
+ return _this2._callApi(httpmethod, method, params, multipart, app_only_auth, callback);
1441
+ });
1442
+ }
1443
+ this.oauth2_token(function () {
1444
+ _this2._callApi(httpmethod, method, params, multipart, app_only_auth, callback);
1445
+ });
1446
+ return;
1447
+ }
1448
+ authorization = "Bearer " + this._oauth_bearer_token;
1449
+ }
1450
+ if (authorization !== null) {
1451
+ xml.setRequestHeader((this._use_proxy ? "X-" : "") + "Authorization", authorization);
1452
+ }
1453
+ xml.onreadystatechange = function () {
1454
+ if (xml.readyState >= 4) {
1455
+ var httpstatus = 12027;
1456
+ try {
1457
+ httpstatus = xml.status;
1458
+ } catch (e) {}
1459
+ var response = "";
1460
+ try {
1461
+ response = xml.responseText;
1462
+ } catch (e) {}
1463
+ var reply = _this2._parseApiReply(response);
1464
+ reply.httpstatus = httpstatus;
1465
+ var rate = null;
1466
+ if (typeof xml.getResponseHeader !== "undefined" && xml.getResponseHeader("x-rate-limit-limit") !== "") {
1467
+ rate = {
1468
+ limit: xml.getResponseHeader("x-rate-limit-limit"),
1469
+ remaining: xml.getResponseHeader("x-rate-limit-remaining"),
1470
+ reset: xml.getResponseHeader("x-rate-limit-reset")
1471
+ };
1472
+ }
1473
+ if (typeof callback === "function") {
1474
+ callback(reply, rate);
1475
+ }
1476
+ if (dfd) {
1477
+ dfd.resolve({ reply: reply, rate: rate });
1478
+ }
1479
+ }
1480
+ };
1481
+ // function called when an error occurs, including a timeout
1482
+ xml.onerror = function (e) {
1483
+ if (typeof callback === "function") {
1484
+ callback(null, null, e);
1485
+ }
1486
+ if (dfd) {
1487
+ dfd.reject(e);
1488
+ }
1489
+ };
1490
+ xml.timeout = 30000; // in milliseconds
1491
+
1492
+ xml.send(httpmethod === "GET" ? null : post_fields);
1493
+ if (dfd) {
1494
+ return this._getPromise(dfd);
1495
+ }
1496
+ return true;
1497
+ }
1498
+
1499
+ /**
1500
+ * Main API handler working on any requests you issue
1501
+ *
1502
+ * @param string fn The member function you called
1503
+ * @param array params The parameters you sent along
1504
+ * @param function callback The callback to call with the reply
1505
+ * @param bool app_only_auth Whether to use app-only auth
1506
+ *
1507
+ * @return object Promise
1508
+ */
1509
+
1510
+ }, {
1511
+ key: "__call",
1512
+ value: function __call(fn) {
1513
+ var params = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];
1514
+ var callback = arguments[2];
1515
+ var app_only_auth = arguments.length <= 3 || arguments[3] === undefined ? false : arguments[3];
1516
+
1517
+ if (typeof callback !== "function" && typeof params === "function") {
1518
+ callback = params;
1519
+ params = {};
1520
+ if (typeof callback === "boolean") {
1521
+ app_only_auth = callback;
1522
+ }
1523
+ } else if (typeof callback === "undefined") {
1524
+ callback = function () {};
1525
+ }
1526
+ switch (fn) {
1527
+ case "oauth_authenticate":
1528
+ case "oauth_authorize":
1529
+ return this[fn](params, callback);
1530
+
1531
+ case "oauth2_token":
1532
+ return this[fn](callback);
1533
+ }
1534
+
1535
+ // parse parameters
1536
+ var apiparams = this._parseApiParams(params);
1537
+
1538
+ // stringify null and boolean parameters
1539
+ apiparams = this._stringifyNullBoolParams(apiparams);
1540
+
1541
+ // reset token when requesting a new token (causes 401 for signature error on 2nd+ requests)
1542
+ if (fn === "oauth_requestToken") {
1543
+ this.setToken(null, null);
1544
+ }
1545
+
1546
+ // map function name to API method
1547
+
1548
+ var _mapFnToApiMethod2 = this._mapFnToApiMethod(fn, apiparams);
1549
+
1550
+ var _mapFnToApiMethod3 = _slicedToArray(_mapFnToApiMethod2, 2);
1551
+
1552
+ var method = _mapFnToApiMethod3[0];
1553
+ var method_template = _mapFnToApiMethod3[1];
1554
+ var httpmethod = this._detectMethod(method_template, apiparams);
1555
+ var multipart = this._detectMultipart(method_template);
1556
+
1557
+ return this._callApi(httpmethod, method, apiparams, multipart, app_only_auth, callback);
1558
+ }
1559
+ }]);
1560
+
1561
+ return Codebird;
1562
+ })();
1563
+
1564
+ ;
1565
+
1566
+ if ((typeof module === "undefined" ? "undefined" : _typeof(module)) === "object" && module && _typeof(module.exports) === "object") {
1567
+ // Expose codebird as module.exports in loaders that implement the Node
1568
+ // module pattern (including browserify). Do not create the global, since
1569
+ // the user will be storing it themselves locally, and globals are frowned
1570
+ // upon in the Node module world.
1571
+ module.exports = Codebird;
1572
+ } else {
1573
+ // Otherwise expose codebird to the global object as usual
1574
+ if ((typeof window === "undefined" ? "undefined" : _typeof(window)) === "object" && window) {
1575
+ window.Codebird = Codebird;
1576
+ }
1577
+
1578
+ // Register as a named AMD module, since codebird can be concatenated with other
1579
+ // files that may use define, but not via a proper concatenation script that
1580
+ // understands anonymous AMD modules. A named AMD is safest and most robust
1581
+ // way to register. Lowercase codebird is used because AMD module names are
1582
+ // derived from file names, and codebird is normally delivered in a lowercase
1583
+ // file name. Do this after creating the global so that if an AMD module wants
1584
+ // to call noConflict to hide this version of codebird, it will work.
1585
+ if (typeof define === "function" && define.amd) {
1586
+ define("codebird", [], function () {
1587
+ return Codebird;
1588
+ });
1589
+ }
1590
+ }
1591
+ })();
assets/social-feeds/doT.min.js ADDED
@@ -0,0 +1,2 @@
 
 
1
+ /* Laura Doktorova https://github.com/olado/doT */
2
+ !function(){"use strict";function e(n,t,r){return("string"==typeof t?t:t.toString()).replace(n.define||a,function(e,t,o,a){return 0===t.indexOf("def.")&&(t=t.substring(4)),t in r||(":"===o?(n.defineParams&&a.replace(n.defineParams,function(e,n,o){r[t]={arg:n,text:o}}),t in r||(r[t]=a)):new Function("def","def['"+t+"']="+a)(r)),""}).replace(n.use||a,function(t,o){n.useParams&&(o=o.replace(n.useParams,function(e,n,t,o){if(r[t]&&r[t].arg&&o){var a=(t+":"+o).replace(/'|\\/g,"_");return r.__exp=r.__exp||{},r.__exp[a]=r[t].text.replace(new RegExp("(^|[^\\w$])"+r[t].arg+"([^\\w$])","g"),"$1"+o+"$2"),n+"def.__exp['"+a+"']"}}));var a=new Function("def","return "+o)(r);return a?e(n,a,r):a})}function n(e){return e.replace(/\\('|\\)/g,"$1").replace(/[\r\t\n]/g," ")}var t,r={engine:"doT",version:"1.1.1",templateSettings:{evaluate:/\{\{([\s\S]+?(\}?)+)\}\}/g,interpolate:/\{\{=([\s\S]+?)\}\}/g,encode:/\{\{!([\s\S]+?)\}\}/g,use:/\{\{#([\s\S]+?)\}\}/g,useParams:/(^|[^\w$])def(?:\.|\[[\'\"])([\w$\.]+)(?:[\'\"]\])?\s*\:\s*([\w$\.]+|\"[^\"]+\"|\'[^\']+\'|\{[^\}]+\})/g,define:/\{\{##\s*([\w\.$]+)\s*(\:|=)([\s\S]+?)#\}\}/g,defineParams:/^\s*([\w$]+):([\s\S]+)/,conditional:/\{\{\?(\?)?\s*([\s\S]*?)\s*\}\}/g,iterate:/\{\{~\s*(?:\}\}|([\s\S]+?)\s*\:\s*([\w$]+)\s*(?:\:\s*([\w$]+))?\s*\}\})/g,varname:"it",strip:!0,append:!0,selfcontained:!1,doNotSkipEncoded:!1},template:void 0,compile:void 0,log:!0};r.encodeHTMLSource=function(e){var n={"&":"&#38;","<":"&#60;",">":"&#62;",'"':"&#34;","'":"&#39;","/":"&#47;"},t=e?/[&<>"'\/]/g:/&(?!#?\w+;)|<|>|"|'|\//g;return function(e){return e?e.toString().replace(t,function(e){return n[e]||e}):""}},t=function(){return this||(0,eval)("this")}(),"undefined"!=typeof module&&module.exports?module.exports=r:"function"==typeof define&&define.amd?define(function(){return r}):t.doT=r;var o={append:{start:"'+(",end:")+'",startencode:"'+encodeHTML("},split:{start:"';out+=(",end:");out+='",startencode:"';out+=encodeHTML("}},a=/$^/;r.template=function(c,i,u){i=i||r.templateSettings;var d,s,p=i.append?o.append:o.split,l=0,f=i.use||i.define?e(i,c,u||{}):c;f=("var out='"+(i.strip?f.replace(/(^|\r|\n)\t* +| +\t*(\r|\n|$)/g," ").replace(/\r|\n|\t|\/\*[\s\S]*?\*\//g,""):f).replace(/'|\\/g,"\\$&").replace(i.interpolate||a,function(e,t){return p.start+n(t)+p.end}).replace(i.encode||a,function(e,t){return d=!0,p.startencode+n(t)+p.end}).replace(i.conditional||a,function(e,t,r){return t?r?"';}else if("+n(r)+"){out+='":"';}else{out+='":r?"';if("+n(r)+"){out+='":"';}out+='"}).replace(i.iterate||a,function(e,t,r,o){return t?(l+=1,s=o||"i"+l,t=n(t),"';var arr"+l+"="+t+";if(arr"+l+"){var "+r+","+s+"=-1,l"+l+"=arr"+l+".length-1;while("+s+"<l"+l+"){"+r+"=arr"+l+"["+s+"+=1];out+='"):"';} } out+='"}).replace(i.evaluate||a,function(e,t){return"';"+n(t)+"out+='"})+"';return out;").replace(/\n/g,"\\n").replace(/\t/g,"\\t").replace(/\r/g,"\\r").replace(/(\s|;|\}|^|\{)out\+='';/g,"$1").replace(/\+''/g,""),d&&(i.selfcontained||!t||t._encodeHTML||(t._encodeHTML=r.encodeHTMLSource(i.doNotSkipEncoded)),f="var encodeHTML = typeof _encodeHTML !== 'undefined' ? _encodeHTML : ("+r.encodeHTMLSource.toString()+"("+(i.doNotSkipEncoded||"")+"));"+f);try{return new Function(i.varname,f)}catch(e){throw"undefined"!=typeof console&&console.log("Could not create a template function: "+f),e}},r.compile=function(e,n){return r.template(e,null,n)}}();
assets/social-feeds/jquery.socialfeed.js ADDED
@@ -0,0 +1,790 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ if (typeof Object.create !== 'function') {
2
+ Object.create = function(obj) {
3
+ function F() {}
4
+ F.prototype = obj;
5
+ return new F();
6
+ };
7
+ }
8
+
9
+ (function($, window, document, undefined) {
10
+ $.fn.socialfeed = function(_options) {
11
+
12
+
13
+ var defaults = {
14
+ plugin_folder: '', // a folder in which the plugin is located (with a slash in the end)
15
+ template: 'template.html', // a path to the template file
16
+ show_media: false, // show images of attachments if available
17
+ media_min_width: 300,
18
+ length: 500, // maximum length of post message shown
19
+ date_format: 'll',
20
+ date_locale: 'en'
21
+ };
22
+ //---------------------------------------------------------------------------------
23
+ var options = $.extend(defaults, _options),
24
+ container = $(this),
25
+ template,
26
+ social_networks = ['facebook', 'instagram', 'vk', 'google', 'blogspot', 'twitter', 'pinterest', 'rss'],
27
+ posts_to_load_count = 0,
28
+ loaded_post_count = 0;
29
+ // container.empty().css('display', 'block');
30
+ //---------------------------------------------------------------------------------
31
+
32
+ //---------------------------------------------------------------------------------
33
+ // This function performs consequent data loading from all of the sources by calling corresponding functions
34
+ function calculatePostsToLoadCount() {
35
+ social_networks.forEach(function(network) {
36
+ if (options[network]) {
37
+ if (options[network].accounts) {
38
+ posts_to_load_count += options[network].limit * options[network].accounts.length;
39
+ } else if (options[network].urls ){
40
+ posts_to_load_count += options[network].limit * options[network].urls.length;
41
+ } else {
42
+ posts_to_load_count += options[network].limit;
43
+ }
44
+ }
45
+ });
46
+ }
47
+
48
+ calculatePostsToLoadCount();
49
+
50
+ function fireCallback() {
51
+ var fire = true;
52
+ /*$.each(Object.keys(loaded), function() {
53
+ if (loaded[this] > 0)
54
+ fire = false;
55
+ });*/
56
+ if (fire && options.callback) {
57
+ options.callback();
58
+ }
59
+ }
60
+
61
+ var Utility = {
62
+ request: function(url, callback) {
63
+ $.ajax({
64
+ url: url,
65
+ dataType: 'jsonp',
66
+ success: callback
67
+ });
68
+ },
69
+ get_request: function(url, callback) {
70
+ $.get(url, callback, 'json');
71
+ },
72
+ wrapLinks: function(string, social_network) {
73
+ var exp = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig;
74
+ if (social_network === 'google-plus') {
75
+ string = string.replace(/(@|#)([a-z0-9_]+['])/ig, Utility.wrapGoogleplusTagTemplate);
76
+ } else {
77
+ string = string.replace(exp, Utility.wrapLinkTemplate);
78
+ }
79
+ return string;
80
+ },
81
+ wrapLinkTemplate: function(string) {
82
+ return '<a target="_blank" href="' + string + '">' + string + '<\/a>';
83
+ },
84
+ wrapGoogleplusTagTemplate: function(string) {
85
+ return '<a target="_blank" href="https://plus.google.com/s/' + string + '" >' + string + '<\/a>';
86
+ },
87
+ shorten: function(string) {
88
+ string = $.trim(string);
89
+ if (string.length > options.length) {
90
+ return jQuery.trim(string).substring(0, options.length).split(" ").slice(0, -1).join(" ") + "...";
91
+ } else {
92
+ return string;
93
+ }
94
+ },
95
+ stripHTML: function(string) {
96
+ if (typeof string === "undefined" || string === null) {
97
+ return '';
98
+ }
99
+ return string.replace(/(<([^>]+)>)|nbsp;|\s{2,}|/ig, "");
100
+ }
101
+ };
102
+
103
+ function SocialFeedPost(social_network, data) {
104
+ this.content = data;
105
+ this.content.social_network = social_network;
106
+ this.content.attachment = (this.content.attachment === undefined) ? '' : this.content.attachment;
107
+ this.content.time_ago = data.dt_create.locale(options.date_locale).fromNow();
108
+ this.content.date = data.dt_create.locale(options.date_locale).format(options.date_format);
109
+ this.content.dt_create = this.content.dt_create.valueOf();
110
+ this.content.text = Utility.wrapLinks(Utility.shorten(data.message + ' ' + data.description), data.social_network);
111
+ this.content.moderation_passed = (options.moderation) ? options.moderation(this.content) : true;
112
+
113
+ Feed[social_network].posts.push(this);
114
+ }
115
+ SocialFeedPost.prototype = {
116
+ render: function() {
117
+ var rendered_html = Feed.template(this.content);
118
+ var data = this.content;
119
+
120
+ if ($(container).children('[social-feed-id=' + data.id + ']').length !== 0) {
121
+ return false;
122
+ }
123
+ if ($(container).children().length === 0) {
124
+ $(container).append(rendered_html);
125
+ } else {
126
+ var i = 0,
127
+ insert_index = -1;
128
+ $.each($(container).children(), function() {
129
+ if ($(this).attr('dt-create') < data.dt_create) {
130
+ insert_index = i;
131
+ return false;
132
+ }
133
+ i++;
134
+ });
135
+ $(container).append(rendered_html);
136
+ if (insert_index >= 0) {
137
+ insert_index++;
138
+ var before = $(container).children('div:nth-child(' + insert_index + ')'),
139
+ current = $(container).children('div:last-child');
140
+ $(current).insertBefore(before);
141
+ }
142
+
143
+ }
144
+ if (options.media_min_width) {
145
+
146
+ var query = '[social-feed-id=' + data.id + '] img.attachment';
147
+ var image = $(query);
148
+
149
+ // preload the image
150
+ var height, width = '';
151
+ var img = new Image();
152
+ var imgSrc = image.attr("src");
153
+
154
+ $(img).load(function() {
155
+
156
+ if (img.width < options.media_min_width) {
157
+ image.hide();
158
+ }
159
+ // garbage collect img
160
+ delete img;
161
+
162
+ }).error(function() {
163
+ // image couldnt be loaded
164
+ image.hide();
165
+
166
+ }).attr({
167
+ src: imgSrc
168
+ });
169
+
170
+ }
171
+
172
+ loaded_post_count++;
173
+ if (loaded_post_count == posts_to_load_count) {
174
+ fireCallback();
175
+ }
176
+
177
+ }
178
+
179
+ };
180
+
181
+ var Feed = {
182
+ template: false,
183
+ init: function() {
184
+ Feed.getTemplate(function() {
185
+ social_networks.forEach(function(network) {
186
+ if (options[network]) {
187
+ if ( options[network].accounts ) {
188
+ //loaded[network] = 0;
189
+ options[network].accounts.forEach(function(account) {
190
+ //loaded[network]++;
191
+ Feed[network].getData(account);
192
+ });
193
+ } else if ( options[network].urls ) {
194
+ options[network].urls.forEach(function(url) {
195
+ Feed[network].getData(url);
196
+ });
197
+ } else {
198
+ Feed[network].getData();
199
+ }
200
+ }
201
+ });
202
+ });
203
+ },
204
+ getTemplate: function(callback) {
205
+ if (Feed.template)
206
+ return callback();
207
+ else {
208
+ if (options.template_html) {
209
+ Feed.template = doT.template(options.template_html);
210
+ return callback();
211
+ } else {
212
+ $.get(options.template, function(template_html) {
213
+ Feed.template = doT.template(template_html);
214
+ return callback();
215
+ });
216
+ }
217
+ }
218
+ },
219
+ twitter: {
220
+ posts: [],
221
+ loaded: false,
222
+ api: 'http://api.tweecool.com/',
223
+
224
+ getData: function(account) {
225
+
226
+ var cb = new Codebird();
227
+ cb.setConsumerKey(options.twitter.consumer_key, options.twitter.consumer_secret);
228
+
229
+ // Allow setting your own proxy with Codebird
230
+ if (options.twitter.proxy !== undefined) {
231
+ cb.setProxy(options.twitter.proxy);
232
+ }
233
+
234
+ switch (account[0]) {
235
+ case '@':
236
+ var userid = account.substr(1);
237
+ cb.__call(
238
+ "statuses_userTimeline",
239
+ "id=" + userid + "&count=" + options.twitter.limit,
240
+ Feed.twitter.utility.getPosts,
241
+ true // this parameter required
242
+ );
243
+ break;
244
+ case '#':
245
+ var hashtag = account.substr(1);
246
+ cb.__call(
247
+ "search_tweets",
248
+ "q=" + hashtag + "&count=" + options.twitter.limit,
249
+ function(reply) {
250
+ Feed.twitter.utility.getPosts(reply.statuses);
251
+ },
252
+ true // this parameter required
253
+ );
254
+ break;
255
+ default:
256
+ }
257
+ },
258
+ utility: {
259
+ getPosts: function(json) {
260
+ if (json) {
261
+ $.each(json, function() {
262
+ var element = this;
263
+ var post = new SocialFeedPost('twitter', Feed.twitter.utility.unifyPostData(element));
264
+ post.render();
265
+ });
266
+ }
267
+ },
268
+ unifyPostData: function(element) {
269
+ var post = {};
270
+ if (element.id) {
271
+ post.id = element.id_str;
272
+ //prevent a moment.js console warning due to Twitter's poor date format.
273
+ post.dt_create = moment(element.created_at, 'dd MMM DD HH:mm:ss ZZ YYYY');
274
+ post.author_link = 'http://twitter.com/' + element.user.screen_name;
275
+ post.author_picture = element.user.profile_image_url_https;
276
+ post.post_url = post.author_link + '/status/' + element.id_str;
277
+ post.author_name = element.user.name;
278
+ post.message = element.text;
279
+ post.description = '';
280
+ post.link = 'http://twitter.com/' + element.user.screen_name + '/status/' + element.id_str;
281
+
282
+ if (options.show_media === true) {
283
+ if (element.entities.media && element.entities.media.length > 0) {
284
+ var image_url = element.entities.media[0].media_url_https;
285
+ if (image_url) {
286
+ post.attachment = '<img class="attachment" src="' + image_url + '" />';
287
+ }
288
+ }
289
+ }
290
+ }
291
+ return post;
292
+ }
293
+ }
294
+ },
295
+ facebook: {
296
+ posts: [],
297
+ graph: 'https://graph.facebook.com/',
298
+ loaded: false,
299
+ getData: function(account) {
300
+ var proceed = function(request_url){
301
+ Utility.request(request_url, Feed.facebook.utility.getPosts);
302
+ };
303
+ var fields = '?fields=id,from,name,message,created_time,story,description,link';
304
+ fields += (options.show_media === true)?',picture,object_id':'';
305
+ var request_url, limit = '&limit=' + options.facebook.limit,
306
+ query_extention = '&access_token=' + options.facebook.access_token + '&callback=?';
307
+ switch (account[0]) {
308
+ case '@':
309
+ var username = account.substr(1);
310
+ Feed.facebook.utility.getUserId(username, function(userdata) {
311
+ if (userdata.id !== '') {
312
+ request_url = Feed.facebook.graph + 'v2.4/' + userdata.id + '/posts'+ fields + limit + query_extention;
313
+ proceed(request_url);
314
+ }
315
+ });
316
+ break;
317
+ case '!':
318
+ var page = account.substr(1);
319
+ request_url = Feed.facebook.graph + 'v2.4/' + page + '/feed'+ fields + limit + query_extention;
320
+ proceed(request_url);
321
+ break;
322
+ default:
323
+ proceed(request_url);
324
+ }
325
+ },
326
+ utility: {
327
+ getUserId: function(username, callback) {
328
+ var query_extention = '&access_token=' + options.facebook.access_token + '&callback=?';
329
+ var url = 'https://graph.facebook.com/' + username + '?' + query_extention;
330
+ var result = '';
331
+ $.get(url, callback, 'json');
332
+ },
333
+ prepareAttachment: function(element) {
334
+ var image_url = element.picture;
335
+ if (image_url.indexOf('_b.') !== -1) {
336
+ //do nothing it is already big
337
+ } else if (image_url.indexOf('safe_image.php') !== -1) {
338
+ image_url = Feed.facebook.utility.getExternalImageURL(image_url, 'url');
339
+
340
+ } else if (image_url.indexOf('app_full_proxy.php') !== -1) {
341
+ image_url = Feed.facebook.utility.getExternalImageURL(image_url, 'src');
342
+
343
+ } else if (element.object_id) {
344
+ image_url = Feed.facebook.graph + element.object_id + '/picture/?type=normal';
345
+ }
346
+ return '<img class="attachment" src="' + image_url + '" />';
347
+ },
348
+ getExternalImageURL: function(image_url, parameter) {
349
+ image_url = decodeURIComponent(image_url).split(parameter + '=')[1];
350
+ if (image_url.indexOf('fbcdn-sphotos') === -1) {
351
+ return image_url.split('&')[0];
352
+ } else {
353
+ return image_url;
354
+ }
355
+
356
+ },
357
+ getPosts: function(json) {
358
+ if (json['data']) {
359
+ json['data'].forEach(function(element) {
360
+ var post = new SocialFeedPost('facebook', Feed.facebook.utility.unifyPostData(element));
361
+ post.render();
362
+ });
363
+ }
364
+ },
365
+ unifyPostData: function(element) {
366
+ var post = {},
367
+ text = (element.message) ? element.message : element.story;
368
+
369
+ post.id = element.id;
370
+ post.dt_create = moment(element.created_time);
371
+ post.author_link = 'http://facebook.com/' + element.from.id;
372
+ post.author_picture = Feed.facebook.graph + element.from.id + '/picture';
373
+ post.author_name = element.from.name;
374
+ post.name = element.name || "";
375
+ post.message = (text) ? text : '';
376
+ post.description = (element.description) ? element.description : '';
377
+ post.link = (element.link) ? element.link : 'http://facebook.com/' + element.from.id;
378
+
379
+ if (options.show_media === true) {
380
+ if (element.picture) {
381
+ var attachment = Feed.facebook.utility.prepareAttachment(element);
382
+ if (attachment) {
383
+ post.attachment = attachment;
384
+ }
385
+ }
386
+ }
387
+ return post;
388
+ }
389
+ }
390
+ },
391
+ google: {
392
+ posts: [],
393
+ loaded: false,
394
+ api: 'https://www.googleapis.com/plus/v1/',
395
+ getData: function(account) {
396
+ var request_url;
397
+ switch (account[0]) {
398
+ case '#':
399
+ var hashtag = account.substr(1);
400
+ request_url = Feed.google.api + 'activities?query=' + hashtag + '&key=' + options.google.access_token + '&maxResults=' + options.google.limit;
401
+ Utility.get_request(request_url, Feed.google.utility.getPosts);
402
+ break;
403
+ case '@':
404
+ var username = account.substr(1);
405
+ request_url = Feed.google.api + 'people/' + username + '/activities/public?key=' + options.google.access_token + '&maxResults=' + options.google.limit;
406
+ Utility.get_request(request_url, Feed.google.utility.getPosts);
407
+ break;
408
+ default:
409
+ }
410
+ },
411
+ utility: {
412
+ getPosts: function(json) {
413
+ if (json.items) {
414
+ $.each(json.items, function(i) {
415
+ var post = new SocialFeedPost('google', Feed.google.utility.unifyPostData(json.items[i]));
416
+ post.render();
417
+ });
418
+ }
419
+ },
420
+ unifyPostData: function(element) {
421
+ var post = {};
422
+
423
+ post.id = element.id;
424
+ post.attachment = '';
425
+ post.description = '';
426
+ post.dt_create = moment(element.published);
427
+ post.author_link = element.actor.url;
428
+ post.author_picture = element.actor.image.url;
429
+ post.author_name = element.actor.displayName;
430
+
431
+ if (options.show_media === true) {
432
+ if (element.object.attachments) {
433
+ $.each(element.object.attachments, function() {
434
+ var image = '';
435
+ if (this.fullImage) {
436
+ image = this.fullImage.url;
437
+ } else {
438
+ if (this.objectType === 'album') {
439
+ if (this.thumbnails && this.thumbnails.length > 0) {
440
+ if (this.thumbnails[0].image) {
441
+ image = this.thumbnails[0].image.url;
442
+ }
443
+ }
444
+ }
445
+ }
446
+ post.attachment = '<img class="attachment" src="' + image + '"/>';
447
+ });
448
+ }
449
+ }
450
+ post.message = element.title;
451
+ post.link = element.url;
452
+
453
+ return post;
454
+ }
455
+ }
456
+ },
457
+ instagram: {
458
+ posts: [],
459
+ api: 'https://api.instagram.com/v1/',
460
+ loaded: false,
461
+ accessType: function() {
462
+ // If we have both the client_id and access_token set in options,
463
+ // use access_token for authentication. If client_id is not set
464
+ // then use access_token. If neither are set, log an error to console.
465
+ if (typeof options.instagram.access_token === 'undefined' && typeof options.instagram.client_id === 'undefined') {
466
+ console.log('You need to define a client_id or access_token to authenticate with Instagram\'s API.');
467
+ return undefined;
468
+ }
469
+ if (options.instagram.access_token) { options.instagram.client_id = undefined; }
470
+ options.instagram.access_type = (typeof options.instagram.client_id === 'undefined' ? 'access_token' : 'client_id');
471
+ return options.instagram.access_type;
472
+ },
473
+ getData: function(account) {
474
+ var url;
475
+
476
+ // API endpoint URL depends on which authentication type we're using.
477
+ if (this.accessType() !== 'undefined') {
478
+ var authTokenParams = options.instagram.access_type + '=' + options.instagram[options.instagram.access_type];
479
+ }
480
+
481
+ switch (account[0]) {
482
+ case '@':
483
+ var username = account.substr(1);
484
+ url = Feed.instagram.api + 'users/search/?q=' + username + '&' + authTokenParams + '&count=1' + '&callback=?';
485
+ Utility.request(url, Feed.instagram.utility.getUsers);
486
+ break;
487
+ case '#':
488
+ var hashtag = account.substr(1);
489
+ url = Feed.instagram.api + 'tags/' + hashtag + '/media/recent/?' + authTokenParams + '&' + 'count=' + options.instagram.limit + '&callback=?';
490
+ Utility.request(url, Feed.instagram.utility.getImages);
491
+ break;
492
+ case '&':
493
+ var id = account.substr(1);
494
+ url = Feed.instagram.api + 'users/' + id + '/?' + authTokenParams + '&' + 'count=' + options.instagram.limit + '&callback=?';
495
+ Utility.request(url, Feed.instagram.utility.getUsers);
496
+ default:
497
+ }
498
+ },
499
+ utility: {
500
+ getImages: function(json) {
501
+ if (json.data) {
502
+ json.data.forEach(function(element) {
503
+ var post = new SocialFeedPost('instagram', Feed.instagram.utility.unifyPostData(element));
504
+ post.render();
505
+ });
506
+ }
507
+ },
508
+ getUsers: function(json) {
509
+ // API endpoint URL depends on which authentication type we're using.
510
+ if (options.instagram.access_type !== 'undefined') {
511
+ var authTokenParams = options.instagram.access_type + '=' + options.instagram[options.instagram.access_type];
512
+ }
513
+
514
+ if (!jQuery.isArray(json.data)) json.data = [json.data]
515
+ json.data.forEach(function(user) {
516
+ var url = Feed.instagram.api + 'users/' + user.id + '/media/recent/?' + authTokenParams + '&' + 'count=' + options.instagram.limit + '&callback=?';
517
+ Utility.request(url, Feed.instagram.utility.getImages);
518
+ });
519
+ },
520
+ unifyPostData: function(element) {
521
+ var post = {};
522
+
523
+ post.id = element.id;
524
+ post.dt_create = moment(element.created_time * 1000);
525
+ post.author_link = 'http://instagram.com/' + element.user.username;
526
+ post.author_picture = element.user.profile_picture;
527
+ post.author_name = element.user.full_name || element.user.username;
528
+ post.message = (element.caption && element.caption) ? element.caption.text : '';
529
+ post.description = '';
530
+ post.link = element.link;
531
+ if (options.show_media) {
532
+ post.attachment = '<img class="attachment" src="' + element.images.standard_resolution.url + '' + '" />';
533
+ }
534
+ return post;
535
+ }
536
+ }
537
+ },
538
+ vk: {
539
+ posts: [],
540
+ loaded: false,
541
+ base: 'http://vk.com/',
542
+ api: 'https://api.vk.com/method/',
543
+ user_json_template: 'https://api.vk.com/method/' + 'users.get?fields=first_name,%20last_name,%20screen_name,%20photo&uid=',
544
+ group_json_template: 'https://api.vk.com/method/' + 'groups.getById?fields=first_name,%20last_name,%20screen_name,%20photo&gid=',
545
+ getData: function(account) {
546
+ var request_url;
547
+
548
+ switch (account[0]) {
549
+ case '@':
550
+ var username = account.substr(1);
551
+ request_url = Feed.vk.api + 'wall.get?owner_id=' + username + '&filter=' + options.vk.source + '&count=' + options.vk.limit + '&callback=?';
552
+ Utility.get_request(request_url, Feed.vk.utility.getPosts);
553
+ break;
554
+ case '#':
555
+ var hashtag = account.substr(1);
556
+ request_url = Feed.vk.api + 'newsfeed.search?q=' + hashtag + '&count=' + options.vk.limit + '&callback=?';
557
+ Utility.get_request(request_url, Feed.vk.utility.getPosts);
558
+ break;
559
+ default:
560
+ }
561
+ },
562
+ utility: {
563
+ getPosts: function(json) {
564
+ if (json.response) {
565
+ $.each(json.response, function() {
566
+ if (this != parseInt(this) && this.post_type === 'post') {
567
+ var owner_id = (this.owner_id) ? this.owner_id : this.from_id,
568
+ vk_wall_owner_url = (owner_id > 0) ? (Feed.vk.user_json_template + owner_id + '&callback=?') : (Feed.vk.group_json_template + (-1) * owner_id + '&callback=?'),
569
+ element = this;
570
+ Utility.get_request(vk_wall_owner_url, function(wall_owner) {
571
+ Feed.vk.utility.unifyPostData(wall_owner, element, json);
572
+ });
573
+ }
574
+ });
575
+ }
576
+ },
577
+ unifyPostData: function(wall_owner, element, json) {
578
+ var post = {};
579
+
580
+ post.id = element.id;
581
+ post.dt_create = moment.unix(element.date);
582
+ post.description = ' ';
583
+ post.message = Utility.stripHTML(element.text);
584
+ if (options.show_media) {
585
+ if (element.attachment) {
586
+ if (element.attachment.type === 'link')
587
+ post.attachment = '<img class="attachment" src="' + element.attachment.link.image_src + '" />';
588
+ if (element.attachment.type === 'video')
589
+ post.attachment = '<img class="attachment" src="' + element.attachment.video.image_big + '" />';
590
+ if (element.attachment.type === 'photo')
591
+ post.attachment = '<img class="attachment" src="' + element.attachment.photo.src_big + '" />';
592
+ }
593
+ }
594
+
595
+ if (element.from_id > 0) {
596
+ var vk_user_json = Feed.vk.user_json_template + element.from_id + '&callback=?';
597
+ Utility.get_request(vk_user_json, function(user_json) {
598
+ var vk_post = new SocialFeedPost('vk', Feed.vk.utility.getUser(user_json, post, element, json));
599
+ vk_post.render();
600
+ });
601
+
602
+ } else {
603
+ var vk_group_json = Feed.vk.group_json_template + (-1) * element.from_id + '&callback=?';
604
+ Utility.get_request(vk_group_json, function(user_json) {
605
+ var vk_post = new SocialFeedPost('vk', Feed.vk.utility.getGroup(user_json, post, element, json));
606
+ vk_post.render();
607
+ });
608
+ }
609
+ },
610
+ getUser: function(user_json, post, element, json) {
611
+ post.author_name = user_json.response[0].first_name + ' ' + user_json.response[0].last_name;
612
+ post.author_picture = user_json.response[0].photo;
613
+ post.author_link = Feed.vk.base + user_json.response[0].screen_name;
614
+ post.link = Feed.vk.base + user_json.response[0].screen_name + '?w=wall' + element.from_id + '_' + element.id;
615
+
616
+ return post;
617
+ },
618
+ getGroup: function(user_json, post, element, json) {
619
+ post.author_name = user_json.response[0].name;
620
+ post.author_picture = user_json.response[0].photo;
621
+ post.author_link = Feed.vk.base + user_json.response[0].screen_name;
622
+ post.link = Feed.vk.base + user_json.response[0].screen_name + '?w=wall-' + user_json.response[0].gid + '_' + element.id;
623
+
624
+ return post;
625
+ }
626
+ }
627
+ },
628
+ blogspot: {
629
+ loaded: false,
630
+ getData: function(account) {
631
+ var url;
632
+
633
+ switch (account[0]) {
634
+ case '@':
635
+ var username = account.substr(1);
636
+ url = 'http://' + username + '.blogspot.com/feeds/posts/default?alt=json-in-script&callback=?';
637
+ request(url, getPosts);
638
+ break;
639
+ default:
640
+ }
641
+ },
642
+ utility: {
643
+ getPosts: function(json) {
644
+ $.each(json.feed.entry, function() {
645
+ var post = {},
646
+ element = this;
647
+ post.id = element.id['$t'].replace(/[^a-z0-9]/gi, '');
648
+ post.dt_create = moment((element.published['$t']));
649
+ post.author_link = element.author[0]['uri']['$t'];
650
+ post.author_picture = 'http:' + element.author[0]['gd$image']['src'];
651
+ post.author_name = element.author[0]['name']['$t'];
652
+ post.message = element.title['$t'] + '</br></br>' + stripHTML(element.content['$t']);
653
+ post.description = '';
654
+ post.link = element.link.pop().href;
655
+
656
+ if (options.show_media) {
657
+ if (element['media$thumbnail']) {
658
+ post.attachment = '<img class="attachment" src="' + element['media$thumbnail']['url'] + '" />';
659
+ }
660
+ }
661
+
662
+ post.render();
663
+
664
+ });
665
+ }
666
+ }
667
+ },
668
+ pinterest: {
669
+ posts: [],
670
+ loaded: false,
671
+ apiv1: 'https://api.pinterest.com/v1/',
672
+
673
+ getData: function(account) {
674
+ var request_url,
675
+ limit = 'limit=' + options.pinterest.limit,
676
+ fields = 'fields=id,created_at,link,note,creator(url,first_name,last_name,image),image',
677
+ query_extention = fields + '&access_token=' + options.pinterest.access_token + '&' + limit + '&callback=?';
678
+ switch (account[0]) {
679
+ case '@':
680
+ var username = account.substr(1);
681
+ if (username === 'me') {
682
+ request_url = Feed.pinterest.apiv1 + 'me/pins/?' + query_extention;
683
+ } else {
684
+ request_url = Feed.pinterest.apiv1 + 'boards/' + username + '/pins?' + query_extention;
685
+ }
686
+ break;
687
+ default:
688
+ }
689
+ Utility.request(request_url, Feed.pinterest.utility.getPosts);
690
+ },
691
+ utility: {
692
+
693
+ getPosts: function(json) {
694
+ json.data.forEach(function(element) {
695
+ var post = new SocialFeedPost('pinterest', Feed.pinterest.utility.unifyPostData(element));
696
+ post.render();
697
+ });
698
+ },
699
+
700
+ unifyPostData: function(element){
701
+ var post = {};
702
+
703
+ post.id = element.id;
704
+ post.dt_create= moment(element.created_at);
705
+ post.author_link = element.creator.url;
706
+ post.author_picture = element.creator.image['60x60' ].url;
707
+ post.author_name = element.creator.first_name + element.creator.last_name;
708
+ post.message = element.note;
709
+ post.description = '';
710
+ post.social_network = 'pinterest';
711
+ post.link = element.link ? element.link : 'https://www.pinterest.com/pin/' + element.id;
712
+ if (options.show_media) {
713
+ post.attachment = '<img class="attachment" src="' + element.image['original'].url + '" />';
714
+ }
715
+ return post;
716
+ }
717
+ }
718
+ },
719
+ rss : {
720
+ posts: [],
721
+ loaded: false,
722
+ api : 'https://query.yahooapis.com/v1/public/yql?q=',
723
+ datatype: 'json',
724
+
725
+ getData: function(url) {
726
+ var limit = options.rss.limit,
727
+ yql = encodeURIComponent('select entry FROM feednormalizer where url=\'' + url + '\' AND output=\'atom_1.0\' | truncate(count=' + limit + ')' ),
728
+ request_url = Feed.rss.api + yql + '&format=json&callback=?';
729
+
730
+ Utility.request(request_url, Feed.rss.utility.getPosts, Feed.rss.datatype);
731
+ },
732
+ utility: {
733
+
734
+ getPosts: function(json) {
735
+ console.log(json);
736
+ if (json.query.count > 0 ){
737
+ $.each(json.query.results.feed, function(index, element) {
738
+ var post = new SocialFeedPost('rss', Feed.rss.utility.unifyPostData(index, element));
739
+ post.render();
740
+ });
741
+ }
742
+ },
743
+
744
+ unifyPostData: function(index, element){
745
+
746
+ var item = element;
747
+
748
+ if ( element.entry !== undefined ){
749
+ item = element.entry;
750
+ }
751
+ var post = {};
752
+
753
+ post.id = '"' + item.id + '"';
754
+ post.dt_create= moment(item.published, 'YYYY-MM-DDTHH:mm:ssZ', 'en');
755
+
756
+ post.author_link = '';
757
+ post.author_picture = '';
758
+ post.author_name = '';
759
+ if( item.creator !== undefined ){
760
+ post.author_name = item.creator;
761
+ }
762
+ post.message = item.title;
763
+ post.description = '';
764
+ if( item.summary !== undefined ){
765
+ post.description = Utility.stripHTML(item.summary.content);
766
+ }
767
+ post.social_network = 'rss';
768
+ post.link = item.link.href;
769
+ if (options.show_media && item.thumbnail !== undefined ) {
770
+ post.attachment = '<img class="attachment" src="' + item.thumbnail.url + '" />';
771
+ }
772
+ return post;
773
+ }
774
+ }
775
+ }
776
+ };
777
+
778
+ //make the plugin chainable
779
+ return this.each(function() {
780
+ // Initialization
781
+ Feed.init();
782
+ if (options.update_period) {
783
+ setInterval(function() {
784
+ return Feed.init();
785
+ }, options.update_period);
786
+ }
787
+ })
788
+ };
789
+
790
+ })(jQuery);
assets/social-feeds/moment.js ADDED
@@ -0,0 +1,4515 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //! moment.js
2
+ //! version : 2.19.3
3
+ //! authors : Tim Wood, Iskren Chernev, Moment.js contributors
4
+ //! license : MIT
5
+ //! momentjs.com
6
+
7
+ ;(function (global, factory) {
8
+ typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
9
+ typeof define === 'function' && define.amd ? define(factory) :
10
+ global.moment = factory()
11
+ }(this, (function () { 'use strict';
12
+
13
+ var hookCallback;
14
+
15
+ function hooks () {
16
+ return hookCallback.apply(null, arguments);
17
+ }
18
+
19
+ // This is done to register the method called with moment()
20
+ // without creating circular dependencies.
21
+ function setHookCallback (callback) {
22
+ hookCallback = callback;
23
+ }
24
+
25
+ function isArray(input) {
26
+ return input instanceof Array || Object.prototype.toString.call(input) === '[object Array]';
27
+ }
28
+
29
+ function isObject(input) {
30
+ // IE8 will treat undefined and null as object if it wasn't for
31
+ // input != null
32
+ return input != null && Object.prototype.toString.call(input) === '[object Object]';
33
+ }
34
+
35
+ function isObjectEmpty(obj) {
36
+ if (Object.getOwnPropertyNames) {
37
+ return (Object.getOwnPropertyNames(obj).length === 0);
38
+ } else {
39
+ var k;
40
+ for (k in obj) {
41
+ if (obj.hasOwnProperty(k)) {
42
+ return false;
43
+ }
44
+ }
45
+ return true;
46
+ }
47
+ }
48
+
49
+ function isUndefined(input) {
50
+ return input === void 0;
51
+ }
52
+
53
+ function isNumber(input) {
54
+ return typeof input === 'number' || Object.prototype.toString.call(input) === '[object Number]';
55
+ }
56
+
57
+ function isDate(input) {
58
+ return input instanceof Date || Object.prototype.toString.call(input) === '[object Date]';
59
+ }
60
+
61
+ function map(arr, fn) {
62
+ var res = [], i;
63
+ for (i = 0; i < arr.length; ++i) {
64
+ res.push(fn(arr[i], i));
65
+ }
66
+ return res;
67
+ }
68
+
69
+ function hasOwnProp(a, b) {
70
+ return Object.prototype.hasOwnProperty.call(a, b);
71
+ }
72
+
73
+ function extend(a, b) {
74
+ for (var i in b) {
75
+ if (hasOwnProp(b, i)) {
76
+ a[i] = b[i];
77
+ }
78
+ }
79
+
80
+ if (hasOwnProp(b, 'toString')) {
81
+ a.toString = b.toString;
82
+ }
83
+
84
+ if (hasOwnProp(b, 'valueOf')) {
85
+ a.valueOf = b.valueOf;
86
+ }
87
+
88
+ return a;
89
+ }
90
+
91
+ function createUTC (input, format, locale, strict) {
92
+ return createLocalOrUTC(input, format, locale, strict, true).utc();
93
+ }
94
+
95
+ function defaultParsingFlags() {
96
+ // We need to deep clone this object.
97
+ return {
98
+ empty : false,
99
+ unusedTokens : [],
100
+ unusedInput : [],
101
+ overflow : -2,
102
+ charsLeftOver : 0,
103
+ nullInput : false,
104
+ invalidMonth : null,
105
+ invalidFormat : false,
106
+ userInvalidated : false,
107
+ iso : false,
108
+ parsedDateParts : [],
109
+ meridiem : null,
110
+ rfc2822 : false,
111
+ weekdayMismatch : false
112
+ };
113
+ }
114
+
115
+ function getParsingFlags(m) {
116
+ if (m._pf == null) {
117
+ m._pf = defaultParsingFlags();
118
+ }
119
+ return m._pf;
120
+ }
121
+
122
+ var some;
123
+ if (Array.prototype.some) {
124
+ some = Array.prototype.some;
125
+ } else {
126
+ some = function (fun) {
127
+ var t = Object(this);
128
+ var len = t.length >>> 0;
129
+
130
+ for (var i = 0; i < len; i++) {
131
+ if (i in t && fun.call(this, t[i], i, t)) {
132
+ return true;
133
+ }
134
+ }
135
+
136
+ return false;
137
+ };
138
+ }
139
+
140
+ function isValid(m) {
141
+ if (m._isValid == null) {
142
+ var flags = getParsingFlags(m);
143
+ var parsedParts = some.call(flags.parsedDateParts, function (i) {
144
+ return i != null;
145
+ });
146
+ var isNowValid = !isNaN(m._d.getTime()) &&
147
+ flags.overflow < 0 &&
148
+ !flags.empty &&
149
+ !flags.invalidMonth &&
150
+ !flags.invalidWeekday &&
151
+ !flags.weekdayMismatch &&
152
+ !flags.nullInput &&
153
+ !flags.invalidFormat &&
154
+ !flags.userInvalidated &&
155
+ (!flags.meridiem || (flags.meridiem && parsedParts));
156
+
157
+ if (m._strict) {
158
+ isNowValid = isNowValid &&
159
+ flags.charsLeftOver === 0 &&
160
+ flags.unusedTokens.length === 0 &&
161
+ flags.bigHour === undefined;
162
+ }
163
+
164
+ if (Object.isFrozen == null || !Object.isFrozen(m)) {
165
+ m._isValid = isNowValid;
166
+ }
167
+ else {
168
+ return isNowValid;
169
+ }
170
+ }
171
+ return m._isValid;
172
+ }
173
+
174
+ function createInvalid (flags) {
175
+ var m = createUTC(NaN);
176
+ if (flags != null) {
177
+ extend(getParsingFlags(m), flags);
178
+ }
179
+ else {
180
+ getParsingFlags(m).userInvalidated = true;
181
+ }
182
+
183
+ return m;
184
+ }
185
+
186
+ // Plugins that add properties should also add the key here (null value),
187
+ // so we can properly clone ourselves.
188
+ var momentProperties = hooks.momentProperties = [];
189
+
190
+ function copyConfig(to, from) {
191
+ var i, prop, val;
192
+
193
+ if (!isUndefined(from._isAMomentObject)) {
194
+ to._isAMomentObject = from._isAMomentObject;
195
+ }
196
+ if (!isUndefined(from._i)) {
197
+ to._i = from._i;
198
+ }
199
+ if (!isUndefined(from._f)) {
200
+ to._f = from._f;
201
+ }
202
+ if (!isUndefined(from._l)) {
203
+ to._l = from._l;
204
+ }
205
+ if (!isUndefined(from._strict)) {
206
+ to._strict = from._strict;
207
+ }
208
+ if (!isUndefined(from._tzm)) {
209
+ to._tzm = from._tzm;
210
+ }
211
+ if (!isUndefined(from._isUTC)) {
212
+ to._isUTC = from._isUTC;
213
+ }
214
+ if (!isUndefined(from._offset)) {
215
+ to._offset = from._offset;
216
+ }
217
+ if (!isUndefined(from._pf)) {
218
+ to._pf = getParsingFlags(from);
219
+ }
220
+ if (!isUndefined(from._locale)) {
221
+ to._locale = from._locale;
222
+ }
223
+
224
+ if (momentProperties.length > 0) {
225
+ for (i = 0; i < momentProperties.length; i++) {
226
+ prop = momentProperties[i];
227
+ val = from[prop];
228
+ if (!isUndefined(val)) {
229
+ to[prop] = val;
230
+ }
231
+ }
232
+ }
233
+
234
+ return to;
235
+ }
236
+
237
+ var updateInProgress = false;
238
+
239
+ // Moment prototype object
240
+ function Moment(config) {
241
+ copyConfig(this, config);
242
+ this._d = new Date(config._d != null ? config._d.getTime() : NaN);
243
+ if (!this.isValid()) {
244
+ this._d = new Date(NaN);
245
+ }
246
+ // Prevent infinite loop in case updateOffset creates new moment
247
+ // objects.
248
+ if (updateInProgress === false) {
249
+ updateInProgress = true;
250
+ hooks.updateOffset(this);
251
+ updateInProgress = false;
252
+ }
253
+ }
254
+
255
+ function isMoment (obj) {
256
+ return obj instanceof Moment || (obj != null && obj._isAMomentObject != null);
257
+ }
258
+
259
+ function absFloor (number) {
260
+ if (number < 0) {
261
+ // -0 -> 0
262
+ return Math.ceil(number) || 0;
263
+ } else {
264
+ return Math.floor(number);
265
+ }
266
+ }
267
+
268
+ function toInt(argumentForCoercion) {
269
+ var coercedNumber = +argumentForCoercion,
270
+ value = 0;
271
+
272
+ if (coercedNumber !== 0 && isFinite(coercedNumber)) {
273
+ value = absFloor(coercedNumber);
274
+ }
275
+
276
+ return value;
277
+ }
278
+
279
+ // compare two arrays, return the number of differences
280
+ function compareArrays(array1, array2, dontConvert) {
281
+ var len = Math.min(array1.length, array2.length),
282
+ lengthDiff = Math.abs(array1.length - array2.length),
283
+ diffs = 0,
284
+ i;
285
+ for (i = 0; i < len; i++) {
286
+ if ((dontConvert && array1[i] !== array2[i]) ||
287
+ (!dontConvert && toInt(array1[i]) !== toInt(array2[i]))) {
288
+ diffs++;
289
+ }
290
+ }
291
+ return diffs + lengthDiff;
292
+ }
293
+
294
+ function warn(msg) {
295
+ if (hooks.suppressDeprecationWarnings === false &&
296
+ (typeof console !== 'undefined') && console.warn) {
297
+ console.warn('Deprecation warning: ' + msg);
298
+ }
299
+ }
300
+
301
+ function deprecate(msg, fn) {
302
+ var firstTime = true;
303
+
304
+ return extend(function () {
305
+ if (hooks.deprecationHandler != null) {
306
+ hooks.deprecationHandler(null, msg);
307
+ }
308
+ if (firstTime) {
309
+ var args = [];
310
+ var arg;
311
+ for (var i = 0; i < arguments.length; i++) {
312
+ arg = '';
313
+ if (typeof arguments[i] === 'object') {
314
+ arg += '\n[' + i + '] ';
315
+ for (var key in arguments[0]) {
316
+ arg += key + ': ' + arguments[0][key] + ', ';
317
+ }
318
+ arg = arg.slice(0, -2); // Remove trailing comma and space
319
+ } else {
320
+ arg = arguments[i];
321
+ }
322
+ args.push(arg);
323
+ }
324
+ warn(msg + '\nArguments: ' + Array.prototype.slice.call(args).join('') + '\n' + (new Error()).stack);
325
+ firstTime = false;
326
+ }
327
+ return fn.apply(this, arguments);
328
+ }, fn);
329
+ }
330
+
331
+ var deprecations = {};
332
+
333
+ function deprecateSimple(name, msg) {
334
+ if (hooks.deprecationHandler != null) {
335
+ hooks.deprecationHandler(name, msg);
336
+ }
337
+ if (!deprecations[name]) {
338
+ warn(msg);
339
+ deprecations[name] = true;
340
+ }
341
+ }
342
+
343
+ hooks.suppressDeprecationWarnings = false;
344
+ hooks.deprecationHandler = null;
345
+
346
+ function isFunction(input) {
347
+ return input instanceof Function || Object.prototype.toString.call(input) === '[object Function]';
348
+ }
349
+
350
+ function set (config) {
351
+ var prop, i;
352
+ for (i in config) {
353
+ prop = config[i];
354
+ if (isFunction(prop)) {
355
+ this[i] = prop;
356
+ } else {
357
+ this['_' + i] = prop;
358
+ }
359
+ }
360
+ this._config = config;
361
+ // Lenient ordinal parsing accepts just a number in addition to
362
+ // number + (possibly) stuff coming from _dayOfMonthOrdinalParse.
363
+ // TODO: Remove "ordinalParse" fallback in next major release.
364
+ this._dayOfMonthOrdinalParseLenient = new RegExp(
365
+ (this._dayOfMonthOrdinalParse.source || this._ordinalParse.source) +
366
+ '|' + (/\d{1,2}/).source);
367
+ }
368
+
369
+ function mergeConfigs(parentConfig, childConfig) {
370
+ var res = extend({}, parentConfig), prop;
371
+ for (prop in childConfig) {
372
+ if (hasOwnProp(childConfig, prop)) {
373
+ if (isObject(parentConfig[prop]) && isObject(childConfig[prop])) {
374
+ res[prop] = {};
375
+ extend(res[prop], parentConfig[prop]);
376
+ extend(res[prop], childConfig[prop]);
377
+ } else if (childConfig[prop] != null) {
378
+ res[prop] = childConfig[prop];
379
+ } else {
380
+ delete res[prop];
381
+ }
382
+ }
383
+ }
384
+ for (prop in parentConfig) {
385
+ if (hasOwnProp(parentConfig, prop) &&
386
+ !hasOwnProp(childConfig, prop) &&
387
+ isObject(parentConfig[prop])) {
388
+ // make sure changes to properties don't modify parent config
389
+ res[prop] = extend({}, res[prop]);
390
+ }
391
+ }
392
+ return res;
393
+ }
394
+
395
+ function Locale(config) {
396
+ if (config != null) {
397
+ this.set(config);
398
+ }
399
+ }
400
+
401
+ var keys;
402
+
403
+ if (Object.keys) {
404
+ keys = Object.keys;
405
+ } else {
406
+ keys = function (obj) {
407
+ var i, res = [];
408
+ for (i in obj) {
409
+ if (hasOwnProp(obj, i)) {
410
+ res.push(i);
411
+ }
412
+ }
413
+ return res;
414
+ };
415
+ }
416
+
417
+ var defaultCalendar = {
418
+ sameDay : '[Today at] LT',
419
+ nextDay : '[Tomorrow at] LT',
420
+ nextWeek : 'dddd [at] LT',
421
+ lastDay : '[Yesterday at] LT',
422
+ lastWeek : '[Last] dddd [at] LT',
423
+ sameElse : 'L'
424
+ };
425
+
426
+ function calendar (key, mom, now) {
427
+ var output = this._calendar[key] || this._calendar['sameElse'];
428
+ return isFunction(output) ? output.call(mom, now) : output;
429
+ }
430
+
431
+ var defaultLongDateFormat = {
432
+ LTS : 'h:mm:ss A',
433
+ LT : 'h:mm A',
434
+ L : 'MM/DD/YYYY',
435
+ LL : 'MMMM D, YYYY',
436
+ LLL : 'MMMM D, YYYY h:mm A',
437
+ LLLL : 'dddd, MMMM D, YYYY h:mm A'
438
+ };
439
+
440
+ function longDateFormat (key) {
441
+ var format = this._longDateFormat[key],
442
+ formatUpper = this._longDateFormat[key.toUpperCase()];
443
+
444
+ if (format || !formatUpper) {
445
+ return format;
446
+ }
447
+
448
+ this._longDateFormat[key] = formatUpper.replace(/MMMM|MM|DD|dddd/g, function (val) {
449
+ return val.slice(1);
450
+ });
451
+
452
+ return this._longDateFormat[key];
453
+ }
454
+
455
+ var defaultInvalidDate = 'Invalid date';
456
+
457
+ function invalidDate () {
458
+ return this._invalidDate;
459
+ }
460
+
461
+ var defaultOrdinal = '%d';
462
+ var defaultDayOfMonthOrdinalParse = /\d{1,2}/;
463
+
464
+ function ordinal (number) {
465
+ return this._ordinal.replace('%d', number);
466
+ }
467
+
468
+ var defaultRelativeTime = {
469
+ future : 'in %s',
470
+ past : '%s ago',
471
+ s : 'a few seconds',
472
+ ss : '%d seconds',
473
+ m : 'a minute',
474
+ mm : '%d minutes',
475
+ h : 'an hour',
476
+ hh : '%d hours',
477
+ d : 'a day',
478
+ dd : '%d days',
479
+ M : 'a month',
480
+ MM : '%d months',
481
+ y : 'a year',
482
+ yy : '%d years'
483
+ };
484
+
485
+ function relativeTime (number, withoutSuffix, string, isFuture) {
486
+ var output = this._relativeTime[string];
487
+ return (isFunction(output)) ?
488
+ output(number, withoutSuffix, string, isFuture) :
489
+ output.replace(/%d/i, number);
490
+ }
491
+
492
+ function pastFuture (diff, output) {
493
+ var format = this._relativeTime[diff > 0 ? 'future' : 'past'];
494
+ return isFunction(format) ? format(output) : format.replace(/%s/i, output);
495
+ }
496
+
497
+ var aliases = {};
498
+
499
+ function addUnitAlias (unit, shorthand) {
500
+ var lowerCase = unit.toLowerCase();
501
+ aliases[lowerCase] = aliases[lowerCase + 's'] = aliases[shorthand] = unit;
502
+ }
503
+
504
+ function normalizeUnits(units) {
505
+ return typeof units === 'string' ? aliases[units] || aliases[units.toLowerCase()] : undefined;
506
+ }
507
+
508
+ function normalizeObjectUnits(inputObject) {
509
+ var normalizedInput = {},
510
+ normalizedProp,
511
+ prop;
512
+
513
+ for (prop in inputObject) {
514
+ if (hasOwnProp(inputObject, prop)) {
515
+ normalizedProp = normalizeUnits(prop);
516
+ if (normalizedProp) {
517
+ normalizedInput[normalizedProp] = inputObject[prop];
518
+ }
519
+ }
520
+ }
521
+
522
+ return normalizedInput;
523
+ }
524
+
525
+ var priorities = {};
526
+
527
+ function addUnitPriority(unit, priority) {
528
+ priorities[unit] = priority;
529
+ }
530
+
531
+ function getPrioritizedUnits(unitsObj) {
532
+ var units = [];
533
+ for (var u in unitsObj) {
534
+ units.push({unit: u, priority: priorities[u]});
535
+ }
536
+ units.sort(function (a, b) {
537
+ return a.priority - b.priority;
538
+ });
539
+ return units;
540
+ }
541
+
542
+ function zeroFill(number, targetLength, forceSign) {
543
+ var absNumber = '' + Math.abs(number),
544
+ zerosToFill = targetLength - absNumber.length,
545
+ sign = number >= 0;
546
+ return (sign ? (forceSign ? '+' : '') : '-') +
547
+ Math.pow(10, Math.max(0, zerosToFill)).toString().substr(1) + absNumber;
548
+ }
549
+
550
+ var formattingTokens = /(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g;
551
+
552
+ var localFormattingTokens = /(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g;
553
+
554
+ var formatFunctions = {};
555
+
556
+ var formatTokenFunctions = {};
557
+
558
+ // token: 'M'
559
+ // padded: ['MM', 2]
560
+ // ordinal: 'Mo'
561
+ // callback: function () { this.month() + 1 }
562
+ function addFormatToken (token, padded, ordinal, callback) {
563
+ var func = callback;
564
+ if (typeof callback === 'string') {
565
+ func = function () {
566
+ return this[callback]();
567
+ };
568
+ }
569
+ if (token) {
570
+ formatTokenFunctions[token] = func;
571
+ }
572
+ if (padded) {
573
+ formatTokenFunctions[padded[0]] = function () {
574
+ return zeroFill(func.apply(this, arguments), padded[1], padded[2]);
575
+ };
576
+ }
577
+ if (ordinal) {
578
+ formatTokenFunctions[ordinal] = function () {
579
+ return this.localeData().ordinal(func.apply(this, arguments), token);
580
+ };
581
+ }
582
+ }
583
+
584
+ function removeFormattingTokens(input) {
585
+ if (input.match(/\[[\s\S]/)) {
586
+ return input.replace(/^\[|\]$/g, '');
587
+ }
588
+ return input.replace(/\\/g, '');
589
+ }
590
+
591
+ function makeFormatFunction(format) {
592
+ var array = format.match(formattingTokens), i, length;
593
+
594
+ for (i = 0, length = array.length; i < length; i++) {
595
+ if (formatTokenFunctions[array[i]]) {
596
+ array[i] = formatTokenFunctions[array[i]];
597
+ } else {
598
+ array[i] = removeFormattingTokens(array[i]);
599
+ }
600
+ }
601
+
602
+ return function (mom) {
603
+ var output = '', i;
604
+ for (i = 0; i < length; i++) {
605
+ output += isFunction(array[i]) ? array[i].call(mom, format) : array[i];
606
+ }
607
+ return output;
608
+ };
609
+ }
610
+
611
+ // format date using native date object
612
+ function formatMoment(m, format) {
613
+ if (!m.isValid()) {
614
+ return m.localeData().invalidDate();
615
+ }
616
+
617
+ format = expandFormat(format, m.localeData());
618
+ formatFunctions[format] = formatFunctions[format] || makeFormatFunction(format);
619
+
620
+ return formatFunctions[format](m);
621
+ }
622
+
623
+ function expandFormat(format, locale) {
624
+ var i = 5;
625
+
626
+ function replaceLongDateFormatTokens(input) {
627
+ return locale.longDateFormat(input) || input;
628
+ }
629
+
630
+ localFormattingTokens.lastIndex = 0;
631
+ while (i >= 0 && localFormattingTokens.test(format)) {
632
+ format = format.replace(localFormattingTokens, replaceLongDateFormatTokens);
633
+ localFormattingTokens.lastIndex = 0;
634
+ i -= 1;
635
+ }
636
+
637
+ return format;
638
+ }
639
+
640
+ var match1 = /\d/; // 0 - 9
641
+ var match2 = /\d\d/; // 00 - 99
642
+ var match3 = /\d{3}/; // 000 - 999
643
+ var match4 = /\d{4}/; // 0000 - 9999
644
+ var match6 = /[+-]?\d{6}/; // -999999 - 999999
645
+ var match1to2 = /\d\d?/; // 0 - 99
646
+ var match3to4 = /\d\d\d\d?/; // 999 - 9999
647
+ var match5to6 = /\d\d\d\d\d\d?/; // 99999 - 999999
648
+ var match1to3 = /\d{1,3}/; // 0 - 999
649
+ var match1to4 = /\d{1,4}/; // 0 - 9999
650
+ var match1to6 = /[+-]?\d{1,6}/; // -999999 - 999999
651
+
652
+ var matchUnsigned = /\d+/; // 0 - inf
653
+ var matchSigned = /[+-]?\d+/; // -inf - inf
654
+
655
+ var matchOffset = /Z|[+-]\d\d:?\d\d/gi; // +00:00 -00:00 +0000 -0000 or Z
656
+ var matchShortOffset = /Z|[+-]\d\d(?::?\d\d)?/gi; // +00 -00 +00:00 -00:00 +0000 -0000 or Z
657
+
658
+ var matchTimestamp = /[+-]?\d+(\.\d{1,3})?/; // 123456789 123456789.123
659
+
660
+ // any word (or two) characters or numbers including two/three word month in arabic.
661
+ // includes scottish gaelic two word and hyphenated months
662
+ var matchWord = /[0-9]{0,256}['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]{1,256}|[\u0600-\u06FF\/]{1,256}(\s*?[\u0600-\u06FF]{1,256}){1,2}/i;
663
+
664
+
665
+ var regexes = {};
666
+
667
+ function addRegexToken (token, regex, strictRegex) {
668
+ regexes[token] = isFunction(regex) ? regex : function (isStrict, localeData) {
669
+ return (isStrict && strictRegex) ? strictRegex : regex;
670
+ };
671
+ }
672
+
673
+ function getParseRegexForToken (token, config) {
674
+ if (!hasOwnProp(regexes, token)) {
675
+ return new RegExp(unescapeFormat(token));
676
+ }
677
+
678
+ return regexes[token](config._strict, config._locale);
679
+ }
680
+
681
+ // Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript
682
+ function unescapeFormat(s) {
683
+ return regexEscape(s.replace('\\', '').replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function (matched, p1, p2, p3, p4) {
684
+ return p1 || p2 || p3 || p4;
685
+ }));
686
+ }
687
+
688
+ function regexEscape(s) {
689
+ return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
690
+ }
691
+
692
+ var tokens = {};
693
+
694
+ function addParseToken (token, callback) {
695
+ var i, func = callback;
696
+ if (typeof token === 'string') {
697
+ token = [token];
698
+ }
699
+ if (isNumber(callback)) {
700
+ func = function (input, array) {
701
+ array[callback] = toInt(input);
702
+ };
703
+ }
704
+ for (i = 0; i < token.length; i++) {
705
+ tokens[token[i]] = func;
706
+ }
707
+ }
708
+
709
+ function addWeekParseToken (token, callback) {
710
+ addParseToken(token, function (input, array, config, token) {
711
+ config._w = config._w || {};
712
+ callback(input, config._w, config, token);
713
+ });
714
+ }
715
+
716
+ function addTimeToArrayFromToken(token, input, config) {
717
+ if (input != null && hasOwnProp(tokens, token)) {
718
+ tokens[token](input, config._a, config, token);
719
+ }
720
+ }
721
+
722
+ var YEAR = 0;
723
+ var MONTH = 1;
724
+ var DATE = 2;
725
+ var HOUR = 3;
726
+ var MINUTE = 4;
727
+ var SECOND = 5;
728
+ var MILLISECOND = 6;
729
+ var WEEK = 7;
730
+ var WEEKDAY = 8;
731
+
732
+ // FORMATTING
733
+
734
+ addFormatToken('Y', 0, 0, function () {
735
+ var y = this.year();
736
+ return y <= 9999 ? '' + y : '+' + y;
737
+ });
738
+
739
+ addFormatToken(0, ['YY', 2], 0, function () {
740
+ return this.year() % 100;
741
+ });
742
+
743
+ addFormatToken(0, ['YYYY', 4], 0, 'year');
744
+ addFormatToken(0, ['YYYYY', 5], 0, 'year');
745
+ addFormatToken(0, ['YYYYYY', 6, true], 0, 'year');
746
+
747
+ // ALIASES
748
+
749
+ addUnitAlias('year', 'y');
750
+
751
+ // PRIORITIES
752
+
753
+ addUnitPriority('year', 1);
754
+
755
+ // PARSING
756
+
757
+ addRegexToken('Y', matchSigned);
758
+ addRegexToken('YY', match1to2, match2);
759
+ addRegexToken('YYYY', match1to4, match4);
760
+ addRegexToken('YYYYY', match1to6, match6);
761
+ addRegexToken('YYYYYY', match1to6, match6);
762
+
763
+ addParseToken(['YYYYY', 'YYYYYY'], YEAR);
764
+ addParseToken('YYYY', function (input, array) {
765
+ array[YEAR] = input.length === 2 ? hooks.parseTwoDigitYear(input) : toInt(input);
766
+ });
767
+ addParseToken('YY', function (input, array) {
768
+ array[YEAR] = hooks.parseTwoDigitYear(input);
769
+ });
770
+ addParseToken('Y', function (input, array) {
771
+ array[YEAR] = parseInt(input, 10);
772
+ });
773
+
774
+ // HELPERS
775
+
776
+ function daysInYear(year) {
777
+ return isLeapYear(year) ? 366 : 365;
778
+ }
779
+
780
+ function isLeapYear(year) {
781
+ return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
782
+ }
783
+
784
+ // HOOKS
785
+
786
+ hooks.parseTwoDigitYear = function (input) {
787
+ return toInt(input) + (toInt(input) > 68 ? 1900 : 2000);
788
+ };
789
+
790
+ // MOMENTS
791
+
792
+ var getSetYear = makeGetSet('FullYear', true);
793
+
794
+ function getIsLeapYear () {
795
+ return isLeapYear(this.year());
796
+ }
797
+
798
+ function makeGetSet (unit, keepTime) {
799
+ return function (value) {
800
+ if (value != null) {
801
+ set$1(this, unit, value);
802
+ hooks.updateOffset(this, keepTime);
803
+ return this;
804
+ } else {
805
+ return get(this, unit);
806
+ }
807
+ };
808
+ }
809
+
810
+ function get (mom, unit) {
811
+ return mom.isValid() ?
812
+ mom._d['get' + (mom._isUTC ? 'UTC' : '') + unit]() : NaN;
813
+ }
814
+
815
+ function set$1 (mom, unit, value) {
816
+ if (mom.isValid() && !isNaN(value)) {
817
+ if (unit === 'FullYear' && isLeapYear(mom.year()) && mom.month() === 1 && mom.date() === 29) {
818
+ mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value, mom.month(), daysInMonth(value, mom.month()));
819
+ }
820
+ else {
821
+ mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value);
822
+ }
823
+ }
824
+ }
825
+
826
+ // MOMENTS
827
+
828
+ function stringGet (units) {
829
+ units = normalizeUnits(units);
830
+ if (isFunction(this[units])) {
831
+ return this[units]();
832
+ }
833
+ return this;
834
+ }
835
+
836
+
837
+ function stringSet (units, value) {
838
+ if (typeof units === 'object') {
839
+ units = normalizeObjectUnits(units);
840
+ var prioritized = getPrioritizedUnits(units);
841
+ for (var i = 0; i < prioritized.length; i++) {
842
+ this[prioritized[i].unit](units[prioritized[i].unit]);
843
+ }
844
+ } else {
845
+ units = normalizeUnits(units);
846
+ if (isFunction(this[units])) {
847
+ return this[units](value);
848
+ }
849
+ }
850
+ return this;
851
+ }
852
+
853
+ function mod(n, x) {
854
+ return ((n % x) + x) % x;
855
+ }
856
+
857
+ var indexOf;
858
+
859
+ if (Array.prototype.indexOf) {
860
+ indexOf = Array.prototype.indexOf;
861
+ } else {
862
+ indexOf = function (o) {
863
+ // I know
864
+ var i;
865
+ for (i = 0; i < this.length; ++i) {
866
+ if (this[i] === o) {
867
+ return i;
868
+ }
869
+ }
870
+ return -1;
871
+ };
872
+ }
873
+
874
+ function daysInMonth(year, month) {
875
+ if (isNaN(year) || isNaN(month)) {
876
+ return NaN;
877
+ }
878
+ var modMonth = mod(month, 12);
879
+ year += (month - modMonth) / 12;
880
+ return modMonth === 1 ? (isLeapYear(year) ? 29 : 28) : (31 - modMonth % 7 % 2);
881
+ }
882
+
883
+ // FORMATTING
884
+
885
+ addFormatToken('M', ['MM', 2], 'Mo', function () {
886
+ return this.month() + 1;
887
+ });
888
+
889
+ addFormatToken('MMM', 0, 0, function (format) {
890
+ return this.localeData().monthsShort(this, format);
891
+ });
892
+
893
+ addFormatToken('MMMM', 0, 0, function (format) {
894
+ return this.localeData().months(this, format);
895
+ });
896
+
897
+ // ALIASES
898
+
899
+ addUnitAlias('month', 'M');
900
+
901
+ // PRIORITY
902
+
903
+ addUnitPriority('month', 8);
904
+
905
+ // PARSING
906
+
907
+ addRegexToken('M', match1to2);
908
+ addRegexToken('MM', match1to2, match2);
909
+ addRegexToken('MMM', function (isStrict, locale) {
910
+ return locale.monthsShortRegex(isStrict);
911
+ });
912
+ addRegexToken('MMMM', function (isStrict, locale) {
913
+ return locale.monthsRegex(isStrict);
914
+ });
915
+
916
+ addParseToken(['M', 'MM'], function (input, array) {
917
+ array[MONTH] = toInt(input) - 1;
918
+ });
919
+
920
+ addParseToken(['MMM', 'MMMM'], function (input, array, config, token) {
921
+ var month = config._locale.monthsParse(input, token, config._strict);
922
+ // if we didn't find a month name, mark the date as invalid.
923
+ if (month != null) {
924
+ array[MONTH] = month;
925
+ } else {
926
+ getParsingFlags(config).invalidMonth = input;
927
+ }
928
+ });
929
+
930
+ // LOCALES
931
+
932
+ var MONTHS_IN_FORMAT = /D[oD]?(\[[^\[\]]*\]|\s)+MMMM?/;
933
+ var defaultLocaleMonths = 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_');
934
+ function localeMonths (m, format) {
935
+ if (!m) {
936
+ return isArray(this._months) ? this._months :
937
+ this._months['standalone'];
938
+ }
939
+ return isArray(this._months) ? this._months[m.month()] :
940
+ this._months[(this._months.isFormat || MONTHS_IN_FORMAT).test(format) ? 'format' : 'standalone'][m.month()];
941
+ }
942
+
943
+ var defaultLocaleMonthsShort = 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_');
944
+ function localeMonthsShort (m, format) {
945
+ if (!m) {
946
+ return isArray(this._monthsShort) ? this._monthsShort :
947
+ this._monthsShort['standalone'];
948
+ }
949
+ return isArray(this._monthsShort) ? this._monthsShort[m.month()] :
950
+ this._monthsShort[MONTHS_IN_FORMAT.test(format) ? 'format' : 'standalone'][m.month()];
951
+ }
952
+
953
+ function handleStrictParse(monthName, format, strict) {
954
+ var i, ii, mom, llc = monthName.toLocaleLowerCase();
955
+ if (!this._monthsParse) {
956
+ // this is not used
957
+ this._monthsParse = [];
958
+ this._longMonthsParse = [];
959
+ this._shortMonthsParse = [];
960
+ for (i = 0; i < 12; ++i) {
961
+ mom = createUTC([2000, i]);
962
+ this._shortMonthsParse[i] = this.monthsShort(mom, '').toLocaleLowerCase();
963
+ this._longMonthsParse[i] = this.months(mom, '').toLocaleLowerCase();
964
+ }
965
+ }
966
+
967
+ if (strict) {
968
+ if (format === 'MMM') {
969
+ ii = indexOf.call(this._shortMonthsParse, llc);
970
+ return ii !== -1 ? ii : null;
971
+ } else {
972
+ ii = indexOf.call(this._longMonthsParse, llc);
973
+ return ii !== -1 ? ii : null;
974
+ }
975
+ } else {
976
+ if (format === 'MMM') {
977
+ ii = indexOf.call(this._shortMonthsParse, llc);
978
+ if (ii !== -1) {
979
+ return ii;
980
+ }
981
+ ii = indexOf.call(this._longMonthsParse, llc);
982
+ return ii !== -1 ? ii : null;
983
+ } else {
984
+ ii = indexOf.call(this._longMonthsParse, llc);
985
+ if (ii !== -1) {
986
+ return ii;
987
+ }
988
+ ii = indexOf.call(this._shortMonthsParse, llc);
989
+ return ii !== -1 ? ii : null;
990
+ }
991
+ }
992
+ }
993
+
994
+ function localeMonthsParse (monthName, format, strict) {
995
+ var i, mom, regex;
996
+
997
+ if (this._monthsParseExact) {
998
+ return handleStrictParse.call(this, monthName, format, strict);
999
+ }
1000
+
1001
+ if (!this._monthsParse) {
1002
+ this._monthsParse = [];
1003
+ this._longMonthsParse = [];
1004
+ this._shortMonthsParse = [];
1005
+ }
1006
+
1007
+ // TODO: add sorting
1008
+ // Sorting makes sure if one month (or abbr) is a prefix of another
1009
+ // see sorting in computeMonthsParse
1010
+ for (i = 0; i < 12; i++) {
1011
+ // make the regex if we don't have it already
1012
+ mom = createUTC([2000, i]);
1013
+ if (strict && !this._longMonthsParse[i]) {
1014
+ this._longMonthsParse[i] = new RegExp('^' + this.months(mom, '').replace('.', '') + '$', 'i');
1015
+ this._shortMonthsParse[i] = new RegExp('^' + this.monthsShort(mom, '').replace('.', '') + '$', 'i');
1016
+ }
1017
+ if (!strict && !this._monthsParse[i]) {
1018
+ regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, '');
1019
+ this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i');
1020
+ }
1021
+ // test the regex
1022
+ if (strict && format === 'MMMM' && this._longMonthsParse[i].test(monthName)) {
1023
+ return i;
1024
+ } else if (strict && format === 'MMM' && this._shortMonthsParse[i].test(monthName)) {
1025
+ return i;
1026
+ } else if (!strict && this._monthsParse[i].test(monthName)) {
1027
+ return i;
1028
+ }
1029
+ }
1030
+ }
1031
+
1032
+ // MOMENTS
1033
+
1034
+ function setMonth (mom, value) {
1035
+ var dayOfMonth;
1036
+
1037
+ if (!mom.isValid()) {
1038
+ // No op
1039
+ return mom;
1040
+ }
1041
+
1042
+ if (typeof value === 'string') {
1043
+ if (/^\d+$/.test(value)) {
1044
+ value = toInt(value);
1045
+ } else {
1046
+ value = mom.localeData().monthsParse(value);
1047
+ // TODO: Another silent failure?
1048
+ if (!isNumber(value)) {
1049
+ return mom;
1050
+ }
1051
+ }
1052
+ }
1053
+
1054
+ dayOfMonth = Math.min(mom.date(), daysInMonth(mom.year(), value));
1055
+ mom._d['set' + (mom._isUTC ? 'UTC' : '') + 'Month'](value, dayOfMonth);
1056
+ return mom;
1057
+ }
1058
+
1059
+ function getSetMonth (value) {
1060
+ if (value != null) {
1061
+ setMonth(this, value);
1062
+ hooks.updateOffset(this, true);
1063
+ return this;
1064
+ } else {
1065
+ return get(this, 'Month');
1066
+ }
1067
+ }
1068
+
1069
+ function getDaysInMonth () {
1070
+ return daysInMonth(this.year(), this.month());
1071
+ }
1072
+
1073
+ var defaultMonthsShortRegex = matchWord;
1074
+ function monthsShortRegex (isStrict) {
1075
+ if (this._monthsParseExact) {
1076
+ if (!hasOwnProp(this, '_monthsRegex')) {
1077
+ computeMonthsParse.call(this);
1078
+ }
1079
+ if (isStrict) {
1080
+ return this._monthsShortStrictRegex;
1081
+ } else {
1082
+ return this._monthsShortRegex;
1083
+ }
1084
+ } else {
1085
+ if (!hasOwnProp(this, '_monthsShortRegex')) {
1086
+ this._monthsShortRegex = defaultMonthsShortRegex;
1087
+ }
1088
+ return this._monthsShortStrictRegex && isStrict ?
1089
+ this._monthsShortStrictRegex : this._monthsShortRegex;
1090
+ }
1091
+ }
1092
+
1093
+ var defaultMonthsRegex = matchWord;
1094
+ function monthsRegex (isStrict) {
1095
+ if (this._monthsParseExact) {
1096
+ if (!hasOwnProp(this, '_monthsRegex')) {
1097
+ computeMonthsParse.call(this);
1098
+ }
1099
+ if (isStrict) {
1100
+ return this._monthsStrictRegex;
1101
+ } else {
1102
+ return this._monthsRegex;
1103
+ }
1104
+ } else {
1105
+ if (!hasOwnProp(this, '_monthsRegex')) {
1106
+ this._monthsRegex = defaultMonthsRegex;
1107
+ }
1108
+ return this._monthsStrictRegex && isStrict ?
1109
+ this._monthsStrictRegex : this._monthsRegex;
1110
+ }
1111
+ }
1112
+
1113
+ function computeMonthsParse () {
1114
+ function cmpLenRev(a, b) {
1115
+ return b.length - a.length;
1116
+ }
1117
+
1118
+ var shortPieces = [], longPieces = [], mixedPieces = [],
1119
+ i, mom;
1120
+ for (i = 0; i < 12; i++) {
1121
+ // make the regex if we don't have it already
1122
+ mom = createUTC([2000, i]);
1123
+ shortPieces.push(this.monthsShort(mom, ''));
1124
+ longPieces.push(this.months(mom, ''));
1125
+ mixedPieces.push(this.months(mom, ''));
1126
+ mixedPieces.push(this.monthsShort(mom, ''));
1127
+ }
1128
+ // Sorting makes sure if one month (or abbr) is a prefix of another it
1129
+ // will match the longer piece.
1130
+ shortPieces.sort(cmpLenRev);
1131
+ longPieces.sort(cmpLenRev);
1132
+ mixedPieces.sort(cmpLenRev);
1133
+ for (i = 0; i < 12; i++) {
1134
+ shortPieces[i] = regexEscape(shortPieces[i]);
1135
+ longPieces[i] = regexEscape(longPieces[i]);
1136
+ }
1137
+ for (i = 0; i < 24; i++) {
1138
+ mixedPieces[i] = regexEscape(mixedPieces[i]);
1139
+ }
1140
+
1141
+ this._monthsRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i');
1142
+ this._monthsShortRegex = this._monthsRegex;
1143
+ this._monthsStrictRegex = new RegExp('^(' + longPieces.join('|') + ')', 'i');
1144
+ this._monthsShortStrictRegex = new RegExp('^(' + shortPieces.join('|') + ')', 'i');
1145
+ }
1146
+
1147
+ function createDate (y, m, d, h, M, s, ms) {
1148
+ // can't just apply() to create a date:
1149
+ // https://stackoverflow.com/q/181348
1150
+ var date = new Date(y, m, d, h, M, s, ms);
1151
+
1152
+ // the date constructor remaps years 0-99 to 1900-1999
1153
+ if (y < 100 && y >= 0 && isFinite(date.getFullYear())) {
1154
+ date.setFullYear(y);
1155
+ }
1156
+ return date;
1157
+ }
1158
+
1159
+ function createUTCDate (y) {
1160
+ var date = new Date(Date.UTC.apply(null, arguments));
1161
+
1162
+ // the Date.UTC function remaps years 0-99 to 1900-1999
1163
+ if (y < 100 && y >= 0 && isFinite(date.getUTCFullYear())) {
1164
+ date.setUTCFullYear(y);
1165
+ }
1166
+ return date;
1167
+ }
1168
+
1169
+ // start-of-first-week - start-of-year
1170
+ function firstWeekOffset(year, dow, doy) {
1171
+ var // first-week day -- which january is always in the first week (4 for iso, 1 for other)
1172
+ fwd = 7 + dow - doy,
1173
+ // first-week day local weekday -- which local weekday is fwd
1174
+ fwdlw = (7 + createUTCDate(year, 0, fwd).getUTCDay() - dow) % 7;
1175
+
1176
+ return -fwdlw + fwd - 1;
1177
+ }
1178
+
1179
+ // https://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday
1180
+ function dayOfYearFromWeeks(year, week, weekday, dow, doy) {
1181
+ var localWeekday = (7 + weekday - dow) % 7,
1182
+ weekOffset = firstWeekOffset(year, dow, doy),
1183
+ dayOfYear = 1 + 7 * (week - 1) + localWeekday + weekOffset,
1184
+ resYear, resDayOfYear;
1185
+
1186
+ if (dayOfYear <= 0) {
1187
+ resYear = year - 1;
1188
+ resDayOfYear = daysInYear(resYear) + dayOfYear;
1189
+ } else if (dayOfYear > daysInYear(year)) {
1190
+ resYear = year + 1;
1191
+ resDayOfYear = dayOfYear - daysInYear(year);
1192
+ } else {
1193
+ resYear = year;
1194
+ resDayOfYear = dayOfYear;
1195
+ }
1196
+
1197
+ return {
1198
+ year: resYear,
1199
+ dayOfYear: resDayOfYear
1200
+ };
1201
+ }
1202
+
1203
+ function weekOfYear(mom, dow, doy) {
1204
+ var weekOffset = firstWeekOffset(mom.year(), dow, doy),
1205
+ week = Math.floor((mom.dayOfYear() - weekOffset - 1) / 7) + 1,
1206
+ resWeek, resYear;
1207
+
1208
+ if (week < 1) {
1209
+ resYear = mom.year() - 1;
1210
+ resWeek = week + weeksInYear(resYear, dow, doy);
1211
+ } else if (week > weeksInYear(mom.year(), dow, doy)) {
1212
+ resWeek = week - weeksInYear(mom.year(), dow, doy);
1213
+ resYear = mom.year() + 1;
1214
+ } else {
1215
+ resYear = mom.year();
1216
+ resWeek = week;
1217
+ }
1218
+
1219
+ return {
1220
+ week: resWeek,
1221
+ year: resYear
1222
+ };
1223
+ }
1224
+
1225
+ function weeksInYear(year, dow, doy) {
1226
+ var weekOffset = firstWeekOffset(year, dow, doy),
1227
+ weekOffsetNext = firstWeekOffset(year + 1, dow, doy);
1228
+ return (daysInYear(year) - weekOffset + weekOffsetNext) / 7;
1229
+ }
1230
+
1231
+ // FORMATTING
1232
+
1233
+ addFormatToken('w', ['ww', 2], 'wo', 'week');
1234
+ addFormatToken('W', ['WW', 2], 'Wo', 'isoWeek');
1235
+
1236
+ // ALIASES
1237
+
1238
+ addUnitAlias('week', 'w');
1239
+ addUnitAlias('isoWeek', 'W');
1240
+
1241
+ // PRIORITIES
1242
+
1243
+ addUnitPriority('week', 5);
1244
+ addUnitPriority('isoWeek', 5);
1245
+
1246
+ // PARSING
1247
+
1248
+ addRegexToken('w', match1to2);
1249
+ addRegexToken('ww', match1to2, match2);
1250
+ addRegexToken('W', match1to2);
1251
+ addRegexToken('WW', match1to2, match2);
1252
+
1253
+ addWeekParseToken(['w', 'ww', 'W', 'WW'], function (input, week, config, token) {
1254
+ week[token.substr(0, 1)] = toInt(input);
1255
+ });
1256
+
1257
+ // HELPERS
1258
+
1259
+ // LOCALES
1260
+
1261
+ function localeWeek (mom) {
1262
+ return weekOfYear(mom, this._week.dow, this._week.doy).week;
1263
+ }
1264
+
1265
+ var defaultLocaleWeek = {
1266
+ dow : 0, // Sunday is the first day of the week.
1267
+ doy : 6 // The week that contains Jan 1st is the first week of the year.
1268
+ };
1269
+
1270
+ function localeFirstDayOfWeek () {
1271
+ return this._week.dow;
1272
+ }
1273
+
1274
+ function localeFirstDayOfYear () {
1275
+ return this._week.doy;
1276
+ }
1277
+
1278
+ // MOMENTS
1279
+
1280
+ function getSetWeek (input) {
1281
+ var week = this.localeData().week(this);
1282
+ return input == null ? week : this.add((input - week) * 7, 'd');
1283
+ }
1284
+
1285
+ function getSetISOWeek (input) {
1286
+ var week = weekOfYear(this, 1, 4).week;
1287
+ return input == null ? week : this.add((input - week) * 7, 'd');
1288
+ }
1289
+
1290
+ // FORMATTING
1291
+
1292
+ addFormatToken('d', 0, 'do', 'day');
1293
+
1294
+ addFormatToken('dd', 0, 0, function (format) {
1295
+ return this.localeData().weekdaysMin(this, format);
1296
+ });
1297
+
1298
+ addFormatToken('ddd', 0, 0, function (format) {
1299
+ return this.localeData().weekdaysShort(this, format);
1300
+ });
1301
+
1302
+ addFormatToken('dddd', 0, 0, function (format) {
1303
+ return this.localeData().weekdays(this, format);
1304
+ });
1305
+
1306
+ addFormatToken('e', 0, 0, 'weekday');
1307
+ addFormatToken('E', 0, 0, 'isoWeekday');
1308
+
1309
+ // ALIASES
1310
+
1311
+ addUnitAlias('day', 'd');
1312
+ addUnitAlias('weekday', 'e');
1313
+ addUnitAlias('isoWeekday', 'E');
1314
+
1315
+ // PRIORITY
1316
+ addUnitPriority('day', 11);
1317
+ addUnitPriority('weekday', 11);
1318
+ addUnitPriority('isoWeekday', 11);
1319
+
1320
+ // PARSING
1321
+
1322
+ addRegexToken('d', match1to2);
1323
+ addRegexToken('e', match1to2);
1324
+ addRegexToken('E', match1to2);
1325
+ addRegexToken('dd', function (isStrict, locale) {
1326
+ return locale.weekdaysMinRegex(isStrict);
1327
+ });
1328
+ addRegexToken('ddd', function (isStrict, locale) {
1329
+ return locale.weekdaysShortRegex(isStrict);
1330
+ });
1331
+ addRegexToken('dddd', function (isStrict, locale) {
1332
+ return locale.weekdaysRegex(isStrict);
1333
+ });
1334
+
1335
+ addWeekParseToken(['dd', 'ddd', 'dddd'], function (input, week, config, token) {
1336
+ var weekday = config._locale.weekdaysParse(input, token, config._strict);
1337
+ // if we didn't get a weekday name, mark the date as invalid
1338
+ if (weekday != null) {
1339
+ week.d = weekday;
1340
+ } else {
1341
+ getParsingFlags(config).invalidWeekday = input;
1342
+ }
1343
+ });
1344
+
1345
+ addWeekParseToken(['d', 'e', 'E'], function (input, week, config, token) {
1346
+ week[token] = toInt(input);
1347
+ });
1348
+
1349
+ // HELPERS
1350
+
1351
+ function parseWeekday(input, locale) {
1352
+ if (typeof input !== 'string') {
1353
+ return input;
1354
+ }
1355
+
1356
+ if (!isNaN(input)) {
1357
+ return parseInt(input, 10);
1358
+ }
1359
+
1360
+ input = locale.weekdaysParse(input);
1361
+ if (typeof input === 'number') {
1362
+ return input;
1363
+ }
1364
+
1365
+ return null;
1366
+ }
1367
+
1368
+ function parseIsoWeekday(input, locale) {
1369
+ if (typeof input === 'string') {
1370
+ return locale.weekdaysParse(input) % 7 || 7;
1371
+ }
1372
+ return isNaN(input) ? null : input;
1373
+ }
1374
+
1375
+ // LOCALES
1376
+
1377
+ var defaultLocaleWeekdays = 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_');
1378
+ function localeWeekdays (m, format) {
1379
+ if (!m) {
1380
+ return isArray(this._weekdays) ? this._weekdays :
1381
+ this._weekdays['standalone'];
1382
+ }
1383
+ return isArray(this._weekdays) ? this._weekdays[m.day()] :
1384
+ this._weekdays[this._weekdays.isFormat.test(format) ? 'format' : 'standalone'][m.day()];
1385
+ }
1386
+
1387
+ var defaultLocaleWeekdaysShort = 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_');
1388
+ function localeWeekdaysShort (m) {
1389
+ return (m) ? this._weekdaysShort[m.day()] : this._weekdaysShort;
1390
+ }
1391
+
1392
+ var defaultLocaleWeekdaysMin = 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_');
1393
+ function localeWeekdaysMin (m) {
1394
+ return (m) ? this._weekdaysMin[m.day()] : this._weekdaysMin;
1395
+ }
1396
+
1397
+ function handleStrictParse$1(weekdayName, format, strict) {
1398
+ var i, ii, mom, llc = weekdayName.toLocaleLowerCase();
1399
+ if (!this._weekdaysParse) {
1400
+ this._weekdaysParse = [];
1401
+ this._shortWeekdaysParse = [];
1402
+ this._minWeekdaysParse = [];
1403
+
1404
+ for (i = 0; i < 7; ++i) {
1405
+ mom = createUTC([2000, 1]).day(i);
1406
+ this._minWeekdaysParse[i] = this.weekdaysMin(mom, '').toLocaleLowerCase();
1407
+ this._shortWeekdaysParse[i] = this.weekdaysShort(mom, '').toLocaleLowerCase();
1408
+ this._weekdaysParse[i] = this.weekdays(mom, '').toLocaleLowerCase();
1409
+ }
1410
+ }
1411
+
1412
+ if (strict) {
1413
+ if (format === 'dddd') {
1414
+ ii = indexOf.call(this._weekdaysParse, llc);
1415
+ return ii !== -1 ? ii : null;
1416
+ } else if (format === 'ddd') {
1417
+ ii = indexOf.call(this._shortWeekdaysParse, llc);
1418
+ return ii !== -1 ? ii : null;
1419
+ } else {
1420
+ ii = indexOf.call(this._minWeekdaysParse, llc);
1421
+ return ii !== -1 ? ii : null;
1422
+ }
1423
+ } else {
1424
+ if (format === 'dddd') {
1425
+ ii = indexOf.call(this._weekdaysParse, llc);
1426
+ if (ii !== -1) {
1427
+ return ii;
1428
+ }
1429
+ ii = indexOf.call(this._shortWeekdaysParse, llc);
1430
+ if (ii !== -1) {
1431
+ return ii;
1432
+ }
1433
+ ii = indexOf.call(this._minWeekdaysParse, llc);
1434
+ return ii !== -1 ? ii : null;
1435
+ } else if (format === 'ddd') {
1436
+ ii = indexOf.call(this._shortWeekdaysParse, llc);
1437
+ if (ii !== -1) {
1438
+ return ii;
1439
+ }
1440
+ ii = indexOf.call(this._weekdaysParse, llc);
1441
+ if (ii !== -1) {
1442
+ return ii;
1443
+ }
1444
+ ii = indexOf.call(this._minWeekdaysParse, llc);
1445
+ return ii !== -1 ? ii : null;
1446
+ } else {
1447
+ ii = indexOf.call(this._minWeekdaysParse, llc);
1448
+ if (ii !== -1) {
1449
+ return ii;
1450
+ }
1451
+ ii = indexOf.call(this._weekdaysParse, llc);
1452
+ if (ii !== -1) {
1453
+ return ii;
1454
+ }
1455
+ ii = indexOf.call(this._shortWeekdaysParse, llc);
1456
+ return ii !== -1 ? ii : null;
1457
+ }
1458
+ }
1459
+ }
1460
+
1461
+ function localeWeekdaysParse (weekdayName, format, strict) {
1462
+ var i, mom, regex;
1463
+
1464
+ if (this._weekdaysParseExact) {
1465
+ return handleStrictParse$1.call(this, weekdayName, format, strict);
1466
+ }
1467
+
1468
+ if (!this._weekdaysParse) {
1469
+ this._weekdaysParse = [];
1470
+ this._minWeekdaysParse = [];
1471
+ this._shortWeekdaysParse = [];
1472
+ this._fullWeekdaysParse = [];
1473
+ }
1474
+
1475
+ for (i = 0; i < 7; i++) {
1476
+ // make the regex if we don't have it already
1477
+
1478
+ mom = createUTC([2000, 1]).day(i);
1479
+ if (strict && !this._fullWeekdaysParse[i]) {
1480
+ this._fullWeekdaysParse[i] = new RegExp('^' + this.weekdays(mom, '').replace('.', '\.?') + '$', 'i');
1481
+ this._shortWeekdaysParse[i] = new RegExp('^' + this.weekdaysShort(mom, '').replace('.', '\.?') + '$', 'i');
1482
+ this._minWeekdaysParse[i] = new RegExp('^' + this.weekdaysMin(mom, '').replace('.', '\.?') + '$', 'i');
1483
+ }
1484
+ if (!this._weekdaysParse[i]) {
1485
+ regex = '^' + this.weekdays(mom, '') + '|^' + this.weekdaysShort(mom, '') + '|^' + this.weekdaysMin(mom, '');
1486
+ this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i');
1487
+ }
1488
+ // test the regex
1489
+ if (strict && format === 'dddd' && this._fullWeekdaysParse[i].test(weekdayName)) {
1490
+ return i;
1491
+ } else if (strict && format === 'ddd' && this._shortWeekdaysParse[i].test(weekdayName)) {
1492
+ return i;
1493
+ } else if (strict && format === 'dd' && this._minWeekdaysParse[i].test(weekdayName)) {
1494
+ return i;
1495
+ } else if (!strict && this._weekdaysParse[i].test(weekdayName)) {
1496
+ return i;
1497
+ }
1498
+ }
1499
+ }
1500
+
1501
+ // MOMENTS
1502
+
1503
+ function getSetDayOfWeek (input) {
1504
+ if (!this.isValid()) {
1505
+ return input != null ? this : NaN;
1506
+ }
1507
+ var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay();
1508
+ if (input != null) {
1509
+ input = parseWeekday(input, this.localeData());
1510
+ return this.add(input - day, 'd');
1511
+ } else {
1512
+ return day;
1513
+ }
1514
+ }
1515
+
1516
+ function getSetLocaleDayOfWeek (input) {
1517
+ if (!this.isValid()) {
1518
+ return input != null ? this : NaN;
1519
+ }
1520
+ var weekday = (this.day() + 7 - this.localeData()._week.dow) % 7;
1521
+ return input == null ? weekday : this.add(input - weekday, 'd');
1522
+ }
1523
+
1524
+ function getSetISODayOfWeek (input) {
1525
+ if (!this.isValid()) {
1526
+ return input != null ? this : NaN;
1527
+ }
1528
+
1529
+ // behaves the same as moment#day except
1530
+ // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6)
1531
+ // as a setter, sunday should belong to the previous week.
1532
+
1533
+ if (input != null) {
1534
+ var weekday = parseIsoWeekday(input, this.localeData());
1535
+ return this.day(this.day() % 7 ? weekday : weekday - 7);
1536
+ } else {
1537
+ return this.day() || 7;
1538
+ }
1539
+ }
1540
+
1541
+ var defaultWeekdaysRegex = matchWord;
1542
+ function weekdaysRegex (isStrict) {
1543
+ if (this._weekdaysParseExact) {
1544
+ if (!hasOwnProp(this, '_weekdaysRegex')) {
1545
+ computeWeekdaysParse.call(this);
1546
+ }
1547
+ if (isStrict) {
1548
+ return this._weekdaysStrictRegex;
1549
+ } else {
1550
+ return this._weekdaysRegex;
1551
+ }
1552
+ } else {
1553
+ if (!hasOwnProp(this, '_weekdaysRegex')) {
1554
+ this._weekdaysRegex = defaultWeekdaysRegex;
1555
+ }
1556
+ return this._weekdaysStrictRegex && isStrict ?
1557
+ this._weekdaysStrictRegex : this._weekdaysRegex;
1558
+ }
1559
+ }
1560
+
1561
+ var defaultWeekdaysShortRegex = matchWord;
1562
+ function weekdaysShortRegex (isStrict) {
1563
+ if (this._weekdaysParseExact) {
1564
+ if (!hasOwnProp(this, '_weekdaysRegex')) {
1565
+ computeWeekdaysParse.call(this);
1566
+ }
1567
+ if (isStrict) {
1568
+ return this._weekdaysShortStrictRegex;
1569
+ } else {
1570
+ return this._weekdaysShortRegex;
1571
+ }
1572
+ } else {
1573
+ if (!hasOwnProp(this, '_weekdaysShortRegex')) {
1574
+ this._weekdaysShortRegex = defaultWeekdaysShortRegex;
1575
+ }
1576
+ return this._weekdaysShortStrictRegex && isStrict ?
1577
+ this._weekdaysShortStrictRegex : this._weekdaysShortRegex;
1578
+ }
1579
+ }
1580
+
1581
+ var defaultWeekdaysMinRegex = matchWord;
1582
+ function weekdaysMinRegex (isStrict) {
1583
+ if (this._weekdaysParseExact) {
1584
+ if (!hasOwnProp(this, '_weekdaysRegex')) {
1585
+ computeWeekdaysParse.call(this);
1586
+ }
1587
+ if (isStrict) {
1588
+ return this._weekdaysMinStrictRegex;
1589
+ } else {
1590
+ return this._weekdaysMinRegex;
1591
+ }
1592
+ } else {
1593
+ if (!hasOwnProp(this, '_weekdaysMinRegex')) {
1594
+ this._weekdaysMinRegex = defaultWeekdaysMinRegex;
1595
+ }
1596
+ return this._weekdaysMinStrictRegex && isStrict ?
1597
+ this._weekdaysMinStrictRegex : this._weekdaysMinRegex;
1598
+ }
1599
+ }
1600
+
1601
+
1602
+ function computeWeekdaysParse () {
1603
+ function cmpLenRev(a, b) {
1604
+ return b.length - a.length;
1605
+ }
1606
+
1607
+ var minPieces = [], shortPieces = [], longPieces = [], mixedPieces = [],
1608
+ i, mom, minp, shortp, longp;
1609
+ for (i = 0; i < 7; i++) {
1610
+ // make the regex if we don't have it already
1611
+ mom = createUTC([2000, 1]).day(i);
1612
+ minp = this.weekdaysMin(mom, '');
1613
+ shortp = this.weekdaysShort(mom, '');
1614
+ longp = this.weekdays(mom, '');
1615
+ minPieces.push(minp);
1616
+ shortPieces.push(shortp);
1617
+ longPieces.push(longp);
1618
+ mixedPieces.push(minp);
1619
+ mixedPieces.push(shortp);
1620
+ mixedPieces.push(longp);
1621
+ }
1622
+ // Sorting makes sure if one weekday (or abbr) is a prefix of another it
1623
+ // will match the longer piece.
1624
+ minPieces.sort(cmpLenRev);
1625
+ shortPieces.sort(cmpLenRev);
1626
+ longPieces.sort(cmpLenRev);
1627
+ mixedPieces.sort(cmpLenRev);
1628
+ for (i = 0; i < 7; i++) {
1629
+ shortPieces[i] = regexEscape(shortPieces[i]);
1630
+ longPieces[i] = regexEscape(longPieces[i]);
1631
+ mixedPieces[i] = regexEscape(mixedPieces[i]);
1632
+ }
1633
+
1634
+ this._weekdaysRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i');
1635
+ this._weekdaysShortRegex = this._weekdaysRegex;
1636
+ this._weekdaysMinRegex = this._weekdaysRegex;
1637
+
1638
+ this._weekdaysStrictRegex = new RegExp('^(' + longPieces.join('|') + ')', 'i');
1639
+ this._weekdaysShortStrictRegex = new RegExp('^(' + shortPieces.join('|') + ')', 'i');
1640
+ this._weekdaysMinStrictRegex = new RegExp('^(' + minPieces.join('|') + ')', 'i');
1641
+ }
1642
+
1643
+ // FORMATTING
1644
+
1645
+ function hFormat() {
1646
+ return this.hours() % 12 || 12;
1647
+ }
1648
+
1649
+ function kFormat() {
1650
+ return this.hours() || 24;
1651
+ }
1652
+
1653
+ addFormatToken('H', ['HH', 2], 0, 'hour');
1654
+ addFormatToken('h', ['hh', 2], 0, hFormat);
1655
+ addFormatToken('k', ['kk', 2], 0, kFormat);
1656
+
1657
+ addFormatToken('hmm', 0, 0, function () {
1658
+ return '' + hFormat.apply(this) + zeroFill(this.minutes(), 2);
1659
+ });
1660
+
1661
+ addFormatToken('hmmss', 0, 0, function () {
1662
+ return '' + hFormat.apply(this) + zeroFill(this.minutes(), 2) +
1663
+ zeroFill(this.seconds(), 2);
1664
+ });
1665
+
1666
+ addFormatToken('Hmm', 0, 0, function () {
1667
+ return '' + this.hours() + zeroFill(this.minutes(), 2);
1668
+ });
1669
+
1670
+ addFormatToken('Hmmss', 0, 0, function () {
1671
+ return '' + this.hours() + zeroFill(this.minutes(), 2) +
1672
+ zeroFill(this.seconds(), 2);
1673
+ });
1674
+
1675
+ function meridiem (token, lowercase) {
1676
+ addFormatToken(token, 0, 0, function () {
1677
+ return this.localeData().meridiem(this.hours(), this.minutes(), lowercase);
1678
+ });
1679
+ }
1680
+
1681
+ meridiem('a', true);
1682
+ meridiem('A', false);
1683
+
1684
+ // ALIASES
1685
+
1686
+ addUnitAlias('hour', 'h');
1687
+
1688
+ // PRIORITY
1689
+ addUnitPriority('hour', 13);
1690
+
1691
+ // PARSING
1692
+
1693
+ function matchMeridiem (isStrict, locale) {
1694
+ return locale._meridiemParse;
1695
+ }
1696
+
1697
+ addRegexToken('a', matchMeridiem);
1698
+ addRegexToken('A', matchMeridiem);
1699
+ addRegexToken('H', match1to2);
1700
+ addRegexToken('h', match1to2);
1701
+ addRegexToken('k', match1to2);
1702
+ addRegexToken('HH', match1to2, match2);
1703
+ addRegexToken('hh', match1to2, match2);
1704
+ addRegexToken('kk', match1to2, match2);
1705
+
1706
+ addRegexToken('hmm', match3to4);
1707
+ addRegexToken('hmmss', match5to6);
1708
+ addRegexToken('Hmm', match3to4);
1709
+ addRegexToken('Hmmss', match5to6);
1710
+
1711
+ addParseToken(['H', 'HH'], HOUR);
1712
+ addParseToken(['k', 'kk'], function (input, array, config) {
1713
+ var kInput = toInt(input);
1714
+ array[HOUR] = kInput === 24 ? 0 : kInput;
1715
+ });
1716
+ addParseToken(['a', 'A'], function (input, array, config) {
1717
+ config._isPm = config._locale.isPM(input);
1718
+ config._meridiem = input;
1719
+ });
1720
+ addParseToken(['h', 'hh'], function (input, array, config) {
1721
+ array[HOUR] = toInt(input);
1722
+ getParsingFlags(config).bigHour = true;
1723
+ });
1724
+ addParseToken('hmm', function (input, array, config) {
1725
+ var pos = input.length - 2;
1726
+ array[HOUR] = toInt(input.substr(0, pos));
1727
+ array[MINUTE] = toInt(input.substr(pos));
1728
+ getParsingFlags(config).bigHour = true;
1729
+ });
1730
+ addParseToken('hmmss', function (input, array, config) {
1731
+ var pos1 = input.length - 4;
1732
+ var pos2 = input.length - 2;
1733
+ array[HOUR] = toInt(input.substr(0, pos1));
1734
+ array[MINUTE] = toInt(input.substr(pos1, 2));
1735
+ array[SECOND] = toInt(input.substr(pos2));
1736
+ getParsingFlags(config).bigHour = true;
1737
+ });
1738
+ addParseToken('Hmm', function (input, array, config) {
1739
+ var pos = input.length - 2;
1740
+ array[HOUR] = toInt(input.substr(0, pos));
1741
+ array[MINUTE] = toInt(input.substr(pos));
1742
+ });
1743
+ addParseToken('Hmmss', function (input, array, config) {
1744
+ var pos1 = input.length - 4;
1745
+ var pos2 = input.length - 2;
1746
+ array[HOUR] = toInt(input.substr(0, pos1));
1747
+ array[MINUTE] = toInt(input.substr(pos1, 2));
1748
+ array[SECOND] = toInt(input.substr(pos2));
1749
+ });
1750
+
1751
+ // LOCALES
1752
+
1753
+ function localeIsPM (input) {
1754
+ // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays
1755
+ // Using charAt should be more compatible.
1756
+ return ((input + '').toLowerCase().charAt(0) === 'p');
1757
+ }
1758
+
1759
+ var defaultLocaleMeridiemParse = /[ap]\.?m?\.?/i;
1760
+ function localeMeridiem (hours, minutes, isLower) {
1761
+ if (hours > 11) {
1762
+ return isLower ? 'pm' : 'PM';
1763
+ } else {
1764
+ return isLower ? 'am' : 'AM';
1765
+ }
1766
+ }
1767
+
1768
+
1769
+ // MOMENTS
1770
+
1771
+ // Setting the hour should keep the time, because the user explicitly
1772
+ // specified which hour he wants. So trying to maintain the same hour (in
1773
+ // a new timezone) makes sense. Adding/subtracting hours does not follow
1774
+ // this rule.
1775
+ var getSetHour = makeGetSet('Hours', true);
1776
+
1777
+ // months
1778
+ // week
1779
+ // weekdays
1780
+ // meridiem
1781
+ var baseConfig = {
1782
+ calendar: defaultCalendar,
1783
+ longDateFormat: defaultLongDateFormat,
1784
+ invalidDate: defaultInvalidDate,
1785
+ ordinal: defaultOrdinal,
1786
+ dayOfMonthOrdinalParse: defaultDayOfMonthOrdinalParse,
1787
+ relativeTime: defaultRelativeTime,
1788
+
1789
+ months: defaultLocaleMonths,
1790
+ monthsShort: defaultLocaleMonthsShort,
1791
+
1792
+ week: defaultLocaleWeek,
1793
+
1794
+ weekdays: defaultLocaleWeekdays,
1795
+ weekdaysMin: defaultLocaleWeekdaysMin,
1796
+ weekdaysShort: defaultLocaleWeekdaysShort,
1797
+
1798
+ meridiemParse: defaultLocaleMeridiemParse
1799
+ };
1800
+
1801
+ // internal storage for locale config files
1802
+ var locales = {};
1803
+ var localeFamilies = {};
1804
+ var globalLocale;
1805
+
1806
+ function normalizeLocale(key) {
1807
+ return key ? key.toLowerCase().replace('_', '-') : key;
1808
+ }
1809
+
1810
+ // pick the locale from the array
1811
+ // try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each
1812
+ // substring from most specific to least, but move to the next array item if it's a more specific variant than the current root
1813
+ function chooseLocale(names) {
1814
+ var i = 0, j, next, locale, split;
1815
+
1816
+ while (i < names.length) {
1817
+ split = normalizeLocale(names[i]).split('-');
1818
+ j = split.length;
1819
+ next = normalizeLocale(names[i + 1]);
1820
+ next = next ? next.split('-') : null;
1821
+ while (j > 0) {
1822
+ locale = loadLocale(split.slice(0, j).join('-'));
1823
+ if (locale) {
1824
+ return locale;
1825
+ }
1826
+ if (next && next.length >= j && compareArrays(split, next, true) >= j - 1) {
1827
+ //the next array item is better than a shallower substring of this one
1828
+ break;
1829
+ }
1830
+ j--;
1831
+ }
1832
+ i++;
1833
+ }
1834
+ return null;
1835
+ }
1836
+
1837
+ function loadLocale(name) {
1838
+ var oldLocale = null;
1839
+ // TODO: Find a better way to register and load all the locales in Node
1840
+ if (!locales[name] && (typeof module !== 'undefined') &&
1841
+ module && module.exports) {
1842
+ try {
1843
+ oldLocale = globalLocale._abbr;
1844
+ var aliasedRequire = require;
1845
+ aliasedRequire('./locale/' + name);
1846
+ getSetGlobalLocale(oldLocale);
1847
+ } catch (e) {}
1848
+ }
1849
+ return locales[name];
1850
+ }
1851
+
1852
+ // This function will load locale and then set the global locale. If
1853
+ // no arguments are passed in, it will simply return the current global
1854
+ // locale key.
1855
+ function getSetGlobalLocale (key, values) {
1856
+ var data;
1857
+ if (key) {
1858
+ if (isUndefined(values)) {
1859
+ data = getLocale(key);
1860
+ }
1861
+ else {
1862
+ data = defineLocale(key, values);
1863
+ }
1864
+
1865
+ if (data) {
1866
+ // moment.duration._locale = moment._locale = data;
1867
+ globalLocale = data;
1868
+ }
1869
+ }
1870
+
1871
+ return globalLocale._abbr;
1872
+ }
1873
+
1874
+ function defineLocale (name, config) {
1875
+ if (config !== null) {
1876
+ var parentConfig = baseConfig;
1877
+ config.abbr = name;
1878
+ if (locales[name] != null) {
1879
+ deprecateSimple('defineLocaleOverride',
1880
+ 'use moment.updateLocale(localeName, config) to change ' +
1881
+ 'an existing locale. moment.defineLocale(localeName, ' +
1882
+ 'config) should only be used for creating a new locale ' +
1883
+ 'See http://momentjs.com/guides/#/warnings/define-locale/ for more info.');
1884
+ parentConfig = locales[name]._config;
1885
+ } else if (config.parentLocale != null) {
1886
+ if (locales[config.parentLocale] != null) {
1887
+ parentConfig = locales[config.parentLocale]._config;
1888
+ } else {
1889
+ if (!localeFamilies[config.parentLocale]) {
1890
+ localeFamilies[config.parentLocale] = [];
1891
+ }
1892
+ localeFamilies[config.parentLocale].push({
1893
+ name: name,
1894
+ config: config
1895
+ });
1896
+ return null;
1897
+ }
1898
+ }
1899
+ locales[name] = new Locale(mergeConfigs(parentConfig, config));
1900
+
1901
+ if (localeFamilies[name]) {
1902
+ localeFamilies[name].forEach(function (x) {
1903
+ defineLocale(x.name, x.config);
1904
+ });
1905
+ }
1906
+
1907
+ // backwards compat for now: also set the locale
1908
+ // make sure we set the locale AFTER all child locales have been
1909
+ // created, so we won't end up with the child locale set.
1910
+ getSetGlobalLocale(name);
1911
+
1912
+
1913
+ return locales[name];
1914
+ } else {
1915
+ // useful for testing
1916
+ delete locales[name];
1917
+ return null;
1918
+ }
1919
+ }
1920
+
1921
+ function updateLocale(name, config) {
1922
+ if (config != null) {
1923
+ var locale, tmpLocale, parentConfig = baseConfig;
1924
+ // MERGE
1925
+ tmpLocale = loadLocale(name);
1926
+ if (tmpLocale != null) {
1927
+ parentConfig = tmpLocale._config;
1928
+ }
1929
+ config = mergeConfigs(parentConfig, config);
1930
+ locale = new Locale(config);
1931
+ locale.parentLocale = locales[name];
1932
+ locales[name] = locale;
1933
+
1934
+ // backwards compat for now: also set the locale
1935
+ getSetGlobalLocale(name);
1936
+ } else {
1937
+ // pass null for config to unupdate, useful for tests
1938
+ if (locales[name] != null) {
1939
+ if (locales[name].parentLocale != null) {
1940
+ locales[name] = locales[name].parentLocale;
1941
+ } else if (locales[name] != null) {
1942
+ delete locales[name];
1943
+ }
1944
+ }
1945
+ }
1946
+ return locales[name];
1947
+ }
1948
+
1949
+ // returns locale data
1950
+ function getLocale (key) {
1951
+ var locale;
1952
+
1953
+ if (key && key._locale && key._locale._abbr) {
1954
+ key = key._locale._abbr;
1955
+ }
1956
+
1957
+ if (!key) {
1958
+ return globalLocale;
1959
+ }
1960
+
1961
+ if (!isArray(key)) {
1962
+ //short-circuit everything else
1963
+ locale = loadLocale(key);
1964
+ if (locale) {
1965
+ return locale;
1966
+ }
1967
+ key = [key];
1968
+ }
1969
+
1970
+ return chooseLocale(key);
1971
+ }
1972
+
1973
+ function listLocales() {
1974
+ return keys(locales);
1975
+ }
1976
+
1977
+ function checkOverflow (m) {
1978
+ var overflow;
1979
+ var a = m._a;
1980
+
1981
+ if (a && getParsingFlags(m).overflow === -2) {
1982
+ overflow =
1983
+ a[MONTH] < 0 || a[MONTH] > 11 ? MONTH :
1984
+ a[DATE] < 1 || a[DATE] > daysInMonth(a[YEAR], a[MONTH]) ? DATE :
1985
+ a[HOUR] < 0 || a[HOUR] > 24 || (a[HOUR] === 24 && (a[MINUTE] !== 0 || a[SECOND] !== 0 || a[MILLISECOND] !== 0)) ? HOUR :
1986
+ a[MINUTE] < 0 || a[MINUTE] > 59 ? MINUTE :
1987
+ a[SECOND] < 0 || a[SECOND] > 59 ? SECOND :
1988
+ a[MILLISECOND] < 0 || a[MILLISECOND] > 999 ? MILLISECOND :
1989
+ -1;
1990
+
1991
+ if (getParsingFlags(m)._overflowDayOfYear && (overflow < YEAR || overflow > DATE)) {
1992
+ overflow = DATE;
1993
+ }
1994
+ if (getParsingFlags(m)._overflowWeeks && overflow === -1) {
1995
+ overflow = WEEK;
1996
+ }
1997
+ if (getParsingFlags(m)._overflowWeekday && overflow === -1) {
1998
+ overflow = WEEKDAY;
1999
+ }
2000
+
2001
+ getParsingFlags(m).overflow = overflow;
2002
+ }
2003
+
2004
+ return m;
2005
+ }
2006
+
2007
+ // Pick the first defined of two or three arguments.
2008
+ function defaults(a, b, c) {
2009
+ if (a != null) {
2010
+ return a;
2011
+ }
2012
+ if (b != null) {
2013
+ return b;
2014
+ }
2015
+ return c;
2016
+ }
2017
+
2018
+ function currentDateArray(config) {
2019
+ // hooks is actually the exported moment object
2020
+ var nowValue = new Date(hooks.now());
2021
+ if (config._useUTC) {
2022
+ return [nowValue.getUTCFullYear(), nowValue.getUTCMonth(), nowValue.getUTCDate()];
2023
+ }
2024
+ return [nowValue.getFullYear(), nowValue.getMonth(), nowValue.getDate()];
2025
+ }
2026
+
2027
+ // convert an array to a date.
2028
+ // the array should mirror the parameters below
2029
+ // note: all values past the year are optional and will default to the lowest possible value.
2030
+ // [year, month, day , hour, minute, second, millisecond]
2031
+ function configFromArray (config) {
2032
+ var i, date, input = [], currentDate, yearToUse;
2033
+
2034
+ if (config._d) {
2035
+ return;
2036
+ }
2037
+
2038
+ currentDate = currentDateArray(config);
2039
+
2040
+ //compute day of the year from weeks and weekdays
2041
+ if (config._w && config._a[DATE] == null && config._a[MONTH] == null) {
2042
+ dayOfYearFromWeekInfo(config);
2043
+ }
2044
+
2045
+ //if the day of the year is set, figure out what it is
2046
+ if (config._dayOfYear != null) {
2047
+ yearToUse = defaults(config._a[YEAR], currentDate[YEAR]);
2048
+
2049
+ if (config._dayOfYear > daysInYear(yearToUse) || config._dayOfYear === 0) {
2050
+ getParsingFlags(config)._overflowDayOfYear = true;
2051
+ }
2052
+
2053
+ date = createUTCDate(yearToUse, 0, config._dayOfYear);
2054
+ config._a[MONTH] = date.getUTCMonth();
2055
+ config._a[DATE] = date.getUTCDate();
2056
+ }
2057
+
2058
+ // Default to current date.
2059
+ // * if no year, month, day of month are given, default to today
2060
+ // * if day of month is given, default month and year
2061
+ // * if month is given, default only year
2062
+ // * if year is given, don't default anything
2063
+ for (i = 0; i < 3 && config._a[i] == null; ++i) {
2064
+ config._a[i] = input[i] = currentDate[i];
2065
+ }
2066
+
2067
+ // Zero out whatever was not defaulted, including time
2068
+ for (; i < 7; i++) {
2069
+ config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i];
2070
+ }
2071
+
2072
+ // Check for 24:00:00.000
2073
+ if (config._a[HOUR] === 24 &&
2074
+ config._a[MINUTE] === 0 &&
2075
+ config._a[SECOND] === 0 &&
2076
+ config._a[MILLISECOND] === 0) {
2077
+ config._nextDay = true;
2078
+ config._a[HOUR] = 0;
2079
+ }
2080
+
2081
+ config._d = (config._useUTC ? createUTCDate : createDate).apply(null, input);
2082
+ // Apply timezone offset from input. The actual utcOffset can be changed
2083
+ // with parseZone.
2084
+ if (config._tzm != null) {
2085
+ config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm);
2086
+ }
2087
+
2088
+ if (config._nextDay) {
2089
+ config._a[HOUR] = 24;
2090
+ }
2091
+
2092
+ // check for mismatching day of week
2093
+ if (config._w && typeof config._w.d !== 'undefined' && config._w.d !== config._d.getDay()) {
2094
+ getParsingFlags(config).weekdayMismatch = true;
2095
+ }
2096
+ }
2097
+
2098
+ function dayOfYearFromWeekInfo(config) {
2099
+ var w, weekYear, week, weekday, dow, doy, temp, weekdayOverflow;
2100
+
2101
+ w = config._w;
2102
+ if (w.GG != null || w.W != null || w.E != null) {
2103
+ dow = 1;
2104
+ doy = 4;
2105
+
2106
+ // TODO: We need to take the current isoWeekYear, but that depends on
2107
+ // how we interpret now (local, utc, fixed offset). So create
2108
+ // a now version of current config (take local/utc/offset flags, and
2109
+ // create now).
2110
+ weekYear = defaults(w.GG, config._a[YEAR], weekOfYear(createLocal(), 1, 4).year);
2111
+ week = defaults(w.W, 1);
2112
+ weekday = defaults(w.E, 1);
2113
+ if (weekday < 1 || weekday > 7) {
2114
+ weekdayOverflow = true;
2115
+ }
2116
+ } else {
2117
+ dow = config._locale._week.dow;
2118
+ doy = config._locale._week.doy;
2119
+
2120
+ var curWeek = weekOfYear(createLocal(), dow, doy);
2121
+
2122
+ weekYear = defaults(w.gg, config._a[YEAR], curWeek.year);
2123
+
2124
+ // Default to current week.
2125
+ week = defaults(w.w, curWeek.week);
2126
+
2127
+ if (w.d != null) {
2128
+ // weekday -- low day numbers are considered next week
2129
+ weekday = w.d;
2130
+ if (weekday < 0 || weekday > 6) {
2131
+ weekdayOverflow = true;
2132
+ }
2133
+ } else if (w.e != null) {
2134
+ // local weekday -- counting starts from begining of week
2135
+ weekday = w.e + dow;
2136
+ if (w.e < 0 || w.e > 6) {
2137
+ weekdayOverflow = true;
2138
+ }
2139
+ } else {
2140
+ // default to begining of week
2141
+ weekday = dow;
2142
+ }
2143
+ }
2144
+ if (week < 1 || week > weeksInYear(weekYear, dow, doy)) {
2145
+ getParsingFlags(config)._overflowWeeks = true;
2146
+ } else if (weekdayOverflow != null) {
2147
+ getParsingFlags(config)._overflowWeekday = true;
2148
+ } else {
2149
+ temp = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy);
2150
+ config._a[YEAR] = temp.year;
2151
+ config._dayOfYear = temp.dayOfYear;
2152
+ }
2153
+ }
2154
+
2155
+ // iso 8601 regex
2156
+ // 0000-00-00 0000-W00 or 0000-W00-0 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000 or +00)
2157
+ var extendedIsoRegex = /^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/;
2158
+ var basicIsoRegex = /^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/;
2159
+
2160
+ var tzRegex = /Z|[+-]\d\d(?::?\d\d)?/;
2161
+
2162
+ var isoDates = [
2163
+ ['YYYYYY-MM-DD', /[+-]\d{6}-\d\d-\d\d/],
2164
+ ['YYYY-MM-DD', /\d{4}-\d\d-\d\d/],
2165
+ ['GGGG-[W]WW-E', /\d{4}-W\d\d-\d/],
2166
+ ['GGGG-[W]WW', /\d{4}-W\d\d/, false],
2167
+ ['YYYY-DDD', /\d{4}-\d{3}/],
2168
+ ['YYYY-MM', /\d{4}-\d\d/, false],
2169
+ ['YYYYYYMMDD', /[+-]\d{10}/],
2170
+ ['YYYYMMDD', /\d{8}/],
2171
+ // YYYYMM is NOT allowed by the standard
2172
+ ['GGGG[W]WWE', /\d{4}W\d{3}/],
2173
+ ['GGGG[W]WW', /\d{4}W\d{2}/, false],
2174
+ ['YYYYDDD', /\d{7}/]
2175
+ ];
2176
+
2177
+ // iso time formats and regexes
2178
+ var isoTimes = [
2179
+ ['HH:mm:ss.SSSS', /\d\d:\d\d:\d\d\.\d+/],
2180
+ ['HH:mm:ss,SSSS', /\d\d:\d\d:\d\d,\d+/],
2181
+ ['HH:mm:ss', /\d\d:\d\d:\d\d/],
2182
+ ['HH:mm', /\d\d:\d\d/],
2183
+ ['HHmmss.SSSS', /\d\d\d\d\d\d\.\d+/],
2184
+ ['HHmmss,SSSS', /\d\d\d\d\d\d,\d+/],
2185
+ ['HHmmss', /\d\d\d\d\d\d/],
2186
+ ['HHmm', /\d\d\d\d/],
2187
+ ['HH', /\d\d/]
2188
+ ];
2189
+
2190
+ var aspNetJsonRegex = /^\/?Date\((\-?\d+)/i;
2191
+
2192
+ // date from iso format
2193
+ function configFromISO(config) {
2194
+ var i, l,
2195
+ string = config._i,
2196
+ match = extendedIsoRegex.exec(string) || basicIsoRegex.exec(string),
2197
+ allowTime, dateFormat, timeFormat, tzFormat;
2198
+
2199
+ if (match) {
2200
+ getParsingFlags(config).iso = true;
2201
+
2202
+ for (i = 0, l = isoDates.length; i < l; i++) {
2203
+ if (isoDates[i][1].exec(match[1])) {
2204
+ dateFormat = isoDates[i][0];
2205
+ allowTime = isoDates[i][2] !== false;
2206
+ break;
2207
+ }
2208
+ }
2209
+ if (dateFormat == null) {
2210
+ config._isValid = false;
2211
+ return;
2212
+ }
2213
+ if (match[3]) {
2214
+ for (i = 0, l = isoTimes.length; i < l; i++) {
2215
+ if (isoTimes[i][1].exec(match[3])) {
2216
+ // match[2] should be 'T' or space
2217
+ timeFormat = (match[2] || ' ') + isoTimes[i][0];
2218
+ break;
2219
+ }
2220
+ }
2221
+ if (timeFormat == null) {
2222
+ config._isValid = false;
2223
+ return;
2224
+ }
2225
+ }
2226
+ if (!allowTime && timeFormat != null) {
2227
+ config._isValid = false;
2228
+ return;
2229
+ }
2230
+ if (match[4]) {
2231
+ if (tzRegex.exec(match[4])) {
2232
+ tzFormat = 'Z';
2233
+ } else {
2234
+ config._isValid = false;
2235
+ return;
2236
+ }
2237
+ }
2238
+ config._f = dateFormat + (timeFormat || '') + (tzFormat || '');
2239
+ configFromStringAndFormat(config);
2240
+ } else {
2241
+ config._isValid = false;
2242
+ }
2243
+ }
2244
+
2245
+ // RFC 2822 regex: For details see https://tools.ietf.org/html/rfc2822#section-3.3
2246
+ var rfc2822 = /^(?:(Mon|Tue|Wed|Thu|Fri|Sat|Sun),?\s)?(\d{1,2})\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(\d{2,4})\s(\d\d):(\d\d)(?::(\d\d))?\s(?:(UT|GMT|[ECMP][SD]T)|([Zz])|([+-]\d{4}))$/;
2247
+
2248
+ function extractFromRFC2822Strings(yearStr, monthStr, dayStr, hourStr, minuteStr, secondStr) {
2249
+ var result = [
2250
+ untruncateYear(yearStr),
2251
+ defaultLocaleMonthsShort.indexOf(monthStr),
2252
+ parseInt(dayStr, 10),
2253
+ parseInt(hourStr, 10),
2254
+ parseInt(minuteStr, 10)
2255
+ ];
2256
+
2257
+ if (secondStr) {
2258
+ result.push(parseInt(secondStr, 10));
2259
+ }
2260
+
2261
+ return result;
2262
+ }
2263
+
2264
+ function untruncateYear(yearStr) {
2265
+ var year = parseInt(yearStr, 10);
2266
+ if (year <= 49) {
2267
+ return 2000 + year;
2268
+ } else if (year <= 999) {
2269
+ return 1900 + year;
2270
+ }
2271
+ return year;
2272
+ }
2273
+
2274
+ function preprocessRFC2822(s) {
2275
+ // Remove comments and folding whitespace and replace multiple-spaces with a single space
2276
+ return s.replace(/\([^)]*\)|[\n\t]/g, ' ').replace(/(\s\s+)/g, ' ').trim();
2277
+ }
2278
+
2279
+ function checkWeekday(weekdayStr, parsedInput, config) {
2280
+ if (weekdayStr) {
2281
+ // TODO: Replace the vanilla JS Date object with an indepentent day-of-week check.
2282
+ var weekdayProvided = defaultLocaleWeekdaysShort.indexOf(weekdayStr),
2283
+ weekdayActual = new Date(parsedInput[0], parsedInput[1], parsedInput[2]).getDay();
2284
+ if (weekdayProvided !== weekdayActual) {
2285
+ getParsingFlags(config).weekdayMismatch = true;
2286
+ config._isValid = false;
2287
+ return false;
2288
+ }
2289
+ }
2290
+ return true;
2291
+ }
2292
+
2293
+ var obsOffsets = {
2294
+ UT: 0,
2295
+ GMT: 0,
2296
+ EDT: -4 * 60,
2297
+ EST: -5 * 60,
2298
+ CDT: -5 * 60,
2299
+ CST: -6 * 60,
2300
+ MDT: -6 * 60,
2301
+ MST: -7 * 60,
2302
+ PDT: -7 * 60,
2303
+ PST: -8 * 60
2304
+ };
2305
+
2306
+ function calculateOffset(obsOffset, militaryOffset, numOffset) {
2307
+ if (obsOffset) {
2308
+ return obsOffsets[obsOffset];
2309
+ } else if (militaryOffset) {
2310
+ // the only allowed military tz is Z
2311
+ return 0;
2312
+ } else {
2313
+ var hm = parseInt(numOffset, 10);
2314
+ var m = hm % 100, h = (hm - m) / 100;
2315
+ return h * 60 + m;
2316
+ }
2317
+ }
2318
+
2319
+ // date and time from ref 2822 format
2320
+ function configFromRFC2822(config) {
2321
+ var match = rfc2822.exec(preprocessRFC2822(config._i));
2322
+ if (match) {
2323
+ var parsedArray = extractFromRFC2822Strings(match[4], match[3], match[2], match[5], match[6], match[7]);
2324
+ if (!checkWeekday(match[1], parsedArray, config)) {
2325
+ return;
2326
+ }
2327
+
2328
+ config._a = parsedArray;
2329
+ config._tzm = calculateOffset(match[8], match[9], match[10]);
2330
+
2331
+ config._d = createUTCDate.apply(null, config._a);
2332
+ config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm);
2333
+
2334
+ getParsingFlags(config).rfc2822 = true;
2335
+ } else {
2336
+ config._isValid = false;
2337
+ }
2338
+ }
2339
+
2340
+ // date from iso format or fallback
2341
+ function configFromString(config) {
2342
+ var matched = aspNetJsonRegex.exec(config._i);
2343
+
2344
+ if (matched !== null) {
2345
+ config._d = new Date(+matched[1]);
2346
+ return;
2347
+ }
2348
+
2349
+ configFromISO(config);
2350
+ if (config._isValid === false) {
2351
+ delete config._isValid;
2352
+ } else {
2353
+ return;
2354
+ }
2355
+
2356
+ configFromRFC2822(config);
2357
+ if (config._isValid === false) {
2358
+ delete config._isValid;
2359
+ } else {
2360
+ return;
2361
+ }
2362
+
2363
+ // Final attempt, use Input Fallback
2364
+ hooks.createFromInputFallback(config);
2365
+ }
2366
+
2367
+ hooks.createFromInputFallback = deprecate(
2368
+ 'value provided is not in a recognized RFC2822 or ISO format. moment construction falls back to js Date(), ' +
2369
+ 'which is not reliable across all browsers and versions. Non RFC2822/ISO date formats are ' +
2370
+ 'discouraged and will be removed in an upcoming major release. Please refer to ' +
2371
+ 'http://momentjs.com/guides/#/warnings/js-date/ for more info.',
2372
+ function (config) {
2373
+ config._d = new Date(config._i + (config._useUTC ? ' UTC' : ''));
2374
+ }
2375
+ );
2376
+
2377
+ // constant that refers to the ISO standard
2378
+ hooks.ISO_8601 = function () {};
2379
+
2380
+ // constant that refers to the RFC 2822 form
2381
+ hooks.RFC_2822 = function () {};
2382
+
2383
+ // date from string and format string
2384
+ function configFromStringAndFormat(config) {
2385
+ // TODO: Move this to another part of the creation flow to prevent circular deps
2386
+ if (config._f === hooks.ISO_8601) {
2387
+ configFromISO(config);
2388
+ return;
2389
+ }
2390
+ if (config._f === hooks.RFC_2822) {
2391
+ configFromRFC2822(config);
2392
+ return;
2393
+ }
2394
+ config._a = [];
2395
+ getParsingFlags(config).empty = true;
2396
+
2397
+ // This array is used to make a Date, either with `new Date` or `Date.UTC`
2398
+ var string = '' + config._i,
2399
+ i, parsedInput, tokens, token, skipped,
2400
+ stringLength = string.length,
2401
+ totalParsedInputLength = 0;
2402
+
2403
+ tokens = expandFormat(config._f, config._locale).match(formattingTokens) || [];
2404
+
2405
+ for (i = 0; i < tokens.length; i++) {
2406
+ token = tokens[i];
2407
+ parsedInput = (string.match(getParseRegexForToken(token, config)) || [])[0];
2408
+ // console.log('token', token, 'parsedInput', parsedInput,
2409
+ // 'regex', getParseRegexForToken(token, config));
2410
+ if (parsedInput) {
2411
+ skipped = string.substr(0, string.indexOf(parsedInput));
2412
+ if (skipped.length > 0) {
2413
+ getParsingFlags(config).unusedInput.push(skipped);
2414
+ }
2415
+ string = string.slice(string.indexOf(parsedInput) + parsedInput.length);
2416
+ totalParsedInputLength += parsedInput.length;
2417
+ }
2418
+ // don't parse if it's not a known token
2419
+ if (formatTokenFunctions[token]) {
2420
+ if (parsedInput) {
2421
+ getParsingFlags(config).empty = false;
2422
+ }
2423
+ else {
2424
+ getParsingFlags(config).unusedTokens.push(token);
2425
+ }
2426
+ addTimeToArrayFromToken(token, parsedInput, config);
2427
+ }
2428
+ else if (config._strict && !parsedInput) {
2429
+ getParsingFlags(config).unusedTokens.push(token);
2430
+ }
2431
+ }
2432
+
2433
+ // add remaining unparsed input length to the string
2434
+ getParsingFlags(config).charsLeftOver = stringLength - totalParsedInputLength;
2435
+ if (string.length > 0) {
2436
+ getParsingFlags(config).unusedInput.push(string);
2437
+ }
2438
+
2439
+ // clear _12h flag if hour is <= 12
2440
+ if (config._a[HOUR] <= 12 &&
2441
+ getParsingFlags(config).bigHour === true &&
2442
+ config._a[HOUR] > 0) {
2443
+ getParsingFlags(config).bigHour = undefined;
2444
+ }
2445
+
2446
+ getParsingFlags(config).parsedDateParts = config._a.slice(0);
2447
+ getParsingFlags(config).meridiem = config._meridiem;
2448
+ // handle meridiem
2449
+ config._a[HOUR] = meridiemFixWrap(config._locale, config._a[HOUR], config._meridiem);
2450
+
2451
+ configFromArray(config);
2452
+ checkOverflow(config);
2453
+ }
2454
+
2455
+
2456
+ function meridiemFixWrap (locale, hour, meridiem) {
2457
+ var isPm;
2458
+
2459
+ if (meridiem == null) {
2460
+ // nothing to do
2461
+ return hour;
2462
+ }
2463
+ if (locale.meridiemHour != null) {
2464
+ return locale.meridiemHour(hour, meridiem);
2465
+ } else if (locale.isPM != null) {
2466
+ // Fallback
2467
+ isPm = locale.isPM(meridiem);
2468
+ if (isPm && hour < 12) {
2469
+ hour += 12;
2470
+ }
2471
+ if (!isPm && hour === 12) {
2472
+ hour = 0;
2473
+ }
2474
+ return hour;
2475
+ } else {
2476
+ // this is not supposed to happen
2477
+ return hour;
2478
+ }
2479
+ }
2480
+
2481
+ // date from string and array of format strings
2482
+ function configFromStringAndArray(config) {
2483
+ var tempConfig,
2484
+ bestMoment,
2485
+
2486
+ scoreToBeat,
2487
+ i,
2488
+ currentScore;
2489
+
2490
+ if (config._f.length === 0) {
2491
+ getParsingFlags(config).invalidFormat = true;
2492
+ config._d = new Date(NaN);
2493
+ return;
2494
+ }
2495
+
2496
+ for (i = 0; i < config._f.length; i++) {
2497
+ currentScore = 0;
2498
+ tempConfig = copyConfig({}, config);
2499
+ if (config._useUTC != null) {
2500
+ tempConfig._useUTC = config._useUTC;
2501
+ }
2502
+ tempConfig._f = config._f[i];
2503
+ configFromStringAndFormat(tempConfig);
2504
+
2505
+ if (!isValid(tempConfig)) {
2506
+ continue;
2507
+ }
2508
+
2509
+ // if there is any input that was not parsed add a penalty for that format
2510
+ currentScore += getParsingFlags(tempConfig).charsLeftOver;
2511
+
2512
+ //or tokens
2513
+ currentScore += getParsingFlags(tempConfig).unusedTokens.length * 10;
2514
+
2515
+ getParsingFlags(tempConfig).score = currentScore;
2516
+
2517
+ if (scoreToBeat == null || currentScore < scoreToBeat) {
2518
+ scoreToBeat = currentScore;
2519
+ bestMoment = tempConfig;
2520
+ }
2521
+ }
2522
+
2523
+ extend(config, bestMoment || tempConfig);
2524
+ }
2525
+
2526
+ function configFromObject(config) {
2527
+ if (config._d) {
2528
+ return;
2529
+ }
2530
+
2531
+ var i = normalizeObjectUnits(config._i);
2532
+ config._a = map([i.year, i.month, i.day || i.date, i.hour, i.minute, i.second, i.millisecond], function (obj) {
2533
+ return obj && parseInt(obj, 10);
2534
+ });
2535
+
2536
+ configFromArray(config);
2537
+ }
2538
+
2539
+ function createFromConfig (config) {
2540
+ var res = new Moment(checkOverflow(prepareConfig(config)));
2541
+ if (res._nextDay) {
2542
+ // Adding is smart enough around DST
2543
+ res.add(1, 'd');
2544
+ res._nextDay = undefined;
2545
+ }
2546
+
2547
+ return res;
2548
+ }
2549
+
2550
+ function prepareConfig (config) {
2551
+ var input = config._i,
2552
+ format = config._f;
2553
+
2554
+ config._locale = config._locale || getLocale(config._l);
2555
+
2556
+ if (input === null || (format === undefined && input === '')) {
2557
+ return createInvalid({nullInput: true});
2558
+ }
2559
+
2560
+ if (typeof input === 'string') {
2561
+ config._i = input = config._locale.preparse(input);
2562
+ }
2563
+
2564
+ if (isMoment(input)) {
2565
+ return new Moment(checkOverflow(input));
2566
+ } else if (isDate(input)) {
2567
+ config._d = input;
2568
+ } else if (isArray(format)) {
2569
+ configFromStringAndArray(config);
2570
+ } else if (format) {
2571
+ configFromStringAndFormat(config);
2572
+ } else {
2573
+ configFromInput(config);
2574
+ }
2575
+
2576
+ if (!isValid(config)) {
2577
+ config._d = null;
2578
+ }
2579
+
2580
+ return config;
2581
+ }
2582
+
2583
+ function configFromInput(config) {
2584
+ var input = config._i;
2585
+ if (isUndefined(input)) {
2586
+ config._d = new Date(hooks.now());
2587
+ } else if (isDate(input)) {
2588
+ config._d = new Date(input.valueOf());
2589
+ } else if (typeof input === 'string') {
2590
+ configFromString(config);
2591
+ } else if (isArray(input)) {
2592
+ config._a = map(input.slice(0), function (obj) {
2593
+ return parseInt(obj, 10);
2594
+ });
2595
+ configFromArray(config);
2596
+ } else if (isObject(input)) {
2597
+ configFromObject(config);
2598
+ } else if (isNumber(input)) {
2599
+ // from milliseconds
2600
+ config._d = new Date(input);
2601
+ } else {
2602
+ hooks.createFromInputFallback(config);
2603
+ }
2604
+ }
2605
+
2606
+ function createLocalOrUTC (input, format, locale, strict, isUTC) {
2607
+ var c = {};
2608
+
2609
+ if (locale === true || locale === false) {
2610
+ strict = locale;
2611
+ locale = undefined;
2612
+ }
2613
+
2614
+ if ((isObject(input) && isObjectEmpty(input)) ||
2615
+ (isArray(input) && input.length === 0)) {
2616
+ input = undefined;
2617
+ }
2618
+ // object construction must be done this way.
2619
+ // https://github.com/moment/moment/issues/1423
2620
+ c._isAMomentObject = true;
2621
+ c._useUTC = c._isUTC = isUTC;
2622
+ c._l = locale;
2623
+ c._i = input;
2624
+ c._f = format;
2625
+ c._strict = strict;
2626
+
2627
+ return createFromConfig(c);
2628
+ }
2629
+
2630
+ function createLocal (input, format, locale, strict) {
2631
+ return createLocalOrUTC(input, format, locale, strict, false);
2632
+ }
2633
+
2634
+ var prototypeMin = deprecate(
2635
+ 'moment().min is deprecated, use moment.max instead. http://momentjs.com/guides/#/warnings/min-max/',
2636
+ function () {
2637
+ var other = createLocal.apply(null, arguments);
2638
+ if (this.isValid() && other.isValid()) {
2639
+ return other < this ? this : other;
2640
+ } else {
2641
+ return createInvalid();
2642
+ }
2643
+ }
2644
+ );
2645
+
2646
+ var prototypeMax = deprecate(
2647
+ 'moment().max is deprecated, use moment.min instead. http://momentjs.com/guides/#/warnings/min-max/',
2648
+ function () {
2649
+ var other = createLocal.apply(null, arguments);
2650
+ if (this.isValid() && other.isValid()) {
2651
+ return other > this ? this : other;
2652
+ } else {
2653
+ return createInvalid();
2654
+ }
2655
+ }
2656
+ );
2657
+
2658
+ // Pick a moment m from moments so that m[fn](other) is true for all
2659
+ // other. This relies on the function fn to be transitive.
2660
+ //
2661
+ // moments should either be an array of moment objects or an array, whose
2662
+ // first element is an array of moment objects.
2663
+ function pickBy(fn, moments) {
2664
+ var res, i;
2665
+ if (moments.length === 1 && isArray(moments[0])) {
2666
+ moments = moments[0];
2667
+ }
2668
+ if (!moments.length) {
2669
+ return createLocal();
2670
+ }
2671
+ res = moments[0];
2672
+ for (i = 1; i < moments.length; ++i) {
2673
+ if (!moments[i].isValid() || moments[i][fn](res)) {
2674
+ res = moments[i];
2675
+ }
2676
+ }
2677
+ return res;
2678
+ }
2679
+
2680
+ // TODO: Use [].sort instead?
2681
+ function min () {
2682
+ var args = [].slice.call(arguments, 0);
2683
+
2684
+ return pickBy('isBefore', args);
2685
+ }
2686
+
2687
+ function max () {
2688
+ var args = [].slice.call(arguments, 0);
2689
+
2690
+ return pickBy('isAfter', args);
2691
+ }
2692
+
2693
+ var now = function () {
2694
+ return Date.now ? Date.now() : +(new Date());
2695
+ };
2696
+
2697
+ var ordering = ['year', 'quarter', 'month', 'week', 'day', 'hour', 'minute', 'second', 'millisecond'];
2698
+
2699
+ function isDurationValid(m) {
2700
+ for (var key in m) {
2701
+ if (!(indexOf.call(ordering, key) !== -1 && (m[key] == null || !isNaN(m[key])))) {
2702
+ return false;
2703
+ }
2704
+ }
2705
+
2706
+ var unitHasDecimal = false;
2707
+ for (var i = 0; i < ordering.length; ++i) {
2708
+ if (m[ordering[i]]) {
2709
+ if (unitHasDecimal) {
2710
+ return false; // only allow non-integers for smallest unit
2711
+ }
2712
+ if (parseFloat(m[ordering[i]]) !== toInt(m[ordering[i]])) {
2713
+ unitHasDecimal = true;
2714
+ }
2715
+ }
2716
+ }
2717
+
2718
+ return true;
2719
+ }
2720
+
2721
+ function isValid$1() {
2722
+ return this._isValid;
2723
+ }
2724
+
2725
+ function createInvalid$1() {
2726
+ return createDuration(NaN);
2727
+ }
2728
+
2729
+ function Duration (duration) {
2730
+ var normalizedInput = normalizeObjectUnits(duration),
2731
+ years = normalizedInput.year || 0,
2732
+ quarters = normalizedInput.quarter || 0,
2733
+ months = normalizedInput.month || 0,
2734
+ weeks = normalizedInput.week || 0,
2735
+ days = normalizedInput.day || 0,
2736
+ hours = normalizedInput.hour || 0,
2737
+ minutes = normalizedInput.minute || 0,
2738
+ seconds = normalizedInput.second || 0,
2739
+ milliseconds = normalizedInput.millisecond || 0;
2740
+
2741
+ this._isValid = isDurationValid(normalizedInput);
2742
+
2743
+ // representation for dateAddRemove
2744
+ this._milliseconds = +milliseconds +
2745
+ seconds * 1e3 + // 1000
2746
+ minutes * 6e4 + // 1000 * 60
2747
+ hours * 1000 * 60 * 60; //using 1000 * 60 * 60 instead of 36e5 to avoid floating point rounding errors https://github.com/moment/moment/issues/2978
2748
+ // Because of dateAddRemove treats 24 hours as different from a
2749
+ // day when working around DST, we need to store them separately
2750
+ this._days = +days +
2751
+ weeks * 7;
2752
+ // It is impossible to translate months into days without knowing
2753
+ // which months you are are talking about, so we have to store
2754
+ // it separately.
2755
+ this._months = +months +
2756
+ quarters * 3 +
2757
+ years * 12;
2758
+
2759
+ this._data = {};
2760
+
2761
+ this._locale = getLocale();
2762
+
2763
+ this._bubble();
2764
+ }
2765
+
2766
+ function isDuration (obj) {
2767
+ return obj instanceof Duration;
2768
+ }
2769
+
2770
+ function absRound (number) {
2771
+ if (number < 0) {
2772
+ return Math.round(-1 * number) * -1;
2773
+ } else {
2774
+ return Math.round(number);
2775
+ }
2776
+ }
2777
+
2778
+ // FORMATTING
2779
+
2780
+ function offset (token, separator) {
2781
+ addFormatToken(token, 0, 0, function () {
2782
+ var offset = this.utcOffset();
2783
+ var sign = '+';
2784
+ if (offset < 0) {
2785
+ offset = -offset;
2786
+ sign = '-';
2787
+ }
2788
+ return sign + zeroFill(~~(offset / 60), 2) + separator + zeroFill(~~(offset) % 60, 2);
2789
+ });
2790
+ }
2791
+
2792
+ offset('Z', ':');
2793
+ offset('ZZ', '');
2794
+
2795
+ // PARSING
2796
+
2797
+ addRegexToken('Z', matchShortOffset);
2798
+ addRegexToken('ZZ', matchShortOffset);
2799
+ addParseToken(['Z', 'ZZ'], function (input, array, config) {
2800
+ config._useUTC = true;
2801
+ config._tzm = offsetFromString(matchShortOffset, input);
2802
+ });
2803
+
2804
+ // HELPERS
2805
+
2806
+ // timezone chunker
2807
+ // '+10:00' > ['10', '00']
2808
+ // '-1530' > ['-15', '30']
2809
+ var chunkOffset = /([\+\-]|\d\d)/gi;
2810
+
2811
+ function offsetFromString(matcher, string) {
2812
+ var matches = (string || '').match(matcher);
2813
+
2814
+ if (matches === null) {
2815
+ return null;
2816
+ }
2817
+
2818
+ var chunk = matches[matches.length - 1] || [];
2819
+ var parts = (chunk + '').match(chunkOffset) || ['-', 0, 0];
2820
+ var minutes = +(parts[1] * 60) + toInt(parts[2]);
2821
+
2822
+ return minutes === 0 ?
2823
+ 0 :
2824
+ parts[0] === '+' ? minutes : -minutes;
2825
+ }
2826
+
2827
+ // Return a moment from input, that is local/utc/zone equivalent to model.
2828
+ function cloneWithOffset(input, model) {
2829
+ var res, diff;
2830
+ if (model._isUTC) {
2831
+ res = model.clone();
2832
+ diff = (isMoment(input) || isDate(input) ? input.valueOf() : createLocal(input).valueOf()) - res.valueOf();
2833
+ // Use low-level api, because this fn is low-level api.
2834
+ res._d.setTime(res._d.valueOf() + diff);
2835
+ hooks.updateOffset(res, false);
2836
+ return res;
2837
+ } else {
2838
+ return createLocal(input).local();
2839
+ }
2840
+ }
2841
+
2842
+ function getDateOffset (m) {
2843
+ // On Firefox.24 Date#getTimezoneOffset returns a floating point.
2844
+ // https://github.com/moment/moment/pull/1871
2845
+ return -Math.round(m._d.getTimezoneOffset() / 15) * 15;
2846
+ }
2847
+
2848
+ // HOOKS
2849
+
2850
+ // This function will be called whenever a moment is mutated.
2851
+ // It is intended to keep the offset in sync with the timezone.
2852
+ hooks.updateOffset = function () {};
2853
+
2854
+ // MOMENTS
2855
+
2856
+ // keepLocalTime = true means only change the timezone, without
2857
+ // affecting the local hour. So 5:31:26 +0300 --[utcOffset(2, true)]-->
2858
+ // 5:31:26 +0200 It is possible that 5:31:26 doesn't exist with offset
2859
+ // +0200, so we adjust the time as needed, to be valid.
2860
+ //
2861
+ // Keeping the time actually adds/subtracts (one hour)
2862
+ // from the actual represented time. That is why we call updateOffset
2863
+ // a second time. In case it wants us to change the offset again
2864
+ // _changeInProgress == true case, then we have to adjust, because
2865
+ // there is no such time in the given timezone.
2866
+ function getSetOffset (input, keepLocalTime, keepMinutes) {
2867
+ var offset = this._offset || 0,
2868
+ localAdjust;
2869
+ if (!this.isValid()) {
2870
+ return input != null ? this : NaN;
2871
+ }
2872
+ if (input != null) {
2873
+ if (typeof input === 'string') {
2874
+ input = offsetFromString(matchShortOffset, input);
2875
+ if (input === null) {
2876
+ return this;
2877
+ }
2878
+ } else if (Math.abs(input) < 16 && !keepMinutes) {
2879
+ input = input * 60;
2880
+ }
2881
+ if (!this._isUTC && keepLocalTime) {
2882
+ localAdjust = getDateOffset(this);
2883
+ }
2884
+ this._offset = input;
2885
+ this._isUTC = true;
2886
+ if (localAdjust != null) {
2887
+ this.add(localAdjust, 'm');
2888
+ }
2889
+ if (offset !== input) {
2890
+ if (!keepLocalTime || this._changeInProgress) {
2891
+ addSubtract(this, createDuration(input - offset, 'm'), 1, false);
2892
+ } else if (!this._changeInProgress) {
2893
+ this._changeInProgress = true;
2894
+ hooks.updateOffset(this, true);
2895
+ this._changeInProgress = null;
2896
+ }
2897
+ }
2898
+ return this;
2899
+ } else {
2900
+ return this._isUTC ? offset : getDateOffset(this);
2901
+ }
2902
+ }
2903
+
2904
+ function getSetZone (input, keepLocalTime) {
2905
+ if (input != null) {
2906
+ if (typeof input !== 'string') {
2907
+ input = -input;
2908
+ }
2909
+
2910
+ this.utcOffset(input, keepLocalTime);
2911
+
2912
+ return this;
2913
+ } else {
2914
+ return -this.utcOffset();
2915
+ }
2916
+ }
2917
+
2918
+ function setOffsetToUTC (keepLocalTime) {
2919
+ return this.utcOffset(0, keepLocalTime);
2920
+ }
2921
+
2922
+ function setOffsetToLocal (keepLocalTime) {
2923
+ if (this._isUTC) {
2924
+ this.utcOffset(0, keepLocalTime);
2925
+ this._isUTC = false;
2926
+
2927
+ if (keepLocalTime) {
2928
+ this.subtract(getDateOffset(this), 'm');
2929
+ }
2930
+ }
2931
+ return this;
2932
+ }
2933
+
2934
+ function setOffsetToParsedOffset () {
2935
+ if (this._tzm != null) {
2936
+ this.utcOffset(this._tzm, false, true);
2937
+ } else if (typeof this._i === 'string') {
2938
+ var tZone = offsetFromString(matchOffset, this._i);
2939
+ if (tZone != null) {
2940
+ this.utcOffset(tZone);
2941
+ }
2942
+ else {
2943
+ this.utcOffset(0, true);
2944
+ }
2945
+ }
2946
+ return this;
2947
+ }
2948
+
2949
+ function hasAlignedHourOffset (input) {
2950
+ if (!this.isValid()) {
2951
+ return false;
2952
+ }
2953
+ input = input ? createLocal(input).utcOffset() : 0;
2954
+
2955
+ return (this.utcOffset() - input) % 60 === 0;
2956
+ }
2957
+
2958
+ function isDaylightSavingTime () {
2959
+ return (
2960
+ this.utcOffset() > this.clone().month(0).utcOffset() ||
2961
+ this.utcOffset() > this.clone().month(5).utcOffset()
2962
+ );
2963
+ }
2964
+
2965
+ function isDaylightSavingTimeShifted () {
2966
+ if (!isUndefined(this._isDSTShifted)) {
2967
+ return this._isDSTShifted;
2968
+ }
2969
+
2970
+ var c = {};
2971
+
2972
+ copyConfig(c, this);
2973
+ c = prepareConfig(c);
2974
+
2975
+ if (c._a) {
2976
+ var other = c._isUTC ? createUTC(c._a) : createLocal(c._a);
2977
+ this._isDSTShifted = this.isValid() &&
2978
+ compareArrays(c._a, other.toArray()) > 0;
2979
+ } else {
2980
+ this._isDSTShifted = false;
2981
+ }
2982
+
2983
+ return this._isDSTShifted;
2984
+ }
2985
+
2986
+ function isLocal () {
2987
+ return this.isValid() ? !this._isUTC : false;
2988
+ }
2989
+
2990
+ function isUtcOffset () {
2991
+ return this.isValid() ? this._isUTC : false;
2992
+ }
2993
+
2994
+ function isUtc () {
2995
+ return this.isValid() ? this._isUTC && this._offset === 0 : false;
2996
+ }
2997
+
2998
+ // ASP.NET json date format regex
2999
+ var aspNetRegex = /^(\-|\+)?(?:(\d*)[. ])?(\d+)\:(\d+)(?:\:(\d+)(\.\d*)?)?$/;
3000
+
3001
+ // from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html
3002
+ // somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere
3003
+ // and further modified to allow for strings containing both week and day
3004
+ var isoRegex = /^(-|\+)?P(?:([-+]?[0-9,.]*)Y)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)W)?(?:([-+]?[0-9,.]*)D)?(?:T(?:([-+]?[0-9,.]*)H)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)S)?)?$/;
3005
+
3006
+ function createDuration (input, key) {
3007
+ var duration = input,
3008
+ // matching against regexp is expensive, do it on demand
3009
+ match = null,
3010
+ sign,
3011
+ ret,
3012
+ diffRes;
3013
+
3014
+ if (isDuration(input)) {
3015
+ duration = {
3016
+ ms : input._milliseconds,
3017
+ d : input._days,
3018
+ M : input._months
3019
+ };
3020
+ } else if (isNumber(input)) {
3021
+ duration = {};
3022
+ if (key) {
3023
+ duration[key] = input;
3024
+ } else {
3025
+ duration.milliseconds = input;
3026
+ }
3027
+ } else if (!!(match = aspNetRegex.exec(input))) {
3028
+ sign = (match[1] === '-') ? -1 : 1;
3029
+ duration = {
3030
+ y : 0,
3031
+ d : toInt(match[DATE]) * sign,
3032
+ h : toInt(match[HOUR]) * sign,
3033
+ m : toInt(match[MINUTE]) * sign,
3034
+ s : toInt(match[SECOND]) * sign,
3035
+ ms : toInt(absRound(match[MILLISECOND] * 1000)) * sign // the millisecond decimal point is included in the match
3036
+ };
3037
+ } else if (!!(match = isoRegex.exec(input))) {
3038
+ sign = (match[1] === '-') ? -1 : (match[1] === '+') ? 1 : 1;
3039
+ duration = {
3040
+ y : parseIso(match[2], sign),
3041
+ M : parseIso(match[3], sign),
3042
+ w : parseIso(match[4], sign),
3043
+ d : parseIso(match[5], sign),
3044
+ h : parseIso(match[6], sign),
3045
+ m : parseIso(match[7], sign),
3046
+ s : parseIso(match[8], sign)
3047
+ };
3048
+ } else if (duration == null) {// checks for null or undefined
3049
+ duration = {};
3050
+ } else if (typeof duration === 'object' && ('from' in duration || 'to' in duration)) {
3051
+ diffRes = momentsDifference(createLocal(duration.from), createLocal(duration.to));
3052
+
3053
+ duration = {};
3054
+ duration.ms = diffRes.milliseconds;
3055
+ duration.M = diffRes.months;
3056
+ }
3057
+
3058
+ ret = new Duration(duration);
3059
+
3060
+ if (isDuration(input) && hasOwnProp(input, '_locale')) {
3061
+ ret._locale = input._locale;
3062
+ }
3063
+
3064
+ return ret;
3065
+ }
3066
+
3067
+ createDuration.fn = Duration.prototype;
3068
+ createDuration.invalid = createInvalid$1;
3069
+
3070
+ function parseIso (inp, sign) {
3071
+ // We'd normally use ~~inp for this, but unfortunately it also
3072
+ // converts floats to ints.
3073
+ // inp may be undefined, so careful calling replace on it.
3074
+ var res = inp && parseFloat(inp.replace(',', '.'));
3075
+ // apply sign while we're at it
3076
+ return (isNaN(res) ? 0 : res) * sign;
3077
+ }
3078
+
3079
+ function positiveMomentsDifference(base, other) {
3080
+ var res = {milliseconds: 0, months: 0};
3081
+
3082
+ res.months = other.month() - base.month() +
3083
+ (other.year() - base.year()) * 12;
3084
+ if (base.clone().add(res.months, 'M').isAfter(other)) {
3085
+ --res.months;
3086
+ }
3087
+
3088
+ res.milliseconds = +other - +(base.clone().add(res.months, 'M'));
3089
+
3090
+ return res;
3091
+ }
3092
+
3093
+ function momentsDifference(base, other) {
3094
+ var res;
3095
+ if (!(base.isValid() && other.isValid())) {
3096
+ return {milliseconds: 0, months: 0};
3097
+ }
3098
+
3099
+ other = cloneWithOffset(other, base);
3100
+ if (base.isBefore(other)) {
3101
+ res = positiveMomentsDifference(base, other);
3102
+ } else {
3103
+ res = positiveMomentsDifference(other, base);
3104
+ res.milliseconds = -res.milliseconds;
3105
+ res.months = -res.months;
3106
+ }
3107
+
3108
+ return res;
3109
+ }
3110
+
3111
+ // TODO: remove 'name' arg after deprecation is removed
3112
+ function createAdder(direction, name) {
3113
+ return function (val, period) {
3114
+ var dur, tmp;
3115
+ //invert the arguments, but complain about it
3116
+ if (period !== null && !isNaN(+period)) {
3117
+ deprecateSimple(name, 'moment().' + name + '(period, number) is deprecated. Please use moment().' + name + '(number, period). ' +
3118
+ 'See http://momentjs.com/guides/#/warnings/add-inverted-param/ for more info.');
3119
+ tmp = val; val = period; period = tmp;
3120
+ }
3121
+
3122
+ val = typeof val === 'string' ? +val : val;
3123
+ dur = createDuration(val, period);
3124
+ addSubtract(this, dur, direction);
3125
+ return this;
3126
+ };
3127
+ }
3128
+
3129
+ function addSubtract (mom, duration, isAdding, updateOffset) {
3130
+ var milliseconds = duration._milliseconds,
3131
+ days = absRound(duration._days),
3132
+ months = absRound(duration._months);
3133
+
3134
+ if (!mom.isValid()) {
3135
+ // No op
3136
+ return;
3137
+ }
3138
+
3139
+ updateOffset = updateOffset == null ? true : updateOffset;
3140
+
3141
+ if (months) {
3142
+ setMonth(mom, get(mom, 'Month') + months * isAdding);
3143
+ }
3144
+ if (days) {
3145
+ set$1(mom, 'Date', get(mom, 'Date') + days * isAdding);
3146
+ }
3147
+ if (milliseconds) {
3148
+ mom._d.setTime(mom._d.valueOf() + milliseconds * isAdding);
3149
+ }
3150
+ if (updateOffset) {
3151
+ hooks.updateOffset(mom, days || months);
3152
+ }
3153
+ }
3154
+
3155
+ var add = createAdder(1, 'add');
3156
+ var subtract = createAdder(-1, 'subtract');
3157
+
3158
+ function getCalendarFormat(myMoment, now) {
3159
+ var diff = myMoment.diff(now, 'days', true);
3160
+ return diff < -6 ? 'sameElse' :
3161
+ diff < -1 ? 'lastWeek' :
3162
+ diff < 0 ? 'lastDay' :
3163
+ diff < 1 ? 'sameDay' :
3164
+ diff < 2 ? 'nextDay' :
3165
+ diff < 7 ? 'nextWeek' : 'sameElse';
3166
+ }
3167
+
3168
+ function calendar$1 (time, formats) {
3169
+ // We want to compare the start of today, vs this.
3170
+ // Getting start-of-today depends on whether we're local/utc/offset or not.
3171
+ var now = time || createLocal(),
3172
+ sod = cloneWithOffset(now, this).startOf('day'),
3173
+ format = hooks.calendarFormat(this, sod) || 'sameElse';
3174
+
3175
+ var output = formats && (isFunction(formats[format]) ? formats[format].call(this, now) : formats[format]);
3176
+
3177
+ return this.format(output || this.localeData().calendar(format, this, createLocal(now)));
3178
+ }
3179
+
3180
+ function clone () {
3181
+ return new Moment(this);
3182
+ }
3183
+
3184
+ function isAfter (input, units) {
3185
+ var localInput = isMoment(input) ? input : createLocal(input);
3186
+ if (!(this.isValid() && localInput.isValid())) {
3187
+ return false;
3188
+ }
3189
+ units = normalizeUnits(!isUndefined(units) ? units : 'millisecond');
3190
+ if (units === 'millisecond') {
3191
+ return this.valueOf() > localInput.valueOf();
3192
+ } else {
3193
+ return localInput.valueOf() < this.clone().startOf(units).valueOf();
3194
+ }
3195
+ }
3196
+
3197
+ function isBefore (input, units) {
3198
+ var localInput = isMoment(input) ? input : createLocal(input);
3199
+ if (!(this.isValid() && localInput.isValid())) {
3200
+ return false;
3201
+ }
3202
+ units = normalizeUnits(!isUndefined(units) ? units : 'millisecond');
3203
+ if (units === 'millisecond') {
3204
+ return this.valueOf() < localInput.valueOf();
3205
+ } else {
3206
+ return this.clone().endOf(units).valueOf() < localInput.valueOf();
3207
+ }
3208
+ }
3209
+
3210
+ function isBetween (from, to, units, inclusivity) {
3211
+ inclusivity = inclusivity || '()';
3212
+ return (inclusivity[0] === '(' ? this.isAfter(from, units) : !this.isBefore(from, units)) &&
3213
+ (inclusivity[1] === ')' ? this.isBefore(to, units) : !this.isAfter(to, units));
3214
+ }
3215
+
3216
+ function isSame (input, units) {
3217
+ var localInput = isMoment(input) ? input : createLocal(input),
3218
+ inputMs;
3219
+ if (!(this.isValid() && localInput.isValid())) {
3220
+ return false;
3221
+ }
3222
+ units = normalizeUnits(units || 'millisecond');
3223
+ if (units === 'millisecond') {
3224
+ return this.valueOf() === localInput.valueOf();
3225
+ } else {
3226
+ inputMs = localInput.valueOf();
3227
+ return this.clone().startOf(units).valueOf() <= inputMs && inputMs <= this.clone().endOf(units).valueOf();
3228
+ }
3229
+ }
3230
+
3231
+ function isSameOrAfter (input, units) {
3232
+ return this.isSame(input, units) || this.isAfter(input,units);
3233
+ }
3234
+
3235
+ function isSameOrBefore (input, units) {
3236
+ return this.isSame(input, units) || this.isBefore(input,units);
3237
+ }
3238
+
3239
+ function diff (input, units, asFloat) {
3240
+ var that,
3241
+ zoneDelta,
3242
+ delta, output;
3243
+
3244
+ if (!this.isValid()) {
3245
+ return NaN;
3246
+ }
3247
+
3248
+ that = cloneWithOffset(input, this);
3249
+
3250
+ if (!that.isValid()) {
3251
+ return NaN;
3252
+ }
3253
+
3254
+ zoneDelta = (that.utcOffset() - this.utcOffset()) * 6e4;
3255
+
3256
+ units = normalizeUnits(units);
3257
+
3258
+ switch (units) {
3259
+ case 'year': output = monthDiff(this, that) / 12; break;
3260
+ case 'month': output = monthDiff(this, that); break;
3261
+ case 'quarter': output = monthDiff(this, that) / 3; break;
3262
+ case 'second': output = (this - that) / 1e3; break; // 1000
3263
+ case 'minute': output = (this - that) / 6e4; break; // 1000 * 60
3264
+ case 'hour': output = (this - that) / 36e5; break; // 1000 * 60 * 60
3265
+ case 'day': output = (this - that - zoneDelta) / 864e5; break; // 1000 * 60 * 60 * 24, negate dst
3266
+ case 'week': output = (this - that - zoneDelta) / 6048e5; break; // 1000 * 60 * 60 * 24 * 7, negate dst
3267
+ default: output = this - that;
3268
+ }
3269
+
3270
+ return asFloat ? output : absFloor(output);
3271
+ }
3272
+
3273
+ function monthDiff (a, b) {
3274
+ // difference in months
3275
+ var wholeMonthDiff = ((b.year() - a.year()) * 12) + (b.month() - a.month()),
3276
+ // b is in (anchor - 1 month, anchor + 1 month)
3277
+ anchor = a.clone().add(wholeMonthDiff, 'months'),
3278
+ anchor2, adjust;
3279
+
3280
+ if (b - anchor < 0) {
3281
+ anchor2 = a.clone().add(wholeMonthDiff - 1, 'months');
3282
+ // linear across the month
3283
+ adjust = (b - anchor) / (anchor - anchor2);
3284
+ } else {
3285
+ anchor2 = a.clone().add(wholeMonthDiff + 1, 'months');
3286
+ // linear across the month
3287
+ adjust = (b - anchor) / (anchor2 - anchor);
3288
+ }
3289
+
3290
+ //check for negative zero, return zero if negative zero
3291
+ return -(wholeMonthDiff + adjust) || 0;
3292
+ }
3293
+
3294
+ hooks.defaultFormat = 'YYYY-MM-DDTHH:mm:ssZ';
3295
+ hooks.defaultFormatUtc = 'YYYY-MM-DDTHH:mm:ss[Z]';
3296
+
3297
+ function toString () {
3298
+ return this.clone().locale('en').format('ddd MMM DD YYYY HH:mm:ss [GMT]ZZ');
3299
+ }
3300
+
3301
+ function toISOString() {
3302
+ if (!this.isValid()) {
3303
+ return null;
3304
+ }
3305
+ var m = this.clone().utc();
3306
+ if (m.year() < 0 || m.year() > 9999) {
3307
+ return formatMoment(m, 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]');
3308
+ }
3309
+ if (isFunction(Date.prototype.toISOString)) {
3310
+ // native implementation is ~50x faster, use it when we can
3311
+ return this.toDate().toISOString();
3312
+ }
3313
+ return formatMoment(m, 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]');
3314
+ }
3315
+
3316
+ /**
3317
+ * Return a human readable representation of a moment that can
3318
+ * also be evaluated to get a new moment which is the same
3319
+ *
3320
+ * @link https://nodejs.org/dist/latest/docs/api/util.html#util_custom_inspect_function_on_objects
3321
+ */
3322
+ function inspect () {
3323
+ if (!this.isValid()) {
3324
+ return 'moment.invalid(/* ' + this._i + ' */)';
3325
+ }
3326
+ var func = 'moment';
3327
+ var zone = '';
3328
+ if (!this.isLocal()) {
3329
+ func = this.utcOffset() === 0 ? 'moment.utc' : 'moment.parseZone';
3330
+ zone = 'Z';
3331
+ }
3332
+ var prefix = '[' + func + '("]';
3333
+ var year = (0 <= this.year() && this.year() <= 9999) ? 'YYYY' : 'YYYYYY';
3334
+ var datetime = '-MM-DD[T]HH:mm:ss.SSS';
3335
+ var suffix = zone + '[")]';
3336
+
3337
+ return this.format(prefix + year + datetime + suffix);
3338
+ }
3339
+
3340
+ function format (inputString) {
3341
+ if (!inputString) {
3342
+ inputString = this.isUtc() ? hooks.defaultFormatUtc : hooks.defaultFormat;
3343
+ }
3344
+ var output = formatMoment(this, inputString);
3345
+ return this.localeData().postformat(output);
3346
+ }
3347
+
3348
+ function from (time, withoutSuffix) {
3349
+ if (this.isValid() &&
3350
+ ((isMoment(time) && time.isValid()) ||
3351
+ createLocal(time).isValid())) {
3352
+ return createDuration({to: this, from: time}).locale(this.locale()).humanize(!withoutSuffix);
3353
+ } else {
3354
+ return this.localeData().invalidDate();
3355
+ }
3356
+ }
3357
+
3358
+ function fromNow (withoutSuffix) {
3359
+ return this.from(createLocal(), withoutSuffix);
3360
+ }
3361
+
3362
+ function to (time, withoutSuffix) {
3363
+ if (this.isValid() &&
3364
+ ((isMoment(time) && time.isValid()) ||
3365
+ createLocal(time).isValid())) {
3366
+ return createDuration({from: this, to: time}).locale(this.locale()).humanize(!withoutSuffix);
3367
+ } else {
3368
+ return this.localeData().invalidDate();
3369
+ }
3370
+ }
3371
+
3372
+ function toNow (withoutSuffix) {
3373
+ return this.to(createLocal(), withoutSuffix);
3374
+ }
3375
+
3376
+ // If passed a locale key, it will set the locale for this
3377
+ // instance. Otherwise, it will return the locale configuration
3378
+ // variables for this instance.
3379
+ function locale (key) {
3380
+ var newLocaleData;
3381
+
3382
+ if (key === undefined) {
3383
+ return this._locale._abbr;
3384
+ } else {
3385
+ newLocaleData = getLocale(key);
3386
+ if (newLocaleData != null) {
3387
+ this._locale = newLocaleData;
3388
+ }
3389
+ return this;
3390
+ }
3391
+ }
3392
+
3393
+ var lang = deprecate(
3394
+ 'moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.',
3395
+ function (key) {
3396
+ if (key === undefined) {
3397
+ return this.localeData();
3398
+ } else {
3399
+ return this.locale(key);
3400
+ }
3401
+ }
3402
+ );
3403
+
3404
+ function localeData () {
3405
+ return this._locale;
3406
+ }
3407
+
3408
+ function startOf (units) {
3409
+ units = normalizeUnits(units);
3410
+ // the following switch intentionally omits break keywords
3411
+ // to utilize falling through the cases.
3412
+ switch (units) {
3413
+ case 'year':
3414
+ this.month(0);
3415
+ /* falls through */
3416
+ case 'quarter':
3417
+ case 'month':
3418
+ this.date(1);
3419
+ /* falls through */
3420
+ case 'week':
3421
+ case 'isoWeek':
3422
+ case 'day':
3423
+ case 'date':
3424
+ this.hours(0);
3425
+ /* falls through */
3426
+ case 'hour':
3427
+ this.minutes(0);
3428
+ /* falls through */
3429
+ case 'minute':
3430
+ this.seconds(0);
3431
+ /* falls through */
3432
+ case 'second':
3433
+ this.milliseconds(0);
3434
+ }
3435
+
3436
+ // weeks are a special case
3437
+ if (units === 'week') {
3438
+ this.weekday(0);
3439
+ }
3440
+ if (units === 'isoWeek') {
3441
+ this.isoWeekday(1);
3442
+ }
3443
+
3444
+ // quarters are also special
3445
+ if (units === 'quarter') {
3446
+ this.month(Math.floor(this.month() / 3) * 3);
3447
+ }
3448
+
3449
+ return this;
3450
+ }
3451
+
3452
+ function endOf (units) {
3453
+ units = normalizeUnits(units);
3454
+ if (units === undefined || units === 'millisecond') {
3455
+ return this;
3456
+ }
3457
+
3458
+ // 'date' is an alias for 'day', so it should be considered as such.
3459
+ if (units === 'date') {
3460
+ units = 'day';
3461
+ }
3462
+
3463
+ return this.startOf(units).add(1, (units === 'isoWeek' ? 'week' : units)).subtract(1, 'ms');
3464
+ }
3465
+
3466
+ function valueOf () {
3467
+ return this._d.valueOf() - ((this._offset || 0) * 60000);
3468
+ }
3469
+
3470
+ function unix () {
3471
+ return Math.floor(this.valueOf() / 1000);
3472
+ }
3473
+
3474
+ function toDate () {
3475
+ return new Date(this.valueOf());
3476
+ }
3477
+
3478
+ function toArray () {
3479
+ var m = this;
3480
+ return [m.year(), m.month(), m.date(), m.hour(), m.minute(), m.second(), m.millisecond()];
3481
+ }
3482
+
3483
+ function toObject () {
3484
+ var m = this;
3485
+ return {
3486
+ years: m.year(),
3487
+ months: m.month(),
3488
+ date: m.date(),
3489
+ hours: m.hours(),
3490
+ minutes: m.minutes(),
3491
+ seconds: m.seconds(),
3492
+ milliseconds: m.milliseconds()
3493
+ };
3494
+ }
3495
+
3496
+ function toJSON () {
3497
+ // new Date(NaN).toJSON() === null
3498
+ return this.isValid() ? this.toISOString() : null;
3499
+ }
3500
+
3501
+ function isValid$2 () {
3502
+ return isValid(this);
3503
+ }
3504
+
3505
+ function parsingFlags () {
3506
+ return extend({}, getParsingFlags(this));
3507
+ }
3508
+
3509
+ function invalidAt () {
3510
+ return getParsingFlags(this).overflow;
3511
+ }
3512
+
3513
+ function creationData() {
3514
+ return {
3515
+ input: this._i,
3516
+ format: this._f,
3517
+ locale: this._locale,
3518
+ isUTC: this._isUTC,
3519
+ strict: this._strict
3520
+ };
3521
+ }
3522
+
3523
+ // FORMATTING
3524
+
3525
+ addFormatToken(0, ['gg', 2], 0, function () {
3526
+ return this.weekYear() % 100;
3527
+ });
3528
+
3529
+ addFormatToken(0, ['GG', 2], 0, function () {
3530
+ return this.isoWeekYear() % 100;
3531
+ });
3532
+
3533
+ function addWeekYearFormatToken (token, getter) {
3534
+ addFormatToken(0, [token, token.length], 0, getter);
3535
+ }
3536
+
3537
+ addWeekYearFormatToken('gggg', 'weekYear');
3538
+ addWeekYearFormatToken('ggggg', 'weekYear');
3539
+ addWeekYearFormatToken('GGGG', 'isoWeekYear');
3540
+ addWeekYearFormatToken('GGGGG', 'isoWeekYear');
3541
+
3542
+ // ALIASES
3543
+
3544
+ addUnitAlias('weekYear', 'gg');
3545
+ addUnitAlias('isoWeekYear', 'GG');
3546
+
3547
+ // PRIORITY
3548
+
3549
+ addUnitPriority('weekYear', 1);
3550
+ addUnitPriority('isoWeekYear', 1);
3551
+
3552
+
3553
+ // PARSING
3554
+
3555
+ addRegexToken('G', matchSigned);
3556
+ addRegexToken('g', matchSigned);
3557
+ addRegexToken('GG', match1to2, match2);
3558
+ addRegexToken('gg', match1to2, match2);
3559
+ addRegexToken('GGGG', match1to4, match4);
3560
+ addRegexToken('gggg', match1to4, match4);
3561
+ addRegexToken('GGGGG', match1to6, match6);
3562
+ addRegexToken('ggggg', match1to6, match6);
3563
+
3564
+ addWeekParseToken(['gggg', 'ggggg', 'GGGG', 'GGGGG'], function (input, week, config, token) {
3565
+ week[token.substr(0, 2)] = toInt(input);
3566
+ });
3567
+
3568
+ addWeekParseToken(['gg', 'GG'], function (input, week, config, token) {
3569
+ week[token] = hooks.parseTwoDigitYear(input);
3570
+ });
3571
+
3572
+ // MOMENTS
3573
+
3574
+ function getSetWeekYear (input) {
3575
+ return getSetWeekYearHelper.call(this,
3576
+ input,
3577
+ this.week(),
3578
+ this.weekday(),
3579
+ this.localeData()._week.dow,
3580
+ this.localeData()._week.doy);
3581
+ }
3582
+
3583
+ function getSetISOWeekYear (input) {
3584
+ return getSetWeekYearHelper.call(this,
3585
+ input, this.isoWeek(), this.isoWeekday(), 1, 4);
3586
+ }
3587
+
3588
+ function getISOWeeksInYear () {
3589
+ return weeksInYear(this.year(), 1, 4);
3590
+ }
3591
+
3592
+ function getWeeksInYear () {
3593
+ var weekInfo = this.localeData()._week;
3594
+ return weeksInYear(this.year(), weekInfo.dow, weekInfo.doy);
3595
+ }
3596
+
3597
+ function getSetWeekYearHelper(input, week, weekday, dow, doy) {
3598
+ var weeksTarget;
3599
+ if (input == null) {
3600
+ return weekOfYear(this, dow, doy).year;
3601
+ } else {
3602
+ weeksTarget = weeksInYear(input, dow, doy);
3603
+ if (week > weeksTarget) {
3604
+ week = weeksTarget;
3605
+ }
3606
+ return setWeekAll.call(this, input, week, weekday, dow, doy);
3607
+ }
3608
+ }
3609
+
3610
+ function setWeekAll(weekYear, week, weekday, dow, doy) {
3611
+ var dayOfYearData = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy),
3612
+ date = createUTCDate(dayOfYearData.year, 0, dayOfYearData.dayOfYear);
3613
+
3614
+ this.year(date.getUTCFullYear());
3615
+ this.month(date.getUTCMonth());
3616
+ this.date(date.getUTCDate());
3617
+ return this;
3618
+ }
3619
+
3620
+ // FORMATTING
3621
+
3622
+ addFormatToken('Q', 0, 'Qo', 'quarter');
3623
+
3624
+ // ALIASES
3625
+
3626
+ addUnitAlias('quarter', 'Q');
3627
+
3628
+ // PRIORITY
3629
+
3630
+ addUnitPriority('quarter', 7);
3631
+
3632
+ // PARSING
3633
+
3634
+ addRegexToken('Q', match1);
3635
+ addParseToken('Q', function (input, array) {
3636
+ array[MONTH] = (toInt(input) - 1) * 3;
3637
+ });
3638
+
3639
+ // MOMENTS
3640
+
3641
+ function getSetQuarter (input) {
3642
+ return input == null ? Math.ceil((this.month() + 1) / 3) : this.month((input - 1) * 3 + this.month() % 3);
3643
+ }
3644
+
3645
+ // FORMATTING
3646
+
3647
+ addFormatToken('D', ['DD', 2], 'Do', 'date');
3648
+
3649
+ // ALIASES
3650
+
3651
+ addUnitAlias('date', 'D');
3652
+
3653
+ // PRIOROITY
3654
+ addUnitPriority('date', 9);
3655
+
3656
+ // PARSING
3657
+
3658
+ addRegexToken('D', match1to2);
3659
+ addRegexToken('DD', match1to2, match2);
3660
+ addRegexToken('Do', function (isStrict, locale) {
3661
+ // TODO: Remove "ordinalParse" fallback in next major release.
3662
+ return isStrict ?
3663
+ (locale._dayOfMonthOrdinalParse || locale._ordinalParse) :
3664
+ locale._dayOfMonthOrdinalParseLenient;
3665
+ });
3666
+
3667
+ addParseToken(['D', 'DD'], DATE);
3668
+ addParseToken('Do', function (input, array) {
3669
+ array[DATE] = toInt(input.match(match1to2)[0], 10);
3670
+ });
3671
+
3672
+ // MOMENTS
3673
+
3674
+ var getSetDayOfMonth = makeGetSet('Date', true);
3675
+
3676
+ // FORMATTING
3677
+
3678
+ addFormatToken('DDD', ['DDDD', 3], 'DDDo', 'dayOfYear');
3679
+
3680
+ // ALIASES
3681
+
3682
+ addUnitAlias('dayOfYear', 'DDD');
3683
+
3684
+ // PRIORITY
3685
+ addUnitPriority('dayOfYear', 4);
3686
+
3687
+ // PARSING
3688
+
3689
+ addRegexToken('DDD', match1to3);
3690
+ addRegexToken('DDDD', match3);
3691
+ addParseToken(['DDD', 'DDDD'], function (input, array, config) {
3692
+ config._dayOfYear = toInt(input);
3693
+ });
3694
+
3695
+ // HELPERS
3696
+
3697
+ // MOMENTS
3698
+
3699
+ function getSetDayOfYear (input) {
3700
+ var dayOfYear = Math.round((this.clone().startOf('day') - this.clone().startOf('year')) / 864e5) + 1;
3701
+ return input == null ? dayOfYear : this.add((input - dayOfYear), 'd');
3702
+ }
3703
+
3704
+ // FORMATTING
3705
+
3706
+ addFormatToken('m', ['mm', 2], 0, 'minute');
3707
+
3708
+ // ALIASES
3709
+
3710
+ addUnitAlias('minute', 'm');
3711
+
3712
+ // PRIORITY
3713
+
3714
+ addUnitPriority('minute', 14);
3715
+
3716
+ // PARSING
3717
+
3718
+ addRegexToken('m', match1to2);
3719
+ addRegexToken('mm', match1to2, match2);
3720
+ addParseToken(['m', 'mm'], MINUTE);
3721
+
3722
+ // MOMENTS
3723
+
3724
+ var getSetMinute = makeGetSet('Minutes', false);
3725
+
3726
+ // FORMATTING
3727
+
3728
+ addFormatToken('s', ['ss', 2], 0, 'second');
3729
+
3730
+ // ALIASES
3731
+
3732
+ addUnitAlias('second', 's');
3733
+
3734
+ // PRIORITY
3735
+
3736
+ addUnitPriority('second', 15);
3737
+
3738
+ // PARSING
3739
+
3740
+ addRegexToken('s', match1to2);
3741
+ addRegexToken('ss', match1to2, match2);
3742
+ addParseToken(['s', 'ss'], SECOND);
3743
+
3744
+ // MOMENTS
3745
+
3746
+ var getSetSecond = makeGetSet('Seconds', false);
3747
+
3748
+ // FORMATTING
3749
+
3750
+ addFormatToken('S', 0, 0, function () {
3751
+ return ~~(this.millisecond() / 100);
3752
+ });
3753
+
3754
+ addFormatToken(0, ['SS', 2], 0, function () {
3755
+ return ~~(this.millisecond() / 10);
3756
+ });
3757
+
3758
+ addFormatToken(0, ['SSS', 3], 0, 'millisecond');
3759
+ addFormatToken(0, ['SSSS', 4], 0, function () {
3760
+ return this.millisecond() * 10;
3761
+ });
3762
+ addFormatToken(0, ['SSSSS', 5], 0, function () {
3763
+ return this.millisecond() * 100;
3764
+ });
3765
+ addFormatToken(0, ['SSSSSS', 6], 0, function () {
3766
+ return this.millisecond() * 1000;
3767
+ });
3768
+ addFormatToken(0, ['SSSSSSS', 7], 0, function () {
3769
+ return this.millisecond() * 10000;
3770
+ });
3771
+ addFormatToken(0, ['SSSSSSSS', 8], 0, function () {
3772
+ return this.millisecond() * 100000;
3773
+ });
3774
+ addFormatToken(0, ['SSSSSSSSS', 9], 0, function () {
3775
+ return this.millisecond() * 1000000;
3776
+ });
3777
+
3778
+
3779
+ // ALIASES
3780
+
3781
+ addUnitAlias('millisecond', 'ms');
3782
+
3783
+ // PRIORITY
3784
+
3785
+ addUnitPriority('millisecond', 16);
3786
+
3787
+ // PARSING
3788
+
3789
+ addRegexToken('S', match1to3, match1);
3790
+ addRegexToken('SS', match1to3, match2);
3791
+ addRegexToken('SSS', match1to3, match3);
3792
+
3793
+ var token;
3794
+ for (token = 'SSSS'; token.length <= 9; token += 'S') {
3795
+ addRegexToken(token, matchUnsigned);
3796
+ }
3797
+
3798
+ function parseMs(input, array) {
3799
+ array[MILLISECOND] = toInt(('0.' + input) * 1000);
3800
+ }
3801
+
3802
+ for (token = 'S'; token.length <= 9; token += 'S') {
3803
+ addParseToken(token, parseMs);
3804
+ }
3805
+ // MOMENTS
3806
+
3807
+ var getSetMillisecond = makeGetSet('Milliseconds', false);
3808
+
3809
+ // FORMATTING
3810
+
3811
+ addFormatToken('z', 0, 0, 'zoneAbbr');
3812
+ addFormatToken('zz', 0, 0, 'zoneName');
3813
+
3814
+ // MOMENTS
3815
+
3816
+ function getZoneAbbr () {
3817
+ return this._isUTC ? 'UTC' : '';
3818
+ }
3819
+
3820
+ function getZoneName () {
3821
+ return this._isUTC ? 'Coordinated Universal Time' : '';
3822
+ }
3823
+
3824
+ var proto = Moment.prototype;
3825
+
3826
+ proto.add = add;
3827
+ proto.calendar = calendar$1;
3828
+ proto.clone = clone;
3829
+ proto.diff = diff;
3830
+ proto.endOf = endOf;
3831
+ proto.format = format;
3832
+ proto.from = from;
3833
+ proto.fromNow = fromNow;
3834
+ proto.to = to;
3835
+ proto.toNow = toNow;
3836
+ proto.get = stringGet;
3837
+ proto.invalidAt = invalidAt;
3838
+ proto.isAfter = isAfter;
3839
+ proto.isBefore = isBefore;
3840
+ proto.isBetween = isBetween;
3841
+ proto.isSame = isSame;
3842
+ proto.isSameOrAfter = isSameOrAfter;
3843
+ proto.isSameOrBefore = isSameOrBefore;
3844
+ proto.isValid = isValid$2;
3845
+ proto.lang = lang;
3846
+ proto.locale = locale;
3847
+ proto.localeData = localeData;
3848
+ proto.max = prototypeMax;
3849
+ proto.min = prototypeMin;
3850
+ proto.parsingFlags = parsingFlags;
3851
+ proto.set = stringSet;
3852
+ proto.startOf = startOf;
3853
+ proto.subtract = subtract;
3854
+ proto.toArray = toArray;
3855
+ proto.toObject = toObject;
3856
+ proto.toDate = toDate;
3857
+ proto.toISOString = toISOString;
3858
+ proto.inspect = inspect;
3859
+ proto.toJSON = toJSON;
3860
+ proto.toString = toString;
3861
+ proto.unix = unix;
3862
+ proto.valueOf = valueOf;
3863
+ proto.creationData = creationData;
3864
+
3865
+ // Year
3866
+ proto.year = getSetYear;
3867
+ proto.isLeapYear = getIsLeapYear;
3868
+
3869
+ // Week Year
3870
+ proto.weekYear = getSetWeekYear;
3871
+ proto.isoWeekYear = getSetISOWeekYear;
3872
+
3873
+ // Quarter
3874
+ proto.quarter = proto.quarters = getSetQuarter;
3875
+
3876
+ // Month
3877
+ proto.month = getSetMonth;
3878
+ proto.daysInMonth = getDaysInMonth;
3879
+
3880
+ // Week
3881
+ proto.week = proto.weeks = getSetWeek;
3882
+ proto.isoWeek = proto.isoWeeks = getSetISOWeek;
3883
+ proto.weeksInYear = getWeeksInYear;
3884
+ proto.isoWeeksInYear = getISOWeeksInYear;
3885
+
3886
+ // Day
3887
+ proto.date = getSetDayOfMonth;
3888
+ proto.day = proto.days = getSetDayOfWeek;
3889
+ proto.weekday = getSetLocaleDayOfWeek;
3890
+ proto.isoWeekday = getSetISODayOfWeek;
3891
+ proto.dayOfYear = getSetDayOfYear;
3892
+
3893
+ // Hour
3894
+ proto.hour = proto.hours = getSetHour;
3895
+
3896
+ // Minute
3897
+ proto.minute = proto.minutes = getSetMinute;
3898
+
3899
+ // Second
3900
+ proto.second = proto.seconds = getSetSecond;
3901
+
3902
+ // Millisecond
3903
+ proto.millisecond = proto.milliseconds = getSetMillisecond;
3904
+
3905
+ // Offset
3906
+ proto.utcOffset = getSetOffset;
3907
+ proto.utc = setOffsetToUTC;
3908
+ proto.local = setOffsetToLocal;
3909
+ proto.parseZone = setOffsetToParsedOffset;
3910
+ proto.hasAlignedHourOffset = hasAlignedHourOffset;
3911
+ proto.isDST = isDaylightSavingTime;
3912
+ proto.isLocal = isLocal;
3913
+ proto.isUtcOffset = isUtcOffset;
3914
+ proto.isUtc = isUtc;
3915
+ proto.isUTC = isUtc;
3916
+
3917
+ // Timezone
3918
+ proto.zoneAbbr = getZoneAbbr;
3919
+ proto.zoneName = getZoneName;
3920
+
3921
+ // Deprecations
3922
+ proto.dates = deprecate('dates accessor is deprecated. Use date instead.', getSetDayOfMonth);
3923
+ proto.months = deprecate('months accessor is deprecated. Use month instead', getSetMonth);
3924
+ proto.years = deprecate('years accessor is deprecated. Use year instead', getSetYear);
3925
+ proto.zone = deprecate('moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/', getSetZone);
3926
+ proto.isDSTShifted = deprecate('isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information', isDaylightSavingTimeShifted);
3927
+
3928
+ function createUnix (input) {
3929
+ return createLocal(input * 1000);
3930
+ }
3931
+
3932
+ function createInZone () {
3933
+ return createLocal.apply(null, arguments).parseZone();
3934
+ }
3935
+
3936
+ function preParsePostFormat (string) {
3937
+ return string;
3938
+ }
3939
+
3940
+ var proto$1 = Locale.prototype;
3941
+
3942
+ proto$1.calendar = calendar;
3943
+ proto$1.longDateFormat = longDateFormat;
3944
+ proto$1.invalidDate = invalidDate;
3945
+ proto$1.ordinal = ordinal;
3946
+ proto$1.preparse = preParsePostFormat;
3947
+ proto$1.postformat = preParsePostFormat;
3948
+ proto$1.relativeTime = relativeTime;
3949
+ proto$1.pastFuture = pastFuture;
3950
+ proto$1.set = set;
3951
+
3952
+ // Month
3953
+ proto$1.months = localeMonths;
3954
+ proto$1.monthsShort = localeMonthsShort;
3955
+ proto$1.monthsParse = localeMonthsParse;
3956
+ proto$1.monthsRegex = monthsRegex;
3957
+ proto$1.monthsShortRegex = monthsShortRegex;
3958
+
3959
+ // Week
3960
+ proto$1.week = localeWeek;
3961
+ proto$1.firstDayOfYear = localeFirstDayOfYear;
3962
+ proto$1.firstDayOfWeek = localeFirstDayOfWeek;
3963
+
3964
+ // Day of Week
3965
+ proto$1.weekdays = localeWeekdays;
3966
+ proto$1.weekdaysMin = localeWeekdaysMin;
3967
+ proto$1.weekdaysShort = localeWeekdaysShort;
3968
+ proto$1.weekdaysParse = localeWeekdaysParse;
3969
+
3970
+ proto$1.weekdaysRegex = weekdaysRegex;
3971
+ proto$1.weekdaysShortRegex = weekdaysShortRegex;
3972
+ proto$1.weekdaysMinRegex = weekdaysMinRegex;
3973
+
3974
+ // Hours
3975
+ proto$1.isPM = localeIsPM;
3976
+ proto$1.meridiem = localeMeridiem;
3977
+
3978
+ function get$1 (format, index, field, setter) {
3979
+ var locale = getLocale();
3980
+ var utc = createUTC().set(setter, index);
3981
+ return locale[field](utc, format);
3982
+ }
3983
+
3984
+ function listMonthsImpl (format, index, field) {
3985
+ if (isNumber(format)) {
3986
+ index = format;
3987
+ format = undefined;
3988
+ }
3989
+
3990
+ format = format || '';
3991
+
3992
+ if (index != null) {
3993
+ return get$1(format, index, field, 'month');
3994
+ }
3995
+
3996
+ var i;
3997
+ var out = [];
3998
+ for (i = 0; i < 12; i++) {
3999
+ out[i] = get$1(format, i, field, 'month');
4000
+ }
4001
+ return out;
4002
+ }
4003
+
4004
+ // ()
4005
+ // (5)
4006
+ // (fmt, 5)
4007
+ // (fmt)
4008
+ // (true)
4009
+ // (true, 5)
4010
+ // (true, fmt, 5)
4011
+ // (true, fmt)
4012
+ function listWeekdaysImpl (localeSorted, format, index, field) {
4013
+ if (typeof localeSorted === 'boolean') {
4014
+ if (isNumber(format)) {
4015
+ index = format;
4016
+ format = undefined;
4017
+ }
4018
+
4019
+ format = format || '';
4020
+ } else {
4021
+ format = localeSorted;
4022
+ index = format;
4023
+ localeSorted = false;
4024
+
4025
+ if (isNumber(format)) {
4026
+ index = format;
4027
+ format = undefined;
4028
+ }
4029
+
4030
+ format = format || '';
4031
+ }
4032
+
4033
+ var locale = getLocale(),
4034
+ shift = localeSorted ? locale._week.dow : 0;
4035
+
4036
+ if (index != null) {
4037
+ return get$1(format, (index + shift) % 7, field, 'day');
4038
+ }
4039
+
4040
+ var i;
4041
+ var out = [];
4042
+ for (i = 0; i < 7; i++) {
4043
+ out[i] = get$1(format, (i + shift) % 7, field, 'day');
4044
+ }
4045
+ return out;
4046
+ }
4047
+
4048
+ function listMonths (format, index) {
4049
+ return listMonthsImpl(format, index, 'months');
4050
+ }
4051
+
4052
+ function listMonthsShort (format, index) {
4053
+ return listMonthsImpl(format, index, 'monthsShort');
4054
+ }
4055
+
4056
+ function listWeekdays (localeSorted, format, index) {
4057
+ return listWeekdaysImpl(localeSorted, format, index, 'weekdays');
4058
+ }
4059
+
4060
+ function listWeekdaysShort (localeSorted, format, index) {
4061
+ return listWeekdaysImpl(localeSorted, format, index, 'weekdaysShort');
4062
+ }
4063
+
4064
+ function listWeekdaysMin (localeSorted, format, index) {
4065
+ return listWeekdaysImpl(localeSorted, format, index, 'weekdaysMin');
4066
+ }
4067
+
4068
+ getSetGlobalLocale('en', {
4069
+ dayOfMonthOrdinalParse: /\d{1,2}(th|st|nd|rd)/,
4070
+ ordinal : function (number) {
4071
+ var b = number % 10,
4072
+ output = (toInt(number % 100 / 10) === 1) ? 'th' :
4073
+ (b === 1) ? 'st' :
4074
+ (b === 2) ? 'nd' :
4075
+ (b === 3) ? 'rd' : 'th';
4076
+ return number + output;
4077
+ }
4078
+ });
4079
+
4080
+ // Side effect imports
4081
+ hooks.lang = deprecate('moment.lang is deprecated. Use moment.locale instead.', getSetGlobalLocale);
4082
+ hooks.langData = deprecate('moment.langData is deprecated. Use moment.localeData instead.', getLocale);
4083
+
4084
+ var mathAbs = Math.abs;
4085
+
4086
+ function abs () {
4087
+ var data = this._data;
4088
+
4089
+ this._milliseconds = mathAbs(this._milliseconds);
4090
+ this._days = mathAbs(this._days);
4091
+ this._months = mathAbs(this._months);
4092
+
4093
+ data.milliseconds = mathAbs(data.milliseconds);
4094
+ data.seconds = mathAbs(data.seconds);
4095
+ data.minutes = mathAbs(data.minutes);
4096
+ data.hours = mathAbs(data.hours);
4097
+ data.months = mathAbs(data.months);
4098
+ data.years = mathAbs(data.years);
4099
+
4100
+ return this;
4101
+ }
4102
+
4103
+ function addSubtract$1 (duration, input, value, direction) {
4104
+ var other = createDuration(input, value);
4105
+
4106
+ duration._milliseconds += direction * other._milliseconds;
4107
+ duration._days += direction * other._days;
4108
+ duration._months += direction * other._months;
4109
+
4110
+ return duration._bubble();
4111
+ }
4112
+
4113
+ // supports only 2.0-style add(1, 's') or add(duration)
4114
+ function add$1 (input, value) {
4115
+ return addSubtract$1(this, input, value, 1);
4116
+ }
4117
+
4118
+ // supports only 2.0-style subtract(1, 's') or subtract(duration)
4119
+ function subtract$1 (input, value) {
4120
+ return addSubtract$1(this, input, value, -1);
4121
+ }
4122
+
4123
+ function absCeil (number) {
4124
+ if (number < 0) {
4125
+ return Math.floor(number);
4126
+ } else {
4127
+ return Math.ceil(number);
4128
+ }
4129
+ }
4130
+
4131
+ function bubble () {
4132
+ var milliseconds = this._milliseconds;
4133
+ var days = this._days;
4134
+ var months = this._months;
4135
+ var data = this._data;
4136
+ var seconds, minutes, hours, years, monthsFromDays;
4137
+
4138
+ // if we have a mix of positive and negative values, bubble down first
4139
+ // check: https://github.com/moment/moment/issues/2166
4140
+ if (!((milliseconds >= 0 && days >= 0 && months >= 0) ||
4141
+ (milliseconds <= 0 && days <= 0 && months <= 0))) {
4142
+ milliseconds += absCeil(monthsToDays(months) + days) * 864e5;
4143
+ days = 0;
4144
+ months = 0;
4145
+ }
4146
+
4147
+ // The following code bubbles up values, see the tests for
4148
+ // examples of what that means.
4149
+ data.milliseconds = milliseconds % 1000;
4150
+
4151
+ seconds = absFloor(milliseconds / 1000);
4152
+ data.seconds = seconds % 60;
4153
+
4154
+ minutes = absFloor(seconds / 60);
4155
+ data.minutes = minutes % 60;
4156
+
4157
+ hours = absFloor(minutes / 60);
4158
+ data.hours = hours % 24;
4159
+
4160
+ days += absFloor(hours / 24);
4161
+
4162
+ // convert days to months
4163
+ monthsFromDays = absFloor(daysToMonths(days));
4164
+ months += monthsFromDays;
4165
+ days -= absCeil(monthsToDays(monthsFromDays));
4166
+
4167
+ // 12 months -> 1 year
4168
+ years = absFloor(months / 12);
4169
+ months %= 12;
4170
+
4171
+ data.days = days;
4172
+ data.months = months;
4173
+ data.years = years;
4174
+
4175
+ return this;
4176
+ }
4177
+
4178
+ function daysToMonths (days) {
4179
+ // 400 years have 146097 days (taking into account leap year rules)
4180
+ // 400 years have 12 months === 4800
4181
+ return days * 4800 / 146097;
4182
+ }
4183
+
4184
+ function monthsToDays (months) {
4185
+ // the reverse of daysToMonths
4186
+ return months * 146097 / 4800;
4187
+ }
4188
+
4189
+ function as (units) {
4190
+ if (!this.isValid()) {
4191
+ return NaN;
4192
+ }
4193
+ var days;
4194
+ var months;
4195
+ var milliseconds = this._milliseconds;
4196
+
4197
+ units = normalizeUnits(units);
4198
+
4199
+ if (units === 'month' || units === 'year') {
4200
+ days = this._days + milliseconds / 864e5;
4201
+ months = this._months + daysToMonths(days);
4202
+ return units === 'month' ? months : months / 12;
4203
+ } else {
4204
+ // handle milliseconds separately because of floating point math errors (issue #1867)
4205
+ days = this._days + Math.round(monthsToDays(this._months));
4206
+ switch (units) {
4207
+ case 'week' : return days / 7 + milliseconds / 6048e5;
4208
+ case 'day' : return days + milliseconds / 864e5;
4209
+ case 'hour' : return days * 24 + milliseconds / 36e5;
4210
+ case 'minute' : return days * 1440 + milliseconds / 6e4;
4211
+ case 'second' : return days * 86400 + milliseconds / 1000;
4212
+ // Math.floor prevents floating point math errors here
4213
+ case 'millisecond': return Math.floor(days * 864e5) + milliseconds;
4214
+ default: throw new Error('Unknown unit ' + units);
4215
+ }
4216
+ }
4217
+ }
4218
+
4219
+ // TODO: Use this.as('ms')?
4220
+ function valueOf$1 () {
4221
+ if (!this.isValid()) {
4222
+ return NaN;
4223
+ }
4224
+ return (
4225
+ this._milliseconds +
4226
+ this._days * 864e5 +
4227
+ (this._months % 12) * 2592e6 +
4228
+ toInt(this._months / 12) * 31536e6
4229
+ );
4230
+ }
4231
+
4232
+ function makeAs (alias) {
4233
+ return function () {
4234
+ return this.as(alias);
4235
+ };
4236
+ }
4237
+
4238
+ var asMilliseconds = makeAs('ms');
4239
+ var asSeconds = makeAs('s');
4240
+ var asMinutes = makeAs('m');
4241
+ var asHours = makeAs('h');
4242
+ var asDays = makeAs('d');
4243
+ var asWeeks = makeAs('w');
4244
+ var asMonths = makeAs('M');
4245
+ var asYears = makeAs('y');
4246
+
4247
+ function clone$1 () {
4248
+ return createDuration(this);
4249
+ }
4250
+
4251
+ function get$2 (units) {
4252
+ units = normalizeUnits(units);
4253
+ return this.isValid() ? this[units + 's']() : NaN;
4254
+ }
4255
+
4256
+ function makeGetter(name) {
4257
+ return function () {
4258
+ return this.isValid() ? this._data[name] : NaN;
4259
+ };
4260
+ }
4261
+
4262
+ var milliseconds = makeGetter('milliseconds');
4263
+ var seconds = makeGetter('seconds');
4264
+ var minutes = makeGetter('minutes');
4265
+ var hours = makeGetter('hours');
4266
+ var days = makeGetter('days');
4267
+ var months = makeGetter('months');
4268
+ var years = makeGetter('years');
4269
+
4270
+ function weeks () {
4271
+ return absFloor(this.days() / 7);
4272
+ }
4273
+
4274
+ var round = Math.round;
4275
+ var thresholds = {
4276
+ ss: 44, // a few seconds to seconds
4277
+ s : 45, // seconds to minute
4278
+ m : 45, // minutes to hour
4279
+ h : 22, // hours to day
4280
+ d : 26, // days to month
4281
+ M : 11 // months to year
4282
+ };
4283
+
4284
+ // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize
4285
+ function substituteTimeAgo(string, number, withoutSuffix, isFuture, locale) {
4286
+ return locale.relativeTime(number || 1, !!withoutSuffix, string, isFuture);
4287
+ }
4288
+
4289
+ function relativeTime$1 (posNegDuration, withoutSuffix, locale) {
4290
+ var duration = createDuration(posNegDuration).abs();
4291
+ var seconds = round(duration.as('s'));
4292
+ var minutes = round(duration.as('m'));
4293
+ var hours = round(duration.as('h'));
4294
+ var days = round(duration.as('d'));
4295
+ var months = round(duration.as('M'));
4296
+ var years = round(duration.as('y'));
4297
+
4298
+ var a = seconds <= thresholds.ss && ['s', seconds] ||
4299
+ seconds < thresholds.s && ['ss', seconds] ||
4300
+ minutes <= 1 && ['m'] ||
4301
+ minutes < thresholds.m && ['mm', minutes] ||
4302
+ hours <= 1 && ['h'] ||
4303
+ hours < thresholds.h && ['hh', hours] ||
4304
+ days <= 1 && ['d'] ||
4305
+ days < thresholds.d && ['dd', days] ||
4306
+ months <= 1 && ['M'] ||
4307
+ months < thresholds.M && ['MM', months] ||
4308
+ years <= 1 && ['y'] || ['yy', years];
4309
+
4310
+ a[2] = withoutSuffix;
4311
+ a[3] = +posNegDuration > 0;
4312
+ a[4] = locale;
4313
+ return substituteTimeAgo.apply(null, a);
4314
+ }
4315
+
4316
+ // This function allows you to set the rounding function for relative time strings
4317
+ function getSetRelativeTimeRounding (roundingFunction) {
4318
+ if (roundingFunction === undefined) {
4319
+ return round;
4320
+ }
4321
+ if (typeof(roundingFunction) === 'function') {
4322
+ round = roundingFunction;
4323
+ return true;
4324
+ }
4325
+ return false;
4326
+ }
4327
+
4328
+ // This function allows you to set a threshold for relative time strings
4329
+ function getSetRelativeTimeThreshold (threshold, limit) {
4330
+ if (thresholds[threshold] === undefined) {
4331
+ return false;
4332
+ }
4333
+ if (limit === undefined) {
4334
+ return thresholds[threshold];
4335
+ }
4336
+ thresholds[threshold] = limit;
4337
+ if (threshold === 's') {
4338
+ thresholds.ss = limit - 1;
4339
+ }
4340
+ return true;
4341
+ }
4342
+
4343
+ function humanize (withSuffix) {
4344
+ if (!this.isValid()) {
4345
+ return this.localeData().invalidDate();
4346
+ }
4347
+
4348
+ var locale = this.localeData();
4349
+ var output = relativeTime$1(this, !withSuffix, locale);
4350
+
4351
+ if (withSuffix) {
4352
+ output = locale.pastFuture(+this, output);
4353
+ }
4354
+
4355
+ return locale.postformat(output);
4356
+ }
4357
+
4358
+ var abs$1 = Math.abs;
4359
+
4360
+ function sign(x) {
4361
+ return ((x > 0) - (x < 0)) || +x;
4362
+ }
4363
+
4364
+ function toISOString$1() {
4365
+ // for ISO strings we do not use the normal bubbling rules:
4366
+ // * milliseconds bubble up until they become hours
4367
+ // * days do not bubble at all
4368
+ // * months bubble up until they become years
4369
+ // This is because there is no context-free conversion between hours and days
4370
+ // (think of clock changes)
4371
+ // and also not between days and months (28-31 days per month)
4372
+ if (!this.isValid()) {
4373
+ return this.localeData().invalidDate();
4374
+ }
4375
+
4376
+ var seconds = abs$1(this._milliseconds) / 1000;
4377
+ var days = abs$1(this._days);
4378
+ var months = abs$1(this._months);
4379
+ var minutes, hours, years;
4380
+
4381
+ // 3600 seconds -> 60 minutes -> 1 hour
4382
+ minutes = absFloor(seconds / 60);
4383
+ hours = absFloor(minutes / 60);
4384
+ seconds %= 60;
4385
+ minutes %= 60;
4386
+
4387
+ // 12 months -> 1 year
4388
+ years = absFloor(months / 12);
4389
+ months %= 12;
4390
+
4391
+
4392
+ // inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js
4393
+ var Y = years;
4394
+ var M = months;
4395
+ var D = days;
4396
+ var h = hours;
4397
+ var m = minutes;
4398
+ var s = seconds ? seconds.toFixed(3).replace(/\.?0+$/, '') : '';
4399
+ var total = this.asSeconds();
4400
+
4401
+ if (!total) {
4402
+ // this is the same as C#'s (Noda) and python (isodate)...
4403
+ // but not other JS (goog.date)
4404
+ return 'P0D';
4405
+ }
4406
+
4407
+ var totalSign = total < 0 ? '-' : '';
4408
+ var ymSign = sign(this._months) !== sign(total) ? '-' : '';
4409
+ var daysSign = sign(this._days) !== sign(total) ? '-' : '';
4410
+ var hmsSign = sign(this._milliseconds) !== sign(total) ? '-' : '';
4411
+
4412
+ return totalSign + 'P' +
4413
+ (Y ? ymSign + Y + 'Y' : '') +
4414
+ (M ? ymSign + M + 'M' : '') +
4415
+ (D ? daysSign + D + 'D' : '') +
4416
+ ((h || m || s) ? 'T' : '') +
4417
+ (h ? hmsSign + h + 'H' : '') +
4418
+ (m ? hmsSign + m + 'M' : '') +
4419
+ (s ? hmsSign + s + 'S' : '');
4420
+ }
4421
+
4422
+ var proto$2 = Duration.prototype;
4423
+
4424
+ proto$2.isValid = isValid$1;
4425
+ proto$2.abs = abs;
4426
+ proto$2.add = add$1;
4427
+ proto$2.subtract = subtract$1;
4428
+ proto$2.as = as;
4429
+ proto$2.asMilliseconds = asMilliseconds;
4430
+ proto$2.asSeconds = asSeconds;
4431
+ proto$2.asMinutes = asMinutes;
4432
+ proto$2.asHours = asHours;
4433
+ proto$2.asDays = asDays;
4434
+ proto$2.asWeeks = asWeeks;
4435
+ proto$2.asMonths = asMonths;
4436
+ proto$2.asYears = asYears;
4437
+ proto$2.valueOf = valueOf$1;
4438
+ proto$2._bubble = bubble;
4439
+ proto$2.clone = clone$1;
4440
+ proto$2.get = get$2;
4441
+ proto$2.milliseconds = milliseconds;
4442
+ proto$2.seconds = seconds;
4443
+ proto$2.minutes = minutes;
4444
+ proto$2.hours = hours;
4445
+ proto$2.days = days;
4446
+ proto$2.weeks = weeks;
4447
+ proto$2.months = months;
4448
+ proto$2.years = years;
4449
+ proto$2.humanize = humanize;
4450
+ proto$2.toISOString = toISOString$1;
4451
+ proto$2.toString = toISOString$1;
4452
+ proto$2.toJSON = toISOString$1;
4453
+ proto$2.locale = locale;
4454
+ proto$2.localeData = localeData;
4455
+
4456
+ // Deprecations
4457
+ proto$2.toIsoString = deprecate('toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)', toISOString$1);
4458
+ proto$2.lang = lang;
4459
+
4460
+ // Side effect imports
4461
+
4462
+ // FORMATTING
4463
+
4464
+ addFormatToken('X', 0, 0, 'unix');
4465
+ addFormatToken('x', 0, 0, 'valueOf');
4466
+
4467
+ // PARSING
4468
+
4469
+ addRegexToken('x', matchSigned);
4470
+ addRegexToken('X', matchTimestamp);
4471
+ addParseToken('X', function (input, array, config) {
4472
+ config._d = new Date(parseFloat(input, 10) * 1000);
4473
+ });
4474
+ addParseToken('x', function (input, array, config) {
4475
+ config._d = new Date(toInt(input));
4476
+ });
4477
+
4478
+ // Side effect imports
4479
+
4480
+
4481
+ hooks.version = '2.19.3';
4482
+
4483
+ setHookCallback(createLocal);
4484
+
4485
+ hooks.fn = proto;
4486
+ hooks.min = min;
4487
+ hooks.max = max;
4488
+ hooks.now = now;
4489
+ hooks.utc = createUTC;
4490
+ hooks.unix = createUnix;
4491
+ hooks.months = listMonths;
4492
+ hooks.isDate = isDate;
4493
+ hooks.locale = getSetGlobalLocale;
4494
+ hooks.invalid = createInvalid;
4495
+ hooks.duration = createDuration;
4496
+ hooks.isMoment = isMoment;
4497
+ hooks.weekdays = listWeekdays;
4498
+ hooks.parseZone = createInZone;
4499
+ hooks.localeData = getLocale;
4500
+ hooks.isDuration = isDuration;
4501
+ hooks.monthsShort = listMonthsShort;
4502
+ hooks.weekdaysMin = listWeekdaysMin;
4503
+ hooks.defineLocale = defineLocale;
4504
+ hooks.updateLocale = updateLocale;
4505
+ hooks.locales = listLocales;
4506
+ hooks.weekdaysShort = listWeekdaysShort;
4507
+ hooks.normalizeUnits = normalizeUnits;
4508
+ hooks.relativeTimeRounding = getSetRelativeTimeRounding;
4509
+ hooks.relativeTimeThreshold = getSetRelativeTimeThreshold;
4510
+ hooks.calendarFormat = getCalendarFormat;
4511
+ hooks.prototype = proto;
4512
+
4513
+ return hooks;
4514
+
4515
+ })));
elements/facebook-feed/facebook-feed.php ADDED
@@ -0,0 +1,700 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Elementor;
3
+
4
+ if ( ! defined( 'ABSPATH' ) ) exit; // If this file is called directly, abort.
5
+
6
+
7
+ class Widget_Eael_Facebook_Feed extends Widget_Base {
8
+
9
+ public function get_name() {
10
+ return 'eael-facebook-feed';
11
+ }
12
+
13
+ public function get_title() {
14
+ return esc_html__( 'EA Facebook Feed', 'essential-addons-elementor' );
15
+ }
16
+
17
+ public function get_icon() {
18
+ return 'fa fa-facebook-official';
19
+ }
20
+
21
+ public function get_categories() {
22
+ return [ 'essential-addons-elementor' ];
23
+ }
24
+
25
+ protected function _register_controls() {
26
+
27
+ $this->start_controls_section(
28
+ 'eael_section_facebook_feed_acc_settings',
29
+ [
30
+ 'label' => esc_html__( 'Account Settings', 'essential-addons-elementor' )
31
+ ]
32
+ );
33
+
34
+ $this->add_control(
35
+ 'eael_facebook_feed_ac_name',
36
+ [
37
+ 'label' => esc_html__( 'Account Name', 'essential-addons-elementor' ),
38
+ 'type' => Controls_Manager::TEXT,
39
+ 'label_block' => false,
40
+ 'default' => '@Codetic',
41
+ 'description' => esc_html__( 'Use @ sign with your account name.', 'essential-addons-elementor' ),
42
+
43
+ ]
44
+ );
45
+
46
+ $this->add_control(
47
+ 'eael_facebook_feed_app_id',
48
+ [
49
+ 'label' => esc_html__( 'App ID', 'essential-addons-elementor' ),
50
+ 'type' => Controls_Manager::TEXT,
51
+ 'label_block' => false,
52
+ 'default' => '138195606893948',
53
+ 'description' => '<a href="https://developers.facebook.com/apps/" target="_blank">Get App ID.</a> Create or select an app and grab the App ID',
54
+ ]
55
+ );
56
+
57
+ $this->add_control(
58
+ 'eael_facebook_feed_app_secret',
59
+ [
60
+ 'label' => esc_html__( 'App Secret', 'essential-addons-elementor' ),
61
+ 'type' => Controls_Manager::TEXT,
62
+ 'label_block' => false,
63
+ 'default' => 'e14ec8e0c0d4918d0133d2cf2aca2de9',
64
+ 'description' => '<a href="https://developers.facebook.com/apps/" target="_blank">Get App Secret.</a> Create or select an app and grab the App ID',
65
+ ]
66
+ );
67
+
68
+ $this->end_controls_section();
69
+
70
+ $this->start_controls_section(
71
+ 'eael_section_facebook_feed_settings',
72
+ [
73
+ 'label' => esc_html__( 'Layout Settings', 'essential-addons-elementor' )
74
+ ]
75
+ );
76
+
77
+ $this->add_control(
78
+ 'eael_facebook_feed_type',
79
+ [
80
+ 'label' => esc_html__( 'Content Layout', 'essential-addons-elementor' ),
81
+ 'type' => Controls_Manager::SELECT,
82
+ 'default' => 'masonry',
83
+ 'options' => [
84
+ 'list' => esc_html__( 'List', 'essential-addons-elementor' ),
85
+ 'masonry' => esc_html__( 'Masonry', 'essential-addons-elementor' ),
86
+ ],
87
+ ]
88
+ );
89
+
90
+ $this->add_control(
91
+ 'eael_facebook_feed_type_col_type',
92
+ [
93
+ 'label' => __( 'Column Grid', 'essential-addons-elementor' ),
94
+ 'type' => Controls_Manager::SELECT,
95
+ 'options' => [
96
+ 'col-2' => '2 Columns',
97
+ 'col-3' => '3 Columns',
98
+ 'col-4' => '4 Columns',
99
+ ],
100
+ 'default' => 'col-3',
101
+ 'prefix_class' => 'eael-social-feed-masonry-',
102
+ 'condition' => [
103
+ 'eael_facebook_feed_type' => 'masonry'
104
+ ],
105
+ ]
106
+ );
107
+
108
+ $this->add_control(
109
+ 'eael_facebook_feed_content_length',
110
+ [
111
+ 'label' => esc_html__( 'Content Length', 'essential-addons-elementor' ),
112
+ 'type' => Controls_Manager::TEXT,
113
+ 'label_block' => false,
114
+ 'default' => '400'
115
+ ]
116
+ );
117
+
118
+ $this->add_control(
119
+ 'eael_facebook_feed_post_limit',
120
+ [
121
+ 'label' => esc_html__( 'Post Limit', 'essential-addons-elementor' ),
122
+ 'type' => Controls_Manager::NUMBER,
123
+ 'label_block' => false,
124
+ 'default' => 10
125
+ ]
126
+ );
127
+
128
+ $this->add_control(
129
+ 'eael_facebook_feed_media',
130
+ [
131
+ 'label' => esc_html__( 'Show Media Elements', 'essential-addons-elementor' ),
132
+ 'type' => Controls_Manager::SWITCHER,
133
+ 'label_on' => __( 'yes', 'essential-addons-elementor' ),
134
+ 'label_off' => __( 'no', 'essential-addons-elementor' ),
135
+ 'default' => 'true',
136
+ 'return_value' => 'true',
137
+ ]
138
+ );
139
+
140
+ $this->end_controls_section();
141
+
142
+ $this->start_controls_section(
143
+ 'eael_section_facebook_feed_card_settings',
144
+ [
145
+ 'label' => esc_html__( 'Card Settings', 'essential-addons-elementor' ),
146
+ ]
147
+ );
148
+
149
+ $this->add_control(
150
+ 'eael_facebook_feed_show_avatar',
151
+ [
152
+ 'label' => esc_html__( 'Show Avatar', 'essential-addons-elementor' ),
153
+ 'type' => Controls_Manager::SWITCHER,
154
+ 'label_on' => __( 'yes', 'essential-addons-elementor' ),
155
+ 'label_off' => __( 'no', 'essential-addons-elementor' ),
156
+ 'default' => 'true',
157
+ 'return_value' => 'true',
158
+ ]
159
+ );
160
+
161
+ $this->add_control(
162
+ 'eael_facebook_feed_avatar_style',
163
+ [
164
+ 'label' => __( 'Avatar Style', 'essential-addons-elementor' ),
165
+ 'type' => Controls_Manager::SELECT,
166
+ 'options' => [
167
+ 'circle' => 'Circle',
168
+ 'square' => 'Square'
169
+ ],
170
+ 'default' => 'circle',
171
+ 'prefix_class' => 'eael-social-feed-avatar-',
172
+ 'condition' => [
173
+ 'eael_facebook_feed_show_avatar' => 'true'
174
+ ],
175
+ ]
176
+ );
177
+
178
+ $this->add_control(
179
+ 'eael_facebook_feed_show_date',
180
+ [
181
+ 'label' => esc_html__( 'Show Date', 'essential-addons-elementor' ),
182
+ 'type' => Controls_Manager::SWITCHER,
183
+ 'label_on' => __( 'yes', 'essential-addons-elementor' ),
184
+ 'label_off' => __( 'no', 'essential-addons-elementor' ),
185
+ 'default' => 'true',
186
+ 'return_value' => 'true',
187
+ ]
188
+ );
189
+
190
+ $this->add_control(
191
+ 'eael_facebook_feed_show_read_more',
192
+ [
193
+ 'label' => esc_html__( 'Show Read More', 'essential-addons-elementor' ),
194
+ 'type' => Controls_Manager::SWITCHER,
195
+ 'label_on' => __( 'yes', 'essential-addons-elementor' ),
196
+ 'label_off' => __( 'no', 'essential-addons-elementor' ),
197
+ 'default' => 'true',
198
+ 'return_value' => 'true',
199
+ ]
200
+ );
201
+ $this->add_control(
202
+ 'eael_facebook_feed_show_icon',
203
+ [
204
+ 'label' => esc_html__( 'Show Icon', 'essential-addons-elementor' ),
205
+ 'type' => Controls_Manager::SWITCHER,
206
+ 'label_on' => __( 'yes', 'essential-addons-elementor' ),
207
+ 'label_off' => __( 'no', 'essential-addons-elementor' ),
208
+ 'default' => 'true',
209
+ 'return_value' => 'true',
210
+ ]
211
+ );
212
+
213
+ $this->end_controls_section();
214
+
215
+ $this->start_controls_section(
216
+ 'eael_section_pro',
217
+ [
218
+ 'label' => __( 'Go Premium for More Features', 'essential-addons-elementor' )
219
+ ]
220
+ );
221
+
222
+ $this->add_control(
223
+ 'eael_control_get_pro',
224
+ [
225
+ 'label' => __( 'Unlock more possibilities', 'essential-addons-elementor' ),
226
+ 'type' => Controls_Manager::CHOOSE,
227
+ 'options' => [
228
+ '1' => [
229
+ 'title' => __( '', 'essential-addons-elementor' ),
230
+ 'icon' => 'fa fa-unlock-alt',
231
+ ],
232
+ ],
233
+ 'default' => '1',
234
+ 'description' => '<span class="pro-feature"> Get the <a href="https://essential-addons.com/elementor/buy.php" target="_blank">Pro version</a> for more stunning elements and customization options.</span>'
235
+ ]
236
+ );
237
+
238
+ $this->end_controls_section();
239
+ /**
240
+ * -------------------------------------------
241
+ * Tab Style (Facebook Feed Title Style)
242
+ * -------------------------------------------
243
+ */
244
+ $this->start_controls_section(
245
+ 'eael_section_facebook_feed_style_settings',
246
+ [
247
+ 'label' => esc_html__( 'General Style', 'essential-addons-elementor' ),
248
+ 'tab' => Controls_Manager::TAB_STYLE
249
+ ]
250
+ );
251
+
252
+ $this->add_control(
253
+ 'eael_facebook_feed_bg_color',
254
+ [
255
+ 'label' => esc_html__( 'Background Color', 'essential-addons-elementor' ),
256
+ 'type' => Controls_Manager::COLOR,
257
+ 'default' => '',
258
+ 'selectors' => [
259
+ '{{WRAPPER}} .eael-facebook-feed-wrapper' => 'background-color: {{VALUE}};',
260
+ ],
261
+ ]
262
+ );
263
+
264
+ $this->add_responsive_control(
265
+ 'eael_facebook_feed_container_padding',
266
+ [
267
+ 'label' => esc_html__( 'Padding', 'essential-addons-elementor' ),
268
+ 'type' => Controls_Manager::DIMENSIONS,
269
+ 'size_units' => [ 'px', 'em', '%' ],
270
+ 'selectors' => [
271
+ '{{WRAPPER}} .eael-facebook-feed-wrapper' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
272
+ ],
273
+ ]
274
+ );
275
+
276
+ $this->add_responsive_control(
277
+ 'eael_facebook_feed_container_margin',
278
+ [
279
+ 'label' => esc_html__( 'Margin', 'essential-addons-elementor' ),
280
+ 'type' => Controls_Manager::DIMENSIONS,
281
+ 'size_units' => [ 'px', 'em', '%' ],
282
+ 'selectors' => [
283
+ '{{WRAPPER}} .eael-facebook-feed-wrapper' => 'margin: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
284
+ ],
285
+ ]
286
+ );
287
+
288
+ $this->add_group_control(
289
+ Group_Control_Border::get_type(),
290
+ [
291
+ 'name' => 'eael_facebook_feed_border',
292
+ 'label' => esc_html__( 'Border', 'essential-addons-elementor' ),
293
+ 'selector' => '{{WRAPPER}} .eael-facebook-feed-wrapper',
294
+ ]
295
+ );
296
+
297
+ $this->add_control(
298
+ 'eael_facebook_feed_border_radius',
299
+ [
300
+ 'label' => esc_html__( 'Border Radius', 'essential-addons-elementor' ),
301
+ 'type' => Controls_Manager::SLIDER,
302
+ 'range' => [
303
+ 'px' => [
304
+ 'max' => 500,
305
+ ],
306
+ ],
307
+ 'selectors' => [
308
+ '{{WRAPPER}} .eael-facebook-feed-wrapper' => 'border-radius: {{SIZE}}px;',
309
+ ],
310
+ ]
311
+ );
312
+
313
+ $this->add_group_control(
314
+ Group_Control_Box_Shadow::get_type(),
315
+ [
316
+ 'name' => 'eael_facebook_feed_shadow',
317
+ 'selector' => '{{WRAPPER}} .eael-facebook-feed-wrapper',
318
+ ]
319
+ );
320
+
321
+ $this->end_controls_section();
322
+
323
+ /**
324
+ * -------------------------------------------
325
+ * Tab Style (Facebook Feed Card Style)
326
+ * -------------------------------------------
327
+ */
328
+ $this->start_controls_section(
329
+ 'eael_section_facebook_feed_card_style_settings',
330
+ [
331
+ 'label' => esc_html__( 'Card Style', 'essential-addons-elementor' ),
332
+ 'tab' => Controls_Manager::TAB_STYLE
333
+ ]
334
+ );
335
+
336
+ $this->add_control(
337
+ 'eael_facebook_feed_card_bg_color',
338
+ [
339
+ 'label' => esc_html__( 'Background Color', 'essential-addons-elementor' ),
340
+ 'type' => Controls_Manager::COLOR,
341
+ 'default' => '',
342
+ 'selectors' => [
343
+ '{{WRAPPER}} .eael-social-feed-element .eael-content' => 'background-color: {{VALUE}};',
344
+ ],
345
+ ]
346
+ );
347
+
348
+ $this->add_responsive_control(
349
+ 'eael_facebook_feed_card_container_padding',
350
+ [
351
+ 'label' => esc_html__( 'Padding', 'essential-addons-elementor' ),
352
+ 'type' => Controls_Manager::DIMENSIONS,
353
+ 'size_units' => [ 'px', 'em', '%' ],
354
+ 'selectors' => [
355
+ '{{WRAPPER}} .eael-social-feed-element .eael-content' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
356
+ ],
357
+ ]
358
+ );
359
+
360
+ $this->add_responsive_control(
361
+ 'eael_facebook_feed_card_container_margin',
362
+ [
363
+ 'label' => esc_html__( 'Margin', 'essential-addons-elementor' ),
364
+ 'type' => Controls_Manager::DIMENSIONS,
365
+ 'size_units' => [ 'px', 'em', '%' ],
366
+ 'selectors' => [
367
+ '{{WRAPPER}} .eael-social-feed-element .eael-content' => 'margin: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
368
+ ],
369
+ ]
370
+ );
371
+
372
+ $this->add_group_control(
373
+ Group_Control_Border::get_type(),
374
+ [
375
+ 'name' => 'eael_facebook_feed_card_border',
376
+ 'label' => esc_html__( 'Border', 'essential-addons-elementor' ),
377
+ 'selector' => '{{WRAPPER}} .eael-social-feed-element .eael-content',
378
+ ]
379
+ );
380
+
381
+ $this->add_control(
382
+ 'eael_facebook_feed_card_border_radius',
383
+ [
384
+ 'label' => esc_html__( 'Border Radius', 'essential-addons-elementor' ),
385
+ 'type' => Controls_Manager::SLIDER,
386
+ 'range' => [
387
+ 'px' => [
388
+ 'max' => 500,
389
+ ],
390
+ ],
391
+ 'selectors' => [
392
+ '{{WRAPPER}} .eael-social-feed-element .eael-content' => 'border-radius: {{SIZE}}px;',
393
+ ],
394
+ ]
395
+ );
396
+
397
+ $this->add_group_control(
398
+ Group_Control_Box_Shadow::get_type(),
399
+ [
400
+ 'name' => 'eael_facebook_feed_card_shadow',
401
+ 'selector' => '{{WRAPPER}} .eael-social-feed-element .eael-content',
402
+ ]
403
+ );
404
+
405
+ $this->end_controls_section();
406
+
407
+ /**
408
+ * -------------------------------------------
409
+ * Tab Style (Twitter Feed Typography Style)
410
+ * -------------------------------------------
411
+ */
412
+ $this->start_controls_section(
413
+ 'eael_section_facebook_feed_card_typo_settings',
414
+ [
415
+ 'label' => esc_html__( 'Color &amp; Typography', 'essential-addons-elementor' ),
416
+ 'tab' => Controls_Manager::TAB_STYLE
417
+ ]
418
+ );
419
+
420
+ $this->add_control(
421
+ 'eael_facebook_feed_title_heading',
422
+ [
423
+ 'label' => esc_html__( 'Title Style', 'essential-addons-elementor' ),
424
+ 'type' => Controls_Manager::HEADING,
425
+ ]
426
+ );
427
+
428
+ $this->add_control(
429
+ 'eael_facebook_feed_title_color',
430
+ [
431
+ 'label' => esc_html__( 'Color', 'essential-addons-elementor' ),
432
+ 'type' => Controls_Manager::COLOR,
433
+ 'default' => '',
434
+ 'selectors' => [
435
+ '{{WRAPPER}} .eael-social-feed-element .author-title' => 'color: {{VALUE}};',
436
+ ],
437
+ ]
438
+ );
439
+
440
+ $this->add_group_control(
441
+ Group_Control_Typography::get_type(),
442
+ [
443
+ 'name' => 'eael_facebook_feed_title_typography',
444
+ 'selector' => '{{WRAPPER}} .eael-social-feed-element .author-title',
445
+ ]
446
+ );
447
+ // Content Style
448
+ $this->add_control(
449
+ 'eael_facebook_feed_content_heading',
450
+ [
451
+ 'label' => esc_html__( 'Content Style', 'essential-addons-elementor' ),
452
+ 'type' => Controls_Manager::HEADING,
453
+ 'separator' => 'before'
454
+ ]
455
+ );
456
+
457
+ $this->add_control(
458
+ 'eael_facebook_feed_content_color',
459
+ [
460
+ 'label' => esc_html__( 'Color', 'essential-addons-elementor' ),
461
+ 'type' => Controls_Manager::COLOR,
462
+ 'default' => '',
463
+ 'selectors' => [
464
+ '{{WRAPPER}} .eael-social-feed-element .social-feed-text' => 'color: {{VALUE}};',
465
+ ],
466
+ ]
467
+ );
468
+
469
+ $this->add_group_control(
470
+ Group_Control_Typography::get_type(),
471
+ [
472
+ 'name' => 'eael_facebook_feed_content_typography',
473
+ 'selector' => '{{WRAPPER}} .eael-social-feed-element .social-feed-text',
474
+ ]
475
+ );
476
+
477
+ // Content Link Style
478
+ $this->add_control(
479
+ 'eael_facebook_feed_content_link_heading',
480
+ [
481
+ 'label' => esc_html__( 'Link Style', 'essential-addons-elementor' ),
482
+ 'type' => Controls_Manager::HEADING,
483
+ 'separator' => 'before'
484
+ ]
485
+ );
486
+
487
+ $this->add_control(
488
+ 'eael_facebook_feed_content_link_color',
489
+ [
490
+ 'label' => esc_html__( 'Color', 'essential-addons-elementor' ),
491
+ 'type' => Controls_Manager::COLOR,
492
+ 'default' => '',
493
+ 'selectors' => [
494
+ '{{WRAPPER}} .eael-social-feed-element .text-wrapper a' => 'color: {{VALUE}};',
495
+ ],
496
+ ]
497
+ );
498
+
499
+ $this->add_control(
500
+ 'eael_facebook_feed_content_link_hover_color',
501
+ [
502
+ 'label' => esc_html__( 'Hover Color', 'essential-addons-elementor' ),
503
+ 'type' => Controls_Manager::COLOR,
504
+ 'default' => '',
505
+ 'selectors' => [
506
+ '{{WRAPPER}} .eael-social-feed-element .text-wrapper a:hover' => 'color: {{VALUE}};',
507
+ ],
508
+ ]
509
+ );
510
+
511
+ $this->add_group_control(
512
+ Group_Control_Typography::get_type(),
513
+ [
514
+ 'name' => 'eael_facebook_feed_content_link_typography',
515
+ 'selector' => '{{WRAPPER}} .eael-social-feed-element .text-wrapper a',
516
+ ]
517
+ );
518
+
519
+ $this->end_controls_section();
520
+
521
+ /**
522
+ * -------------------------------------------
523
+ * Tab Style (Facebook Feed Preloader Style)
524
+ * -------------------------------------------
525
+ */
526
+ $this->start_controls_section(
527
+ 'eael_section_facebook_feed_card_preloader_settings',
528
+ [
529
+ 'label' => esc_html__( 'Preloader Style', 'essential-addons-elementor' ),
530
+ 'tab' => Controls_Manager::TAB_STYLE
531
+ ]
532
+ );
533
+
534
+ $this->add_control(
535
+ 'eael_facebook_feed_preloader_size',
536
+ [
537
+ 'label' => esc_html__( 'Size', 'essential-addons-elementor' ),
538
+ 'type' => Controls_Manager::SLIDER,
539
+ 'default' => [
540
+ 'size' => 30,
541
+ ],
542
+ 'range' => [
543
+ 'px' => [
544
+ 'max' => 100,
545
+ ],
546
+ ],
547
+ 'selectors' => [
548
+ '{{WRAPPER}} .eael-loading-feed .loader' => 'width: {{SIZE}}px; height: {{SIZE}}px;',
549
+ ],
550
+ ]
551
+ );
552
+
553
+ $this->add_control(
554
+ 'eael_section_facebook_feed_preloader_color',
555
+ [
556
+ 'label' => esc_html__( 'Color', 'essential-addons-elementor' ),
557
+ 'type' => Controls_Manager::COLOR,
558
+ 'default' => '#3498db',
559
+ 'selectors' => [
560
+ '{{WRAPPER}} .eael-loading-feed .loader' => 'border-top-color: {{VALUE}};',
561
+ ],
562
+ ]
563
+ );
564
+
565
+
566
+ $this->end_controls_section();
567
+
568
+ }
569
+
570
+
571
+ protected function render( ) {
572
+
573
+ $settings = $this->get_settings();
574
+
575
+ if( 'list' == $settings['eael_facebook_feed_type'] ) {
576
+ $feed_class = 'list-view';
577
+ }elseif( 'masonry' == $settings['eael_facebook_feed_type'] ) {
578
+ $feed_class = 'masonry-view';
579
+ }
580
+
581
+
582
+ // Get the specific template
583
+ if( 'masonry' == $settings['eael_facebook_feed_type'] ) {
584
+ $template = 'masonry.php';
585
+ }else {
586
+ $template = 'list.php';
587
+ }
588
+
589
+
590
+ ?>
591
+ <div class="eael-facebook-feed-wrapper">
592
+ <div class="eael-facebook-feed-container <?php echo esc_attr( $feed_class ); ?>"></div>
593
+ <div class="eael-loading-feed"><div class="loader"></div></div>
594
+ </div>
595
+ <script>
596
+ jQuery( document ).ready( function($) {
597
+ var loadingFeed = $( '.eael-loading-feed' );
598
+ /**
599
+ * Facebook Feed Init
600
+ */
601
+ function eael_facebook_feeds() {
602
+
603
+ $( '.eael-facebook-feed-container' ).socialfeed({
604
+ facebook:{
605
+ accounts: ['<?php echo $settings['eael_facebook_feed_ac_name']; ?>'],
606
+ limit: <?php echo $settings['eael_facebook_feed_post_limit']; ?>,
607
+ access_token: '<?php echo $settings['eael_facebook_feed_app_id']; ?>|<?php echo $settings['eael_facebook_feed_app_secret']; ?>'
608
+ },
609
+
610
+ // GENERAL SETTINGS
611
+ length: <?php if( !empty( $settings['eael_facebook_feed_content_length'] ) ) : echo $settings['eael_facebook_feed_content_length']; else: echo '400'; endif; ?>,
612
+ show_media: <?php if( !empty( $settings['eael_facebook_feed_media'] ) ) : echo $settings['eael_facebook_feed_media']; else: echo 'false'; endif; ?>,
613
+ template: '<?php echo plugins_url( '/', __FILE__ ) . 'templates/'.$template; ?>',
614
+ });
615
+ }
616
+ /**
617
+ * Facebook Feed Masonry View
618
+ */
619
+ function eael_facebook_feed_masonry() {
620
+ $('.eael-facebook-feed-container').masonry({
621
+ itemSelector: '.eael-social-feed-element',
622
+ percentPosition: true,
623
+ columnWidth: '.eael-social-feed-element'
624
+ });
625
+ }
626
+
627
+ $.ajax({
628
+ url: eael_facebook_feeds(),
629
+ beforeSend: function() {
630
+ loadingFeed.addClass( 'show-loading' );
631
+ },
632
+ success: function() {
633
+ <?php if( 'masonry' == $settings['eael_facebook_feed_type'] ) : ?>
634
+ eael_facebook_feed_masonry();
635
+ <?php endif; ?>
636
+ loadingFeed.removeClass( 'show-loading' );
637
+ },
638
+ error: function() {
639
+ console.log('error loading');
640
+ }
641
+ });
642
+
643
+ });
644
+
645
+ </script>
646
+
647
+ <?php
648
+ echo '<style>';
649
+ // Show Avatar
650
+ if( $settings['eael_facebook_feed_show_avatar'] == 'true' ) {
651
+ echo '.eael-social-feed-element .auth-img { display: block; }';
652
+ }else {
653
+ echo '.eael-social-feed-element .auth-img { display: none; }';
654
+ }
655
+ // Show Date
656
+ if( $settings['eael_facebook_feed_show_date'] == 'true' ) {
657
+ echo '.eael-social-feed-element .social-feed-date { display: block; }';
658
+ }else {
659
+ echo '.eael-social-feed-element .social-feed-date { display: none; }';
660
+ }
661
+ // Show Read More
662
+ if( $settings['eael_facebook_feed_show_read_more'] == 'true' ) {
663
+ echo '.eael-social-feed-element .read-more-link { display: block }';
664
+ }else {
665
+ echo '.eael-social-feed-element .read-more-link { display: none !important; }';
666
+ }
667
+
668
+ // Show Icon
669
+ if( $settings['eael_facebook_feed_show_icon'] == 'true' ) {
670
+ echo '.eael-social-feed-element .social-feed-icon { display: inline-block }';
671
+ }else {
672
+ echo '.eael-social-feed-element .social-feed-icon { display: none !important; }';
673
+ }
674
+
675
+ // Masonry Grid
676
+ if( $settings['eael_facebook_feed_type_col_type'] == 'col-2' ) {
677
+ $width = '50%';
678
+ }else if( $settings['eael_facebook_feed_type_col_type'] == 'col-3' ) {
679
+ $width = '33.33%';
680
+ }else if( $settings['eael_facebook_feed_type_col_type'] == 'col-4' ) {
681
+ $width = '25%';
682
+ echo '.eael-social-feed-element .social-feed-date { text-align: left; width: 100%; margin-bottom: 8px;}';
683
+ }
684
+ echo '.eael-facebook-feed-container.masonry-view .eael-social-feed-element { width: '.$width.' }
685
+ .eael-social-feed-element .media-object { width: 30px; }';
686
+
687
+ echo '</style>';
688
+ }
689
+
690
+ protected function content_template() {''
691
+
692
+ ?>
693
+
694
+
695
+ <?php
696
+ }
697
+ }
698
+
699
+
700
+ Plugin::instance()->widgets_manager->register_widget_type( new Widget_Eael_Facebook_Feed() );
elements/facebook-feed/templates/list.php ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Template: Facebook List
4
+ */
5
+ ?>
6
+ <div class="eael-social-feed-element {{? !it.moderation_passed}}hidden{{?}}" dt-create="{{=it.dt_create}}" social-feed-id = "{{=it.id}}">
7
+ {{=it.attachment}}
8
+ <div class='eael-content'>
9
+ <a class="pull-left auth-img" href="{{=it.author_link}}" target="_blank">
10
+ <img class="media-object" src="{{=it.author_picture}}">
11
+ </a>
12
+ <div class="media-body">
13
+ <p>
14
+ <i class="fa fa-{{=it.social_network}} social-feed-icon"></i>
15
+ <span class="author-title">{{=it.author_name}}</span>
16
+ <span class="muted pull-right social-feed-date"> {{=it.time_ago}}</span>
17
+ </p>
18
+ <div class='text-wrapper'>
19
+ <p class="social-feed-text">{{=it.text}} </p>
20
+ <p><a href="{{=it.link}}" target="_blank" class="read-more-link">Read More</a></p>
21
+ </div>
22
+ </div>
23
+ </div>
24
+ </div>
elements/facebook-feed/templates/masonry.php ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Template: Facebook Masonry
4
+ */
5
+ ?>
6
+ <div class="eael-social-feed-element {{? !it.moderation_passed}}hidden{{?}}" dt-create="{{=it.dt_create}}" social-feed-id = "{{=it.id}}">
7
+ {{=it.attachment}}
8
+ <div class='eael-content'>
9
+ <a class="pull-left auth-img" href="{{=it.author_link}}" target="_blank">
10
+ <img class="media-object" src="{{=it.author_picture}}">
11
+ </a>
12
+ <div class="media-body">
13
+ <p>
14
+ <i class="fa fa-{{=it.social_network}} social-feed-icon"></i>
15
+ <span class="author-title">{{=it.author_name}}</span>
16
+ <span class="muted pull-right social-feed-date"> {{=it.time_ago}}</span>
17
+ </p>
18
+ <div class='text-wrapper'>
19
+ <p class="social-feed-text">{{=it.text}} </p>
20
+ <p><a href="{{=it.link}}" target="_blank" class="read-more-link">Read More</a></p>
21
+ </div>
22
+ </div>
23
+ </div>
24
+ </div>
elements/twitter-feed/templates/list.php ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Template: Twitter List
4
+ */
5
+ ?>
6
+ <div class="eael-social-feed-element {{? !it.moderation_passed}}hidden{{?}}" dt-create="{{=it.dt_create}}" social-feed-id = "{{=it.id}}">
7
+ <div class='eael-content'>
8
+ <a class="pull-left auth-img" href="{{=it.author_link}}" target="_blank">
9
+ <img class="media-object" src="{{=it.author_picture}}">
10
+ </a>
11
+ <div class="media-body">
12
+ <p>
13
+ <i class="fa fa-{{=it.social_network}} social-feed-icon"></i>
14
+ <span class="author-title">{{=it.author_name}}</span>
15
+ <span class="muted pull-right social-feed-date"> {{=it.time_ago}}</span>
16
+ </p>
17
+ <div class='text-wrapper'>
18
+ <p class="social-feed-text">{{=it.text}} </p>
19
+ <p><a href="{{=it.link}}" target="_blank" class="read-more-link">Read More <i class="fa fa-angle-double-right"></i></a></p>
20
+ </div>
21
+ </div>
22
+ </div>
23
+ {{=it.attachment}}
24
+ </div>
elements/twitter-feed/templates/masonry.php ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Template: Twitter Masonry
4
+ */
5
+ ?>
6
+ <div class="eael-social-feed-element {{? !it.moderation_passed}}hidden{{?}}" dt-create="{{=it.dt_create}}" social-feed-id = "{{=it.id}}">
7
+ <div class='eael-content'>
8
+ <a class="pull-left auth-img" href="{{=it.author_link}}" target="_blank">
9
+ <img class="media-object" src="{{=it.author_picture}}">
10
+ </a>
11
+ <div class="media-body">
12
+ <p>
13
+ <i class="fa fa-{{=it.social_network}} social-feed-icon"></i>
14
+ <span class="author-title">{{=it.author_name}}</span>
15
+ <span class="muted pull-right social-feed-date"> {{=it.time_ago}}</span>
16
+ </p>
17
+ <div class='text-wrapper'>
18
+ <p class="social-feed-text">{{=it.text}} </p>
19
+ <p><a href="{{=it.link}}" target="_blank" class="read-more-link">Read More <i class="fa fa-angle-double-right"></i></a></p>
20
+ </div>
21
+ </div>
22
+ </div>
23
+ {{=it.attachment}}
24
+ </div>
elements/twitter-feed/twitter-feed.php ADDED
@@ -0,0 +1,715 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Elementor;
3
+
4
+ if ( ! defined( 'ABSPATH' ) ) exit; // If this file is called directly, abort.
5
+
6
+
7
+ class Widget_Eael_Twitter_Feed extends Widget_Base {
8
+
9
+ public function get_name() {
10
+ return 'eael-twitter-feed';
11
+ }
12
+
13
+ public function get_title() {
14
+ return esc_html__( 'EA Twitter Feed', 'essential-addons-elementor' );
15
+ }
16
+
17
+ public function get_icon() {
18
+ return 'fa fa-twitter';
19
+ }
20
+
21
+ public function get_categories() {
22
+ return [ 'essential-addons-elementor' ];
23
+ }
24
+
25
+ protected function _register_controls() {
26
+
27
+ $this->start_controls_section(
28
+ 'eael_section_twitter_feed_acc_settings',
29
+ [
30
+ 'label' => esc_html__( 'Account Settings', 'essential-addons-elementor' )
31
+ ]
32
+ );
33
+
34
+ $this->add_control(
35
+ 'eael_twitter_feed_ac_name',
36
+ [
37
+ 'label' => esc_html__( 'Account Name', 'essential-addons-elementor' ),
38
+ 'type' => Controls_Manager::TEXT,
39
+ 'default' => '@Codetic_',
40
+ 'label_block' => false,
41
+ 'description' => esc_html__( 'Use @ sign with your account name.', 'essential-addons-elementor' ),
42
+
43
+ ]
44
+ );
45
+
46
+ $this->add_control(
47
+ 'eael_twitter_feed_hashtag_name',
48
+ [
49
+ 'label' => esc_html__( 'Hashtag Name', 'essential-addons-elementor' ),
50
+ 'type' => Controls_Manager::TEXT,
51
+ 'label_block' => false,
52
+ 'description' => esc_html__( 'Use # sign with your hashtag name.', 'essential-addons-elementor' ),
53
+
54
+ ]
55
+ );
56
+
57
+ $this->add_control(
58
+ 'eael_twitter_feed_consumer_key',
59
+ [
60
+ 'label' => esc_html__( 'Consumer Key', 'essential-addons-elementor' ),
61
+ 'type' => Controls_Manager::TEXT,
62
+ 'label_block' => false,
63
+ 'default' => 'wwC72W809xRKd9ySwUzXzjkmS',
64
+ 'description' => '<a href="https://apps.twitter.com/app/" target="_blank">Get Consumer Key.</a> Create a new app or select existing app and grab the <b>consumer key.</b>',
65
+ ]
66
+ );
67
+
68
+ $this->add_control(
69
+ 'eael_twitter_feed_consumer_secret',
70
+ [
71
+ 'label' => esc_html__( 'Consumer Secret', 'essential-addons-elementor' ),
72
+ 'type' => Controls_Manager::TEXT,
73
+ 'label_block' => false,
74
+ 'default' => 'rn54hBqxjve2CWOtZqwJigT3F5OEvrriK2XAcqoQVohzr2UA8h',
75
+ 'description' => '<a href="https://apps.twitter.com/app/" target="_blank">Get Consumer Secret.</a> Create a new app or select existing app and grab the <b>consumer secret.</b>',
76
+ ]
77
+ );
78
+
79
+ $this->end_controls_section();
80
+
81
+ $this->start_controls_section(
82
+ 'eael_section_twitter_feed_settings',
83
+ [
84
+ 'label' => esc_html__( 'Layout Settings', 'essential-addons-elementor' )
85
+ ]
86
+ );
87
+
88
+ $this->add_control(
89
+ 'eael_twitter_feed_type',
90
+ [
91
+ 'label' => esc_html__( 'Content Layout', 'essential-addons-elementor' ),
92
+ 'type' => Controls_Manager::SELECT,
93
+ 'default' => 'masonry',
94
+ 'options' => [
95
+ 'list' => esc_html__( 'List', 'essential-addons-elementor' ),
96
+ 'masonry' => esc_html__( 'Masonry', 'essential-addons-elementor' ),
97
+ ],
98
+ ]
99
+ );
100
+
101
+ $this->add_control(
102
+ 'eael_twitter_feed_type_col_type',
103
+ [
104
+ 'label' => __( 'Column Grid', 'essential-addons-elementor' ),
105
+ 'type' => Controls_Manager::SELECT,
106
+ 'options' => [
107
+ 'col-2' => '2 Columns',
108
+ 'col-3' => '3 Columns',
109
+ 'col-4' => '4 Columns',
110
+ ],
111
+ 'default' => 'col-3',
112
+ 'condition' => [
113
+ 'eael_twitter_feed_type' => 'masonry'
114
+ ],
115
+ ]
116
+ );
117
+
118
+ $this->add_control(
119
+ 'eael_twitter_feed_content_length',
120
+ [
121
+ 'label' => esc_html__( 'Content Length', 'essential-addons-elementor' ),
122
+ 'type' => Controls_Manager::TEXT,
123
+ 'label_block' => false,
124
+ 'default' => '400'
125
+ ]
126
+ );
127
+
128
+ $this->add_control(
129
+ 'eael_twitter_feed_post_limit',
130
+ [
131
+ 'label' => esc_html__( 'Post Limit', 'essential-addons-elementor' ),
132
+ 'type' => Controls_Manager::NUMBER,
133
+ 'label_block' => false,
134
+ 'default' => 10
135
+ ]
136
+ );
137
+
138
+ $this->add_control(
139
+ 'eael_twitter_feed_media',
140
+ [
141
+ 'label' => esc_html__( 'Show Media Elements', 'essential-addons-elementor' ),
142
+ 'type' => Controls_Manager::SWITCHER,
143
+ 'label_on' => __( 'yes', 'essential-addons-elementor' ),
144
+ 'label_off' => __( 'no', 'essential-addons-elementor' ),
145
+ 'default' => 'true',
146
+ 'return_value' => 'true',
147
+ ]
148
+ );
149
+
150
+ $this->end_controls_section();
151
+
152
+ $this->start_controls_section(
153
+ 'eael_section_twitter_feed_card_settings',
154
+ [
155
+ 'label' => esc_html__( 'Card Settings', 'essential-addons-elementor' ),
156
+ ]
157
+ );
158
+
159
+ $this->add_control(
160
+ 'eael_twitter_feed_show_avatar',
161
+ [
162
+ 'label' => esc_html__( 'Show Avatar', 'essential-addons-elementor' ),
163
+ 'type' => Controls_Manager::SWITCHER,
164
+ 'label_on' => __( 'yes', 'essential-addons-elementor' ),
165
+ 'label_off' => __( 'no', 'essential-addons-elementor' ),
166
+ 'default' => 'true',
167
+ 'return_value' => 'true',
168
+ ]
169
+ );
170
+
171
+ $this->add_control(
172
+ 'eael_twitter_feed_avatar_style',
173
+ [
174
+ 'label' => __( 'Avatar Style', 'essential-addons-elementor' ),
175
+ 'type' => Controls_Manager::SELECT,
176
+ 'options' => [
177
+ 'circle' => 'Circle',
178
+ 'square' => 'Square'
179
+ ],
180
+ 'default' => 'circle',
181
+ 'prefix_class' => 'eael-social-feed-avatar-',
182
+ 'condition' => [
183
+ 'eael_twitter_feed_show_avatar' => 'true'
184
+ ],
185
+ ]
186
+ );
187
+
188
+ $this->add_control(
189
+ 'eael_twitter_feed_show_date',
190
+ [
191
+ 'label' => esc_html__( 'Show Date', 'essential-addons-elementor' ),
192
+ 'type' => Controls_Manager::SWITCHER,
193
+ 'label_on' => __( 'yes', 'essential-addons-elementor' ),
194
+ 'label_off' => __( 'no', 'essential-addons-elementor' ),
195
+ 'default' => 'true',
196
+ 'return_value' => 'true',
197
+ ]
198
+ );
199
+
200
+ $this->add_control(
201
+ 'eael_twitter_feed_show_read_more',
202
+ [
203
+ 'label' => esc_html__( 'Show Read More', 'essential-addons-elementor' ),
204
+ 'type' => Controls_Manager::SWITCHER,
205
+ 'label_on' => __( 'yes', 'essential-addons-elementor' ),
206
+ 'label_off' => __( 'no', 'essential-addons-elementor' ),
207
+ 'default' => 'true',
208
+ 'return_value' => 'true',
209
+ ]
210
+ );
211
+
212
+ $this->add_control(
213
+ 'eael_twitter_feed_show_icon',
214
+ [
215
+ 'label' => esc_html__( 'Show Icon', 'essential-addons-elementor' ),
216
+ 'type' => Controls_Manager::SWITCHER,
217
+ 'label_on' => __( 'yes', 'essential-addons-elementor' ),
218
+ 'label_off' => __( 'no', 'essential-addons-elementor' ),
219
+ 'default' => 'true',
220
+ 'return_value' => 'true',
221
+ ]
222
+ );
223
+
224
+ $this->end_controls_section();
225
+
226
+ $this->start_controls_section(
227
+ 'eael_section_pro',
228
+ [
229
+ 'label' => __( 'Go Premium for More Features', 'essential-addons-elementor' )
230
+ ]
231
+ );
232
+
233
+ $this->add_control(
234
+ 'eael_control_get_pro',
235
+ [
236
+ 'label' => __( 'Unlock more possibilities', 'essential-addons-elementor' ),
237
+ 'type' => Controls_Manager::CHOOSE,
238
+ 'options' => [
239
+ '1' => [
240
+ 'title' => __( '', 'essential-addons-elementor' ),
241
+ 'icon' => 'fa fa-unlock-alt',
242
+ ],
243
+ ],
244
+ 'default' => '1',
245
+ 'description' => '<span class="pro-feature"> Get the <a href="https://essential-addons.com/elementor/buy.php" target="_blank">Pro version</a> for more stunning elements and customization options.</span>'
246
+ ]
247
+ );
248
+
249
+ $this->end_controls_section();
250
+ /**
251
+ * -------------------------------------------
252
+ * Tab Style (Twitter Feed Title Style)
253
+ * -------------------------------------------
254
+ */
255
+ $this->start_controls_section(
256
+ 'eael_section_twitter_feed_style_settings',
257
+ [
258
+ 'label' => esc_html__( 'General Style', 'essential-addons-elementor' ),
259
+ 'tab' => Controls_Manager::TAB_STYLE
260
+ ]
261
+ );
262
+
263
+ $this->add_control(
264
+ 'eael_twitter_feed_bg_color',
265
+ [
266
+ 'label' => esc_html__( 'Background Color', 'essential-addons-elementor' ),
267
+ 'type' => Controls_Manager::COLOR,
268
+ 'default' => '',
269
+ 'selectors' => [
270
+ '{{WRAPPER}} .eael-twitter-feed-wrapper' => 'background-color: {{VALUE}};',
271
+ ],
272
+ ]
273
+ );
274
+
275
+ $this->add_responsive_control(
276
+ 'eael_twitter_feed_container_padding',
277
+ [
278
+ 'label' => esc_html__( 'Padding', 'essential-addons-elementor' ),
279
+ 'type' => Controls_Manager::DIMENSIONS,
280
+ 'size_units' => [ 'px', 'em', '%' ],
281
+ 'selectors' => [
282
+ '{{WRAPPER}} .eael-twitter-feed-wrapper' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
283
+ ],
284
+ ]
285
+ );
286
+
287
+ $this->add_responsive_control(
288
+ 'eael_twitter_feed_container_margin',
289
+ [
290
+ 'label' => esc_html__( 'Margin', 'essential-addons-elementor' ),
291
+ 'type' => Controls_Manager::DIMENSIONS,
292
+ 'size_units' => [ 'px', 'em', '%' ],
293
+ 'selectors' => [
294
+ '{{WRAPPER}} .eael-twitter-feed-wrapper' => 'margin: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
295
+ ],
296
+ ]
297
+ );
298
+
299
+ $this->add_group_control(
300
+ Group_Control_Border::get_type(),
301
+ [
302
+ 'name' => 'eael_twitter_feed_border',
303
+ 'label' => esc_html__( 'Border', 'essential-addons-elementor' ),
304
+ 'selector' => '{{WRAPPER}} .eael-twitter-feed-wrapper',
305
+ ]
306
+ );
307
+
308
+ $this->add_control(
309
+ 'eael_twitter_feed_border_radius',
310
+ [
311
+ 'label' => esc_html__( 'Border Radius', 'essential-addons-elementor' ),
312
+ 'type' => Controls_Manager::SLIDER,
313
+ 'range' => [
314
+ 'px' => [
315
+ 'max' => 500,
316
+ ],
317
+ ],
318
+ 'selectors' => [
319
+ '{{WRAPPER}} .eael-twitter-feed-wrapper' => 'border-radius: {{SIZE}}px;',
320
+ ],
321
+ ]
322
+ );
323
+
324
+ $this->add_group_control(
325
+ Group_Control_Box_Shadow::get_type(),
326
+ [
327
+ 'name' => 'eael_twitter_feed_shadow',
328
+ 'selector' => '{{WRAPPER}} .eael-twitter-feed-wrapper',
329
+ ]
330
+ );
331
+
332
+ $this->end_controls_section();
333
+
334
+ /**
335
+ * -------------------------------------------
336
+ * Tab Style (Twitter Feed Card Style)
337
+ * -------------------------------------------
338
+ */
339
+ $this->start_controls_section(
340
+ 'eael_section_twitter_feed_card_style_settings',
341
+ [
342
+ 'label' => esc_html__( 'Card Style', 'essential-addons-elementor' ),
343
+ 'tab' => Controls_Manager::TAB_STYLE
344
+ ]
345
+ );
346
+
347
+ $this->add_control(
348
+ 'eael_twitter_feed_card_bg_color',
349
+ [
350
+ 'label' => esc_html__( 'Background Color', 'essential-addons-elementor' ),
351
+ 'type' => Controls_Manager::COLOR,
352
+ 'default' => '',
353
+ 'selectors' => [
354
+ '{{WRAPPER}} .eael-social-feed-element .eael-content' => 'background-color: {{VALUE}};',
355
+ ],
356
+ ]
357
+ );
358
+
359
+ $this->add_responsive_control(
360
+ 'eael_twitter_feed_card_container_padding',
361
+ [
362
+ 'label' => esc_html__( 'Padding', 'essential-addons-elementor' ),
363
+ 'type' => Controls_Manager::DIMENSIONS,
364
+ 'size_units' => [ 'px', 'em', '%' ],
365
+ 'selectors' => [
366
+ '{{WRAPPER}} .eael-social-feed-element .eael-content' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
367
+ ],
368
+ ]
369
+ );
370
+
371
+ $this->add_responsive_control(
372
+ 'eael_twitter_feed_card_container_margin',
373
+ [
374
+ 'label' => esc_html__( 'Margin', 'essential-addons-elementor' ),
375
+ 'type' => Controls_Manager::DIMENSIONS,
376
+ 'size_units' => [ 'px', 'em', '%' ],
377
+ 'selectors' => [
378
+ '{{WRAPPER}} .eael-social-feed-element .eael-content' => 'margin: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
379
+ ],
380
+ ]
381
+ );
382
+
383
+ $this->add_group_control(
384
+ Group_Control_Border::get_type(),
385
+ [
386
+ 'name' => 'eael_twitter_feed_card_border',
387
+ 'label' => esc_html__( 'Border', 'essential-addons-elementor' ),
388
+ 'selector' => '{{WRAPPER}} .eael-social-feed-element .eael-content',
389
+ ]
390
+ );
391
+
392
+ $this->add_control(
393
+ 'eael_twitter_feed_card_border_radius',
394
+ [
395
+ 'label' => esc_html__( 'Border Radius', 'essential-addons-elementor' ),
396
+ 'type' => Controls_Manager::SLIDER,
397
+ 'range' => [
398
+ 'px' => [
399
+ 'max' => 500,
400
+ ],
401
+ ],
402
+ 'selectors' => [
403
+ '{{WRAPPER}} .eael-social-feed-element .eael-content' => 'border-radius: {{SIZE}}px;',
404
+ ],
405
+ ]
406
+ );
407
+
408
+ $this->add_group_control(
409
+ Group_Control_Box_Shadow::get_type(),
410
+ [
411
+ 'name' => 'eael_twitter_feed_card_shadow',
412
+ 'selector' => '{{WRAPPER}} .eael-social-feed-element .eael-content',
413
+ ]
414
+ );
415
+
416
+ $this->end_controls_section();
417
+
418
+ /**
419
+ * -------------------------------------------
420
+ * Tab Style (Twitter Feed Typography Style)
421
+ * -------------------------------------------
422
+ */
423
+ $this->start_controls_section(
424
+ 'eael_section_twitter_feed_card_typo_settings',
425
+ [
426
+ 'label' => esc_html__( 'Color &amp; Typography', 'essential-addons-elementor' ),
427
+ 'tab' => Controls_Manager::TAB_STYLE
428
+ ]
429
+ );
430
+
431
+ $this->add_control(
432
+ 'eael_twitter_feed_title_heading',
433
+ [
434
+ 'label' => esc_html__( 'Title Style', 'essential-addons-elementor' ),
435
+ 'type' => Controls_Manager::HEADING,
436
+ ]
437
+ );
438
+
439
+ $this->add_control(
440
+ 'eael_twitter_feed_title_color',
441
+ [
442
+ 'label' => esc_html__( 'Color', 'essential-addons-elementor' ),
443
+ 'type' => Controls_Manager::COLOR,
444
+ 'default' => '',
445
+ 'selectors' => [
446
+ '{{WRAPPER}} .eael-social-feed-element .author-title' => 'color: {{VALUE}};',
447
+ ],
448
+ ]
449
+ );
450
+
451
+ $this->add_group_control(
452
+ Group_Control_Typography::get_type(),
453
+ [
454
+ 'name' => 'eael_twitter_feed_title_typography',
455
+ 'selector' => '{{WRAPPER}} .eael-social-feed-element .author-title',
456
+ ]
457
+ );
458
+ // Content Style
459
+ $this->add_control(
460
+ 'eael_twitter_feed_content_heading',
461
+ [
462
+ 'label' => esc_html__( 'Content Style', 'essential-addons-elementor' ),
463
+ 'type' => Controls_Manager::HEADING,
464
+ 'separator' => 'before'
465
+ ]
466
+ );
467
+
468
+ $this->add_control(
469
+ 'eael_twitter_feed_content_color',
470
+ [
471
+ 'label' => esc_html__( 'Color', 'essential-addons-elementor' ),
472
+ 'type' => Controls_Manager::COLOR,
473
+ 'default' => '',
474
+ 'selectors' => [
475
+ '{{WRAPPER}} .eael-social-feed-element .social-feed-text' => 'color: {{VALUE}};',
476
+ ],
477
+ ]
478
+ );
479
+
480
+ $this->add_group_control(
481
+ Group_Control_Typography::get_type(),
482
+ [
483
+ 'name' => 'eael_twitter_feed_content_typography',
484
+ 'selector' => '{{WRAPPER}} .eael-social-feed-element .social-feed-text',
485
+ ]
486
+ );
487
+
488
+ // Content Link Style
489
+ $this->add_control(
490
+ 'eael_twitter_feed_content_link_heading',
491
+ [
492
+ 'label' => esc_html__( 'Link Style', 'essential-addons-elementor' ),
493
+ 'type' => Controls_Manager::HEADING,
494
+ 'separator' => 'before'
495
+ ]
496
+ );
497
+
498
+ $this->add_control(
499
+ 'eael_twitter_feed_content_link_color',
500
+ [
501
+ 'label' => esc_html__( 'Color', 'essential-addons-elementor' ),
502
+ 'type' => Controls_Manager::COLOR,
503
+ 'default' => '',
504
+ 'selectors' => [
505
+ '{{WRAPPER}} .eael-social-feed-element .text-wrapper a' => 'color: {{VALUE}};',
506
+ ],
507
+ ]
508
+ );
509
+
510
+ $this->add_control(
511
+ 'eael_twitter_feed_content_link_hover_color',
512
+ [
513
+ 'label' => esc_html__( 'Hover Color', 'essential-addons-elementor' ),
514
+ 'type' => Controls_Manager::COLOR,
515
+ 'default' => '',
516
+ 'selectors' => [
517
+ '{{WRAPPER}} .eael-social-feed-element .text-wrapper a:hover' => 'color: {{VALUE}};',
518
+ ],
519
+ ]
520
+ );
521
+
522
+ $this->add_group_control(
523
+ Group_Control_Typography::get_type(),
524
+ [
525
+ 'name' => 'eael_twitter_feed_content_link_typography',
526
+ 'selector' => '{{WRAPPER}} .eael-social-feed-element .text-wrapper a',
527
+ ]
528
+ );
529
+
530
+ $this->end_controls_section();
531
+
532
+ /**
533
+ * -------------------------------------------
534
+ * Tab Style (Twitter Feed Preloader Style)
535
+ * -------------------------------------------
536
+ */
537
+ $this->start_controls_section(
538
+ 'eael_section_twitter_feed_card_preloader_settings',
539
+ [
540
+ 'label' => esc_html__( 'Preloader Style', 'essential-addons-elementor' ),
541
+ 'tab' => Controls_Manager::TAB_STYLE
542
+ ]
543
+ );
544
+
545
+ $this->add_control(
546
+ 'eael_twitter_feed_preloader_size',
547
+ [
548
+ 'label' => esc_html__( 'Size', 'essential-addons-elementor' ),
549
+ 'type' => Controls_Manager::SLIDER,
550
+ 'default' => [
551
+ 'size' => 30,
552
+ ],
553
+ 'range' => [
554
+ 'px' => [
555
+ 'max' => 100,
556
+ ],
557
+ ],
558
+ 'selectors' => [
559
+ '{{WRAPPER}} .eael-loading-feed .loader' => 'width: {{SIZE}}px; height: {{SIZE}}px;',
560
+ ],
561
+ ]
562
+ );
563
+
564
+ $this->add_control(
565
+ 'eael_section_twitter_feed_preloader_color',
566
+ [
567
+ 'label' => esc_html__( 'Color', 'essential-addons-elementor' ),
568
+ 'type' => Controls_Manager::COLOR,
569
+ 'default' => '#3498db',
570
+ 'selectors' => [
571
+ '{{WRAPPER}} .eael-loading-feed .loader' => 'border-top-color: {{VALUE}};',
572
+ ],
573
+ ]
574
+ );
575
+
576
+
577
+ $this->end_controls_section();
578
+
579
+ }
580
+
581
+
582
+ protected function render( ) {
583
+
584
+ $settings = $this->get_settings();
585
+
586
+ if( 'list' == $settings['eael_twitter_feed_type'] ) {
587
+ $feed_class = 'list-view';
588
+ }elseif( 'masonry' == $settings['eael_twitter_feed_type'] ) {
589
+ $feed_class = 'masonry-view';
590
+ }
591
+
592
+ // Get the specific template
593
+ if( 'masonry' == $settings['eael_twitter_feed_type'] ) {
594
+ $template = 'masonry.php';
595
+ }else {
596
+ $template = 'list.php';
597
+ }
598
+
599
+ ?>
600
+ <div class="eael-twitter-feed-wrapper">
601
+ <div class="eael-twitter-feed-container <?php echo esc_attr( $feed_class ); ?>"></div>
602
+ <div class="eael-loading-feed"><div class="loader"></div></div>
603
+ </div>
604
+ <script>
605
+ jQuery( document ).ready( function($) {
606
+ var loadingFeed = $( '.eael-loading-feed' );
607
+
608
+ /**
609
+ * Twitter Feed Init
610
+ */
611
+ function eael_twitter_feeds() {
612
+ $( '.eael-twitter-feed-container' ).socialfeed({
613
+ // TWITTER
614
+ twitter:{
615
+ accounts: ['<?php echo $settings['eael_twitter_feed_ac_name']; ?>', '<?php echo $settings['eael_twitter_feed_hashtag_name']; ?>'],
616
+ limit: <?php echo $settings['eael_twitter_feed_post_limit']; ?>,
617
+ consumer_key: '<?php echo $settings['eael_twitter_feed_consumer_key']; ?>',
618
+ consumer_secret: '<?php echo $settings['eael_twitter_feed_consumer_secret']; ?>',
619
+ },
620
+
621
+ // GENERAL SETTINGS
622
+ length: <?php if( !empty( $settings['eael_twitter_feed_content_length'] ) ) : echo $settings['eael_twitter_feed_content_length']; else: echo '400'; endif; ?>,
623
+ show_media: <?php if( !empty( $settings['eael_twitter_feed_media'] ) ) : echo $settings['eael_twitter_feed_media']; else: echo 'false'; endif; ?>,
624
+ template: '<?php echo plugins_url( '/', __FILE__ ) . 'templates/'.$template; ?>',
625
+ });
626
+ }
627
+
628
+ /**
629
+ * Twitter Feed masonry View
630
+ */
631
+ function eael_twitter_feed_masonry() {
632
+ $('.eael-twitter-feed-container').masonry({
633
+ itemSelector: '.eael-social-feed-element',
634
+ percentPosition: true,
635
+ columnWidth: '.eael-social-feed-element'
636
+ });
637
+ }
638
+
639
+ $.ajax({
640
+ url: eael_twitter_feeds(),
641
+ beforeSend: function() {
642
+ loadingFeed.addClass( 'show-loading' );
643
+ },
644
+ success: function() {
645
+ setInterval( function() {
646
+ <?php if( 'masonry' == $settings['eael_twitter_feed_type'] ) : ?>
647
+ eael_twitter_feed_masonry();
648
+ <?php endif; ?>
649
+ loadingFeed.removeClass( 'show-loading' );
650
+ }, 3000 );
651
+ },
652
+ error: function() {
653
+ console.log('error loading');
654
+ }
655
+ });
656
+
657
+ });
658
+
659
+
660
+ </script>
661
+
662
+
663
+ <?php
664
+ echo '<style>';
665
+ // Show Avatar
666
+ if( $settings['eael_twitter_feed_show_avatar'] == 'true' ) {
667
+ echo '.eael-social-feed-element .auth-img { display: block; }';
668
+ }else {
669
+ echo '.eael-social-feed-element .auth-img { display: none; }';
670
+ }
671
+ // Show Date
672
+ if( $settings['eael_twitter_feed_show_date'] == 'true' ) {
673
+ echo '.eael-social-feed-element .social-feed-date { display: block; }';
674
+ }else {
675
+ echo '.eael-social-feed-element .social-feed-date { display: none; }';
676
+ }
677
+ // Show Read More
678
+ if( $settings['eael_twitter_feed_show_read_more'] == 'true' ) {
679
+ echo '.eael-social-feed-element .read-more-link { display: block }';
680
+ }else {
681
+ echo '.eael-social-feed-element .read-more-link { display: none !important; }';
682
+ }
683
+ // Show Icon
684
+ if( $settings['eael_twitter_feed_show_icon'] == 'true' ) {
685
+ echo '.eael-social-feed-element .social-feed-icon { display: inline-block }';
686
+ }else {
687
+ echo '.eael-social-feed-element .social-feed-icon { display: none !important; }';
688
+ }
689
+
690
+ // Masonry Grid
691
+ if( $settings['eael_twitter_feed_type_col_type'] == 'col-2' ) {
692
+ $width = '50%';
693
+ }else if( $settings['eael_twitter_feed_type_col_type'] == 'col-3' ) {
694
+ $width = '33.33%';
695
+ }else if( $settings['eael_twitter_feed_type_col_type'] == 'col-4' ) {
696
+ $width = '25%';
697
+ echo '.eael-social-feed-element .social-feed-date { text-align: left; width: 100%; margin-bottom: 8px;}';
698
+ }
699
+ echo '.eael-twitter-feed-container.masonry-view .eael-social-feed-element { width: '.$width.'}
700
+ .eael-social-feed-element .media-object { width: 30px; }';
701
+
702
+ echo '</style>';
703
+ }
704
+
705
+ protected function content_template() {''
706
+
707
+ ?>
708
+
709
+
710
+ <?php
711
+ }
712
+ }
713
+
714
+
715
+ Plugin::instance()->widgets_manager->register_widget_type( new Widget_Eael_Twitter_Feed() );
essential_adons_elementor.php CHANGED
@@ -4,7 +4,7 @@
4
  * Description: The ultimate elements library for Elementor page builder plugin for WordPress.
5
  * Plugin URI: https://essential-addons.com/elementor/
6
  * Author: Codetic
7
- * Version: 2.3.0
8
  * Author URI: http://www.codetic.net
9
  *
10
  * Text Domain: essential-addons-elementor
@@ -23,7 +23,7 @@ require_once ESSENTIAL_ADDONS_EL_PATH.'admin/settings.php';
23
 
24
  function add_eael_elements(){
25
 
26
- $eael_default_keys = [ 'contact-form-7', 'count-down', 'creative-btn', 'fancy-text', 'img-comparison', 'instagram-gallery', 'interactive-promo', 'lightbox', 'post-block', 'post-grid', 'post-timeline', 'product-grid', 'team-members', 'testimonial-slider', 'testimonials', 'testimonials', 'weforms', 'static-product', 'call-to-action', 'flip-box', 'info-box', 'dual-header', 'price-table', 'flip-carousel', 'interactive-cards', 'ninja-form', 'gravity-form', 'caldera-form', 'wisdom_registered_setting' ];
27
  $eael_default_settings = array_fill_keys( $eael_default_keys, true );
28
 
29
  $is_component_active = get_option( 'eael_save_settings', $eael_default_settings );
@@ -89,6 +89,13 @@ function add_eael_elements(){
89
  if( class_exists( 'Caldera_Forms' ) && $is_component_active['caldera-form'] ) {
90
  require_once ESSENTIAL_ADDONS_EL_PATH.'elements/caldera-forms/caldera-forms.php';
91
  }
 
 
 
 
 
 
 
92
  }
93
  add_action('elementor/widgets/widgets_registered','add_eael_elements');
94
 
@@ -103,12 +110,20 @@ function essential_addons_el_enqueue(){
103
  if( $is_component_active['count-down'] ) {
104
  wp_enqueue_script('essential_addons_elementor-countdown-js',ESSENTIAL_ADDONS_EL_URL.'assets/js/countdown.min.js', array('jquery'),'1.0', true);
105
  }
106
- if( $is_component_active['post-grid'] ) {
107
  wp_enqueue_script('essential_addons_elementor-masonry-js',ESSENTIAL_ADDONS_EL_URL.'assets/js/masonry.min.js', array('jquery'),'1.0', true);
108
  }
109
  if( $is_component_active['post-grid'] || $is_component_active['post-timeline'] ) {
110
  wp_enqueue_script('essential_addons_elementor-load-more-js',ESSENTIAL_ADDONS_EL_URL.'assets/js/load-more.js', array('jquery'),'1.0', true);
111
  }
 
 
 
 
 
 
 
 
112
 
113
  }
114
  add_action( 'wp_enqueue_scripts', 'essential_addons_el_enqueue' );
@@ -127,7 +142,7 @@ add_action( 'elementor/editor/before_enqueue_scripts', function() {
127
 
128
  function eael_add_settings_link( $links ) {
129
  $settings_link = sprintf( '<a href="admin.php?page=eael-settings">' . __( 'Settings' ) . '</a>' );
130
- $go_pro_link = sprintf( '<a href="https://essential-addons.com/elementor/buy.php" target="_blank" style="color: #39b54a; font-weight: bold;">' . __( 'Go Pro' ) . '</a>' );
131
  array_push( $links, $settings_link, $go_pro_link );
132
  return $links;
133
  }
@@ -172,4 +187,34 @@ if( ! function_exists( 'essential_addons_elementor_lite_start_plugin_tracking' )
172
  );
173
  }
174
  essential_addons_elementor_lite_start_plugin_tracking();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
175
  }
4
  * Description: The ultimate elements library for Elementor page builder plugin for WordPress.
5
  * Plugin URI: https://essential-addons.com/elementor/
6
  * Author: Codetic
7
+ * Version: 2.3.1
8
  * Author URI: http://www.codetic.net
9
  *
10
  * Text Domain: essential-addons-elementor
23
 
24
  function add_eael_elements(){
25
 
26
+ $eael_default_keys = [ 'contact-form-7', 'count-down', 'creative-btn', 'fancy-text', 'img-comparison', 'instagram-gallery', 'interactive-promo', 'lightbox', 'post-block', 'post-grid', 'post-timeline', 'product-grid', 'team-members', 'testimonial-slider', 'testimonials', 'testimonials', 'weforms', 'static-product', 'call-to-action', 'flip-box', 'info-box', 'dual-header', 'price-table', 'flip-carousel', 'interactive-cards', 'ninja-form', 'gravity-form', 'caldera-form', 'wisdom_registered_setting', 'twitter-feed', 'facebook-feed' ];
27
  $eael_default_settings = array_fill_keys( $eael_default_keys, true );
28
 
29
  $is_component_active = get_option( 'eael_save_settings', $eael_default_settings );
89
  if( class_exists( 'Caldera_Forms' ) && $is_component_active['caldera-form'] ) {
90
  require_once ESSENTIAL_ADDONS_EL_PATH.'elements/caldera-forms/caldera-forms.php';
91
  }
92
+ if( $is_component_active['twitter-feed'] ) {
93
+ require_once ESSENTIAL_ADDONS_EL_PATH.'elements/twitter-feed/twitter-feed.php';
94
+ }
95
+
96
+ if( $is_component_active['facebook-feed'] ) {
97
+ require_once ESSENTIAL_ADDONS_EL_PATH.'elements/facebook-feed/facebook-feed.php';
98
+ }
99
  }
100
  add_action('elementor/widgets/widgets_registered','add_eael_elements');
101
 
110
  if( $is_component_active['count-down'] ) {
111
  wp_enqueue_script('essential_addons_elementor-countdown-js',ESSENTIAL_ADDONS_EL_URL.'assets/js/countdown.min.js', array('jquery'),'1.0', true);
112
  }
113
+ if( $is_component_active['post-grid'] || $is_component_active['twitter-feed'] || $is_component_active['facebook-feed'] ) {
114
  wp_enqueue_script('essential_addons_elementor-masonry-js',ESSENTIAL_ADDONS_EL_URL.'assets/js/masonry.min.js', array('jquery'),'1.0', true);
115
  }
116
  if( $is_component_active['post-grid'] || $is_component_active['post-timeline'] ) {
117
  wp_enqueue_script('essential_addons_elementor-load-more-js',ESSENTIAL_ADDONS_EL_URL.'assets/js/load-more.js', array('jquery'),'1.0', true);
118
  }
119
+ if( $is_component_active['twitter-feed']) {
120
+ wp_enqueue_script('essential_addons_elementor-codebird-js',ESSENTIAL_ADDONS_EL_URL.'assets/social-feeds/codebird.js', array('jquery'),'1.0', true);
121
+ }
122
+ if( $is_component_active['twitter-feed'] || $is_component_active['facebook-feed'] ) {
123
+ wp_enqueue_script('essential_addons_elementor-doT-js',ESSENTIAL_ADDONS_EL_URL.'assets/social-feeds/doT.min.js', array('jquery'),'1.0', true);
124
+ wp_enqueue_script('essential_addons_elementor-moment-js',ESSENTIAL_ADDONS_EL_URL.'assets/social-feeds/moment.js', array('jquery'),'1.0', true);
125
+ wp_enqueue_script('essential_addons_elementor-socialfeed-js',ESSENTIAL_ADDONS_EL_URL.'assets/social-feeds/jquery.socialfeed.js', array('jquery'),'1.0', true);
126
+ }
127
 
128
  }
129
  add_action( 'wp_enqueue_scripts', 'essential_addons_el_enqueue' );
142
 
143
  function eael_add_settings_link( $links ) {
144
  $settings_link = sprintf( '<a href="admin.php?page=eael-settings">' . __( 'Settings' ) . '</a>' );
145
+ $go_pro_link = sprintf( '<a href="https://wpdeveloper.net/in/upgrade-essential-addons-elementor" target="_blank" style="color: #39b54a; font-weight: bold;">' . __( 'Go Pro' ) . '</a>' );
146
  array_push( $links, $settings_link, $go_pro_link );
147
  return $links;
148
  }
187
  );
188
  }
189
  essential_addons_elementor_lite_start_plugin_tracking();
190
+ }
191
+
192
+ // admin notice
193
+
194
+ add_action('admin_notices', 'eael_admin_notice');
195
+
196
+ function eael_admin_notice() {
197
+ if ( current_user_can( 'install_plugins' ) )
198
+ {
199
+ global $current_user ;
200
+ $user_id = $current_user->ID;
201
+ /* Check that the user hasn't already clicked to ignore the message */
202
+ if ( ! get_user_meta($user_id, 'eael_ignore_notice231') ) {
203
+ echo '<div class="eael-admin-notice updated"><p>';
204
+ printf(__('We love to have you in our <strong>Essential Addons</strong> family. <span class="dashicons dashicons-heart" style="color: #f00;"></span> Show your love by leaving a review and encourage for more features. <a href="https://wpdeveloper.net/review-essential-addons-elementor" target="_blank" style="text-decoration: none;"><span class="dashicons dashicons-smiley"></span> Leave a Review</a>
205
+  <a href="%1$s" style="text-decoration: none; margin-left: 10px;"><span class="dashicons dashicons-dismiss"></span> No Thanks</a>'), admin_url( 'admin.php?page=eael-settings&eael_nag_ignore=0' ));
206
+ echo "</p></div>";
207
+ }
208
+ }
209
+ }
210
+
211
+ add_action('admin_init', 'eael_nag_ignore');
212
+
213
+ function eael_nag_ignore() {
214
+ global $current_user;
215
+ $user_id = $current_user->ID;
216
+ /* If user clicks to ignore the notice, add that to their user meta */
217
+ if ( isset($_GET['eael_nag_ignore']) && '0' == $_GET['eael_nag_ignore'] ) {
218
+ add_user_meta($user_id, 'eael_ignore_notice231', 'true', true);
219
+ }
220
  }
readme.txt CHANGED
@@ -3,7 +3,7 @@ Contributors: Codetic, re_enter_rupok, Asif2BD, robicse11128
3
  Tags: elementor, elements, addons, elementor addon, elementor widget, page builder, builder, visual editor, wordpress page builder
4
  Requires at least: 4.0
5
  Tested up to: 4.9.1
6
- Stable tag: 2.3.0
7
  License: GPLv3
8
  License URI: https://opensource.org/licenses/GPL-3.0
9
 
@@ -20,7 +20,7 @@ Ultimate elements library for Elementor WordPress Page Builder. Lots of useful
20
 
21
  ### Features
22
 
23
- * 18+ Stunning Elements (Free)
24
  * Fully Customizable
25
  * Unlimited Design Options
26
  * Elements Control option
@@ -47,6 +47,8 @@ Ultimate elements library for Elementor WordPress Page Builder. Lots of useful
47
  * [Dual Color Headline](https://essential-addons.com/elementor/dual-color-headline/)
48
  * [Call to Action](https://essential-addons.com/elementor/call-to-action/)
49
  * [Pricing Table](https://essential-addons.com/elementor/pricing-table/)
 
 
50
 
51
 
52
 
@@ -63,10 +65,18 @@ Ultimate elements library for Elementor WordPress Page Builder. Lots of useful
63
  * [Interactive Cards](https://essential-addons.com/elementor/interactive-cards/)
64
  * [Content Timeline](https://essential-addons.com/elementor/content-timeline/)
65
  * [Data Table](https://essential-addons.com/elementor/table/)
66
-
 
67
 
68
  More coming soon (weekly update) ...
69
 
 
 
 
 
 
 
 
70
  == Installation ==
71
 
72
  Note : This plugin works with Elementor. Make sure you have [Elementor](https://wordpress.org/plugins/elementor/) installed.
@@ -97,6 +107,12 @@ Your existing elements/content will work with premium version. So you won't lose
97
 
98
  == Changelog ==
99
 
 
 
 
 
 
 
100
  = 2.3.0 =
101
 
102
  - Caldera Forms element added
3
  Tags: elementor, elements, addons, elementor addon, elementor widget, page builder, builder, visual editor, wordpress page builder
4
  Requires at least: 4.0
5
  Tested up to: 4.9.1
6
+ Stable tag: 2.3.1
7
  License: GPLv3
8
  License URI: https://opensource.org/licenses/GPL-3.0
9
 
20
 
21
  ### Features
22
 
23
+ * 20+ Stunning Elements (Free)
24
  * Fully Customizable
25
  * Unlimited Design Options
26
  * Elements Control option
47
  * [Dual Color Headline](https://essential-addons.com/elementor/dual-color-headline/)
48
  * [Call to Action](https://essential-addons.com/elementor/call-to-action/)
49
  * [Pricing Table](https://essential-addons.com/elementor/pricing-table/)
50
+ * [Facebook Feed](https://essential-addons.com/elementor/facebook-feed/)
51
+ * [Twitter Feed](https://essential-addons.com/elementor/twitter-feed/)
52
 
53
 
54
 
65
  * [Interactive Cards](https://essential-addons.com/elementor/interactive-cards/)
66
  * [Content Timeline](https://essential-addons.com/elementor/content-timeline/)
67
  * [Data Table](https://essential-addons.com/elementor/table/)
68
+ * [Facebook Feed Carousel](https://essential-addons.com/elementor/facebook-feed/)
69
+ * [Twitter Feed Carousel](https://essential-addons.com/elementor/twitter-feed/)
70
 
71
  More coming soon (weekly update) ...
72
 
73
+
74
+ ### Looking for a companion theme?
75
+
76
+ Check [Flexia](https://wordpress.org/themes/flexia/), the best friend of Elementor and Essential Addons. A modern lightweight and versatile theme for WordPress with endless customization options.
77
+
78
+
79
+
80
  == Installation ==
81
 
82
  Note : This plugin works with Elementor. Make sure you have [Elementor](https://wordpress.org/plugins/elementor/) installed.
107
 
108
  == Changelog ==
109
 
110
+ = 2.3.1 =
111
+
112
+ - Facebook Feed element added
113
+ - Twitter Feed element added
114
+ - Few minor bug fixed and improvements
115
+
116
  = 2.3.0 =
117
 
118
  - Caldera Forms element added