Jetpack by WordPress.com - Version 2.4.5

Version Description

Release Date: May 26, 2016

  • Important security update. Please upgrade immediately.
Download this release

Release Info

Developer samhotchkiss
Plugin Icon 128x128 Jetpack by WordPress.com
Version 2.4.5
Comparing to
See all releases

Code changes from version 2.3.8 to 2.4.5

Files changed (140) hide show
  1. _inc/gallery-settings.js +1 -1
  2. _inc/images/module-icons-sprite-2x.png +0 -0
  3. _inc/images/module-icons-sprite.png +0 -0
  4. _inc/jetpack.css +27 -19
  5. class.jetpack-debugger.php +337 -336
  6. class.jetpack-heartbeat.php +3 -3
  7. class.jetpack-options.php +1 -0
  8. class.jetpack.php +89 -79
  9. class.json-api-endpoints.php +7 -0
  10. class.photon.php +1 -1
  11. functions.twitter-cards.php +67 -0
  12. jetpack.php +21 -4
  13. languages/jetpack-ar.mo +0 -0
  14. languages/jetpack-az.mo +0 -0
  15. languages/jetpack-bs_BA.mo +0 -0
  16. languages/jetpack-ca.mo +0 -0
  17. languages/jetpack-cs_CZ.mo +0 -0
  18. languages/jetpack-da_DK.mo +0 -0
  19. languages/jetpack-de_DE.mo +0 -0
  20. languages/jetpack-el.mo +0 -0
  21. languages/jetpack-es_ES.mo +0 -0
  22. languages/jetpack-fa_IR.mo +0 -0
  23. languages/jetpack-fi.mo +0 -0
  24. languages/jetpack-fr_FR.mo +0 -0
  25. languages/jetpack-gl_ES.mo +0 -0
  26. languages/jetpack-he_IL.mo +0 -0
  27. languages/jetpack-hr.mo +0 -0
  28. languages/jetpack-hu_HU.mo +0 -0
  29. languages/jetpack-id_ID.mo +0 -0
  30. languages/jetpack-it_IT.mo +0 -0
  31. languages/jetpack-ja.mo +0 -0
  32. languages/jetpack-ko_KR.mo +0 -0
  33. languages/jetpack-lt_LT.mo +0 -0
  34. languages/jetpack-mk_MK.mo +0 -0
  35. languages/jetpack-my_MM.mo +0 -0
  36. languages/jetpack-nb_NO.mo +0 -0
  37. languages/jetpack-nl_NL.mo +0 -0
  38. languages/jetpack-nn_NO.mo +0 -0
  39. languages/jetpack-pl_PL.mo +0 -0
  40. languages/jetpack-pt_BR.mo +0 -0
  41. languages/jetpack-pt_PT.mo +0 -0
  42. languages/jetpack-ro_RO.mo +0 -0
  43. languages/jetpack-ru_RU.mo +0 -0
  44. languages/jetpack-sa_IN.mo +0 -0
  45. languages/jetpack-sk_SK.mo +0 -0
  46. languages/jetpack-sq.mo +0 -0
  47. languages/jetpack-sr_RS.mo +0 -0
  48. languages/jetpack-sv_SE.mo +0 -0
  49. languages/jetpack-th.mo +0 -0
  50. languages/jetpack-tr_TR.mo +0 -0
  51. languages/jetpack-uk.mo +0 -0
  52. languages/jetpack-ur.mo +0 -0
  53. languages/jetpack-zh_CN.mo +0 -0
  54. languages/jetpack-zh_TW.mo +0 -0
  55. modules/after-the-deadline.php +1 -0
  56. modules/after-the-deadline/config-unignore.php +3 -0
  57. modules/carousel.php +1 -0
  58. modules/comments.php +1 -0
  59. modules/contact-form.php +1 -0
  60. modules/contact-form/admin.php +6 -1
  61. modules/contact-form/css/menu-alter.css +2 -2
  62. modules/contact-form/css/rtl/menu-alter-rtl.css +3 -3
  63. modules/contact-form/grunion-contact-form.php +1 -1
  64. modules/custom-css.php +1 -0
  65. modules/custom-css/custom-css.php +15 -4
  66. modules/custom-css/custom-css/css/css-editor.css +3 -0
  67. modules/custom-css/custom-css/preprocessors/lessc.inc.php +438 -123
  68. modules/custom-css/custom-css/preprocessors/scss.inc.php +829 -235
  69. modules/custom-post-types/comics.php +12 -12
  70. modules/custom-post-types/testimonial.php +3 -3
  71. modules/debug.php +6 -0
  72. modules/enhanced-distribution.php +1 -0
  73. modules/gravatar-hovercards.php +1 -0
  74. modules/holiday-snow.php +1 -0
  75. modules/infinite-scroll.php +1 -0
  76. modules/json-api.php +1 -0
  77. modules/latex.php +1 -0
  78. modules/likes.php +13 -12
  79. modules/likes/post-count-jetpack.js +18 -0
  80. modules/likes/post-count.js +4 -16
  81. modules/likes/style.css +1 -1
  82. modules/minileven.php +1 -0
  83. modules/minileven/theme/pub/minileven/functions.php +5 -5
  84. modules/minileven/theme/pub/minileven/style.css +7 -4
  85. modules/mobile-push.php +1 -0
  86. modules/module-extras.php +9 -50
  87. modules/module-info.php +41 -24
  88. modules/notes.php +1 -0
  89. modules/omnisearch.php +1 -0
  90. modules/omnisearch/omnisearch-core.php +5 -0
  91. modules/omnisearch/omnisearch-media.php +46 -0
  92. modules/omnisearch/omnisearch.css +16 -3
  93. modules/omnisearch/rtl/omnisearch-rtl.css +17 -4
  94. modules/photon.php +1 -0
  95. modules/post-by-email.php +1 -0
  96. modules/publicize.php +1 -0
  97. modules/publicize/assets/publicize.js +1 -1
  98. modules/publicize/assets/rtl/publicize-rtl.css +2 -1
  99. modules/publicize/ui.php +10 -6
  100. modules/random-redirect.php +43 -0
  101. modules/sharedaddy.php +1 -0
  102. modules/sharedaddy/images/facebook.png +0 -0
  103. modules/sharedaddy/images/facebook@2x.png +0 -0
  104. modules/sharedaddy/images/icon-facebook-2x.png +0 -0
  105. modules/sharedaddy/images/icon-facebook.png +0 -0
  106. modules/sharedaddy/sharing-service.php +1 -1
  107. modules/sharedaddy/sharing.php +2 -1
  108. modules/shortcodes.php +1 -0
  109. modules/shortcodes/css/rtl/slideshow-shortcode-rtl.css +2 -1
  110. modules/shortcodes/css/slideshow-shortcode.css +1 -0
  111. modules/shortcodes/css/style.css +140 -0
  112. modules/shortcodes/images/collapse.png +0 -0
  113. modules/shortcodes/images/expand.png +0 -0
  114. modules/shortcodes/images/slide-nav.png +0 -0
  115. modules/shortcodes/js/jmpress.js +2721 -0
  116. modules/shortcodes/js/jmpress.min.js +13 -0
  117. modules/shortcodes/js/main.js +197 -0
  118. modules/shortcodes/presentations.php +382 -0
  119. modules/shortcodes/twitter-timeline.php +31 -0
  120. modules/shortcodes/vine.php +65 -0
  121. modules/shortlinks.php +1 -0
  122. modules/stats.php +1 -0
  123. modules/subscriptions.php +32 -12
  124. modules/theme-tools.php +62 -0
  125. modules/tiled-gallery.php +1 -0
  126. modules/tiled-gallery/tiled-gallery.php +5 -0
  127. modules/vaultpress.php +1 -0
  128. modules/widget-visibility.php +11 -0
  129. modules/widget-visibility/widget-conditions.php +379 -0
  130. modules/widget-visibility/widget-conditions/rtl/widget-conditions-rtl.css +41 -0
  131. modules/widget-visibility/widget-conditions/widget-conditions.css +39 -0
  132. modules/widget-visibility/widget-conditions/widget-conditions.js +112 -0
  133. modules/widgets.php +1 -0
  134. modules/widgets/top-posts.php +1 -1
  135. modules/widgets/twitter-timeline.php +12 -3
  136. modules/wpcc.php +24 -0
  137. modules/wpcc/wpcc-sign-on.css +11 -0
  138. modules/wpcc/wpcc-sign-on.js +4 -0
  139. modules/wpcc/wpcc-sign-on.php +437 -0
  140. readme.txt +54 -6
_inc/gallery-settings.js CHANGED
@@ -29,4 +29,4 @@
29
  return this;
30
  }
31
  });
32
- })(jQuery);
29
  return this;
30
  }
31
  });
32
+ })(jQuery);
_inc/images/module-icons-sprite-2x.png CHANGED
Binary file
_inc/images/module-icons-sprite.png CHANGED
Binary file
_inc/jetpack.css CHANGED
@@ -30,17 +30,17 @@
30
  */
31
 
32
  /* Force the menu not to be sticky, so we can color the arrow. */
33
- .toplevel_page_jetpack.admin-color-mp6.sticky-menu #adminmenuwrap,
34
- body[class*=" jetpack_page_jetpack_"].admin-color-mp6.sticky-menu #adminmenuwrap {
35
  position: relative;
36
  z-index: auto;
37
  top: 0;
38
  }
39
 
40
- .toplevel_page_jetpack.admin-color-mp6 ul#adminmenu a.wp-has-current-submenu:after,
41
- .toplevel_page_jetpack.admin-color-mp6 ul#adminmenu > li.current > a.current:after,
42
- body[class*=" jetpack_page_jetpack_"].admin-color-mp6 ul#adminmenu a.wp-has-current-submenu:after,
43
- body[class*=" jetpack_page_jetpack_"].admin-color-mp6 ul#adminmenu > li.current > a.current:after {
44
  border-right-color:#8fad4b;
45
  }
46
 
@@ -49,8 +49,8 @@ body[class*=" jetpack_page_jetpack_"].jetpack-disconnected #wpwrap {
49
  background: url(images/header-clouds.png) -150px -60px repeat-x;
50
  }
51
 
52
- .toplevel_page_jetpack.jetpack-disconnected.admin-color-mp6 #wpwrap,
53
- body[class*=" jetpack_page_jetpack_"].jetpack-disconnected.admin-color-mp6 #wpwrap {
54
  background-position: -143px -60px;
55
  }
56
 
@@ -59,8 +59,8 @@ body[class*=" jetpack_page_jetpack_"].jetpack-disconnected.folded #wpwrap {
59
  background-position: -263px -60px;
60
  }
61
 
62
- .toplevel_page_jetpack.jetpack-disconnected.admin-color-mp6.folded #wpwrap,
63
- body[class*=" jetpack_page_jetpack_"].jetpack-disconnected.admin-color-mp6.folded #wpwrap {
64
  background-position: -257px -60px;
65
  }
66
 
@@ -69,8 +69,8 @@ body[class*=" jetpack_page_jetpack_"].jetpack-connected #wpwrap {
69
  background: url(images/header-clouds-small.png) 45px 0 repeat-x;
70
  }
71
 
72
- .toplevel_page_jetpack.jetpack-connected.admin-color-mp6 #wpwrap,
73
- body[class*=" jetpack_page_jetpack_"].jetpack-connected.admin-color-mp6 #wpwrap {
74
  background-position: 52px 0;
75
  }
76
 
@@ -79,8 +79,8 @@ body[class*=" jetpack_page_jetpack_"].jetpack-connected.folded #wpwrap {
79
  background-position: -68px 0;
80
  }
81
 
82
- .toplevel_page_jetpack.jetpack-connected.admin-color-mp6.folded #wpwrap,
83
- body[class*=" jetpack_page_jetpack_"].jetpack-connected.admin-color-mp6.folded #wpwrap {
84
  background-position: -62px 0;
85
  }
86
 
@@ -91,8 +91,8 @@ body[class*=" jetpack_page_jetpack_"].jetpack-connected.admin-color-mp6.folded #
91
  background-position: -263px -60px;
92
  }
93
 
94
- .toplevel_page_jetpack.jetpack-disconnected.admin-color-mp6.auto-fold #wpwrap,
95
- body[class*=" jetpack_page_jetpack_"].jetpack-disconnected.admin-color-mp6.auto-fold #wpwrap {
96
  background-position: -257px -60px;
97
  }
98
 
@@ -101,8 +101,8 @@ body[class*=" jetpack_page_jetpack_"].jetpack-connected.admin-color-mp6.folded #
101
  background-position: -68px 0;
102
  }
103
 
104
- .toplevel_page_jetpack.jetpack-connected.admin-color-mp6.auto-fold #wpwrap,
105
- body[class*=" jetpack_page_jetpack_"].jetpack-connected.admin-color-mp6.auto-fold #wpwrap {
106
  background-position: -62px 0;
107
  }
108
 
@@ -667,7 +667,7 @@ p.jp-help {
667
  border-bottom-left-radius: 3px;
668
  background-repeat: no-repeat;
669
  background-image: url(images/module-icons-sprite.png);
670
- background-size: 2705px 50px; /* remember to update this every time a new module is added! */
671
  }
672
 
673
  @media only screen and (-moz-min-device-pixel-ratio: 1.5),
@@ -789,6 +789,14 @@ p.jp-help {
789
  background-position: -2625px 5px;
790
  }
791
 
 
 
 
 
 
 
 
 
792
  .jetpack-module div.module-image p {
793
  background-color: #b4d278;
794
  color: #fff;
30
  */
31
 
32
  /* Force the menu not to be sticky, so we can color the arrow. */
33
+ .toplevel_page_jetpack.mp6.sticky-menu #adminmenuwrap,
34
+ body[class*=" jetpack_page_jetpack_"].mp6.sticky-menu #adminmenuwrap {
35
  position: relative;
36
  z-index: auto;
37
  top: 0;
38
  }
39
 
40
+ .toplevel_page_jetpack.mp6 ul#adminmenu a.wp-has-current-submenu:after,
41
+ .toplevel_page_jetpack.mp6 ul#adminmenu > li.current > a.current:after,
42
+ body[class*=" jetpack_page_jetpack_"].mp6 ul#adminmenu a.wp-has-current-submenu:after,
43
+ body[class*=" jetpack_page_jetpack_"].mp6 ul#adminmenu > li.current > a.current:after {
44
  border-right-color:#8fad4b;
45
  }
46
 
49
  background: url(images/header-clouds.png) -150px -60px repeat-x;
50
  }
51
 
52
+ .toplevel_page_jetpack.jetpack-disconnected.mp6 #wpwrap,
53
+ body[class*=" jetpack_page_jetpack_"].jetpack-disconnected.mp6 #wpwrap {
54
  background-position: -143px -60px;
55
  }
56
 
59
  background-position: -263px -60px;
60
  }
61
 
62
+ .toplevel_page_jetpack.jetpack-disconnected.mp6.folded #wpwrap,
63
+ body[class*=" jetpack_page_jetpack_"].jetpack-disconnected.mp6.folded #wpwrap {
64
  background-position: -257px -60px;
65
  }
66
 
69
  background: url(images/header-clouds-small.png) 45px 0 repeat-x;
70
  }
71
 
72
+ .toplevel_page_jetpack.jetpack-connected.mp6 #wpwrap,
73
+ body[class*=" jetpack_page_jetpack_"].jetpack-connected.mp6 #wpwrap {
74
  background-position: 52px 0;
75
  }
76
 
79
  background-position: -68px 0;
80
  }
81
 
82
+ .toplevel_page_jetpack.jetpack-connected.mp6.folded #wpwrap,
83
+ body[class*=" jetpack_page_jetpack_"].jetpack-connected.mp6.folded #wpwrap {
84
  background-position: -62px 0;
85
  }
86
 
91
  background-position: -263px -60px;
92
  }
93
 
94
+ .toplevel_page_jetpack.jetpack-disconnected.mp6.auto-fold #wpwrap,
95
+ body[class*=" jetpack_page_jetpack_"].jetpack-disconnected.mp6.auto-fold #wpwrap {
96
  background-position: -257px -60px;
97
  }
98
 
101
  background-position: -68px 0;
102
  }
103
 
104
+ .toplevel_page_jetpack.jetpack-connected.mp6.auto-fold #wpwrap,
105
+ body[class*=" jetpack_page_jetpack_"].jetpack-connected.mp6.auto-fold #wpwrap {
106
  background-position: -62px 0;
107
  }
108
 
667
  border-bottom-left-radius: 3px;
668
  background-repeat: no-repeat;
669
  background-image: url(images/module-icons-sprite.png);
670
+ background-size: 2885px 50px; /* remember to update this every time a new module is added! */
671
  }
672
 
673
  @media only screen and (-moz-min-device-pixel-ratio: 1.5),
789
  background-position: -2625px 5px;
790
  }
791
 
792
+ #wpcc.jetpack-module div.module-image {
793
+ background-position: -2710px 5px;
794
+ }
795
+
796
+ #widget-visibility.jetpack-module div.module-image {
797
+ background-position: -2800px 5px;
798
+ }
799
+
800
  .jetpack-module div.module-image p {
801
  background-color: #b4d278;
802
  color: #fff;
class.jetpack-debugger.php CHANGED
@@ -1,353 +1,354 @@
1
  <?php
2
 
3
- function is_jetpack_support_open() {
4
- try {
5
- $response = wp_remote_request( "http://jetpack.me/is-support-open" );
6
- $body = wp_remote_retrieve_body( $response );
7
- $json = json_decode( $body );
8
- return ( ( bool )$json->is_support_open );
9
- }
10
- catch ( Exception $e ) {
11
- return true;
12
- }
13
- }
14
-
15
- function jetpack_increase_timeout($time) {
16
- $time = 20; //seconds
17
- return $time;
18
- }
19
-
20
-
21
- function jetpack_debug_display_handler() {
22
- if ( ! current_user_can( 'manage_options' ) )
23
- wp_die( esc_html__('You do not have sufficient permissions to access this page.', 'jetpack' ) );
24
-
25
- global $current_user;
26
- get_currentuserinfo();
27
-
28
- $user_id = get_current_user_id();
29
- $user_tokens = Jetpack::get_option( 'user_tokens' );
30
- if ( is_array( $user_tokens ) && array_key_exists( $user_id, $user_tokens ) ) {
31
- $user_token = $user_tokens[$user_id];
32
- } else {
33
- $user_token = '[this user has no token]';
34
- }
35
- unset( $user_tokens );
36
 
37
- $debug_info = "\r\n";
38
- foreach ( array(
39
- 'CLIENT_ID' => 'id',
40
- 'BLOG_TOKEN' => 'blog_token',
41
- 'MASTER_USER' => 'master_user',
42
- 'CERT' => 'fallback_no_verify_ssl_certs',
43
- 'TIME_DIFF' => 'time_diff',
44
- 'VERSION' => 'version',
45
- 'OLD_VERSION' => 'old_version',
46
- 'PUBLIC' => 'public',
47
- ) as $label => $option_name ) {
48
- $debug_info .= "\r\n" . esc_html( $label . ": " . Jetpack::get_option( $option_name ) );
49
  }
50
 
51
- $debug_info .= "\r\n" . esc_html( "USER_ID: " . $user_id );
52
- $debug_info .= "\r\n" . esc_html( "USER_TOKEN: " . $user_token );
53
- $debug_info .= "\r\n" . esc_html( "PHP_VERSION: " . PHP_VERSION );
54
- $debug_info .= "\r\n" . esc_html( "WORDPRESS_VERSION: " . $GLOBALS['wp_version'] );
55
- $debug_info .= "\r\n" . esc_html( "JETPACK__VERSION: " . JETPACK__VERSION );
56
- $debug_info .= "\r\n" . esc_html( "JETPACK__PLUGIN_DIR: " . JETPACK__PLUGIN_DIR );
57
- $debug_info .= "\r\n" . esc_html( "SITE_URL: " . site_url() );
58
- $debug_info .= "\r\n" . esc_html( "HOME_URL: " . home_url() );
59
-
60
- $debug_info .= "\r\n\r\nTEST RESULTS:\r\n\r\n";
61
- $debug_raw_info = '';
62
-
63
-
64
- $tests = array();
65
-
66
- $tests['HTTP']['result'] = wp_remote_get( preg_replace( '/^https:/', 'http:', JETPACK__API_BASE ) . 'test/1/' );
67
- $tests['HTTP']['fail_message'] = esc_html__( 'Your site isn’t reaching the Jetpack servers.', 'jetpack' );
68
-
69
- $tests['HTTPS']['result'] = wp_remote_get( preg_replace( '/^http:/', 'https:', JETPACK__API_BASE ) . 'test/1/' );
70
- $tests['HTTPS']['fail_message'] = esc_html__( 'Your site isn’t securely reaching the Jetpack servers.', 'jetpack' );
71
-
72
-
73
- $self_xml_rpc_url = site_url( 'xmlrpc.php' );
74
 
75
- $args = array();
76
- $testsite_url = Jetpack::fix_url_for_bad_hosts( JETPACK__API_BASE . 'testsite/1/?url=', $args );
77
-
78
- add_filter( 'http_request_timeout', 'jetpack_increase_timeout' );
79
-
80
- $tests['SELF']['result'] = wp_remote_get( $testsite_url . $self_xml_rpc_url );
81
- $tests['SELF']['fail_message'] = esc_html__( 'It looks like your site can not communicate properly with Jetpack.', 'jetpack' );
82
 
83
- remove_filter( 'http_request_timeout', 'jetpack_increase_timeout' );
84
-
85
- ?>
86
- <div class="wrap">
87
- <h2><?php esc_html_e( 'Jetpack Debugging Center', 'jetpack' ); ?></h2>
88
- <h3><?php _e( "Testing your site's compatibily with Jetpack...", 'jetpack' ); ?></h3>
89
- <div class="jetpack-debug-test-container">
90
- <?php
91
- ob_start();
92
- foreach ( $tests as $test_name => $test_info ) :
93
- if ( is_wp_error( $test_info['result'] ) ||
94
- false == ( $response_code = wp_remote_retrieve_response_code( $test_info['result'] ) ) ||
95
- '200' != $response_code ) {
96
- $debug_info .= $test_name . ": FAIL\r\n";
97
- ?>
98
- <div class="jetpack-test-error">
99
- <p>
100
- <a class="jetpack-test-heading" href="#"><?php echo $test_info['fail_message']; ?>
101
- <span class="noticon noticon-collapse"></span>
102
- </a>
103
- </p>
104
- <pre class="jetpack-test-details"><?php esc_html_e( $test_name , 'jetpack'); ?>:
105
- <?php esc_html_e( is_wp_error( $test_info['result'] ) ? $test_info['result']->get_error_message() : print_r( $test_info['result'], 1 ) ); ?></pre>
106
- </div><?php
107
- } else {
108
- $debug_info .= $test_name . ": PASS\r\n";
109
- }
110
- $debug_raw_info .= "\r\n\r\n" . $test_name . "\r\n" . esc_html( print_r( $test_info['result'], 1 ) );
111
- ?>
112
- <?php endforeach;
113
- $html = ob_get_clean();
114
-
115
- if ( '' == trim( $html ) ) {
116
- echo '<div class="jetpack-tests-succed">' . esc_html__( 'Your Jetpack setup looks a-okay!', 'jetpack' ) . '</div>';
117
  }
118
- else {
119
- echo '<h3>' . esc_html__( 'There seems to be a problem with your site’s ability to communicate with Jetpack!', 'jetpack' ) . '</h3>';
120
- echo $html;
 
 
 
 
 
 
 
 
 
 
 
121
  }
122
- $debug_info .= "\r\n\r\nRAW TEST RESULTS:" . $debug_raw_info ."\r\n";
123
- ?>
124
- </div>
125
- <div class="entry-content">
126
- <h3><?php esc_html_e( 'Trouble with Jetpack?', 'jetpack' ); ?></h3>
127
- <h4><?php esc_html_e( 'It may be caused by one of these issues, which you can diagnose yourself:', 'jetpack' ); ?></h4>
128
- <ol>
129
- <li><b><em><?php esc_html_e( 'A known issue.', 'jetpack' ); ?></em></b> <?php echo sprintf( __( 'Some themes and plugins have <a href="%1$s" target="_blank">known conflicts</a> with Jetpack – check the <a href="%2$s" target="_blank">list</a>. (You can also browse the <a href="%3$s">Jetpack support pages</a> or <a href="%4$s">Jetpack support forum</a> to see if others have experienced and solved the problem.)', 'jetpack' ), 'http://jetpack.me/known-issues/', 'http://jetpack.me/known-issues/', 'http://jetpack.me/support/', 'http://wordpress.org/support/plugin/jetpack' ); ?></li>
130
- <li><b><em><?php esc_html_e( 'An incompatible plugin.', 'jetpack' ); ?></em></b> <?php esc_html_e( "Find out by disabling all plugins except Jetpack. If the problem persists, it's not a plugin issue. If the problem is solved, turn your plugins on one by one until the problem pops up again – there's the culprit! Let us know, and we'll try to help.", 'jetpack' ); ?></li>
131
- <li><b><em><?php esc_html_e( 'A theme conflict.', 'jetpack' ); ?></em></b> <?php esc_html_e( "If your problem isn't known or caused by a plugin, try activating Twenty Twelve (the default WordPress theme). If this solves the problem, something in your theme is probably broken – let the theme's author know.", 'jetpack' ); ?></li>
132
- <li><b><em><?php esc_html_e( 'A problem with your XMLRPC file.', 'jetpack' ); ?></em></b> <?php echo sprintf( __( 'Load your <a href="%s">XMLRPC file</a>. It should say “XML-RPC server accepts POST requests only.” on a line by itself.', 'jetpack' ), site_url( 'xmlrpc.php' ) ); ?>
133
- <ul>
134
- <li>- <?php esc_html_e( "If it's not by itself, a theme or plugin is displaying extra characters. Try steps 2 and 3.", 'jetpack' ); ?></li>
135
- <li>- <?php esc_html_e( "If you get a 404 message, contact your web host. Their security may block XMLRPC.", 'jetpack' ); ?></li>
136
- </ul>
137
- </li>
138
- </ol>
139
- <p class="jetpack-show-contact-form"><?php _e( 'If none of these help you find a solution, <a href="#">click here to contact Jetpack support</a>. Tell us as much as you can about the issue and what steps you\'ve tried to resolve it, and one of our Happiness Engineers will be in touch to help.', 'jetpack' ); ?>
140
- </p>
141
- </div>
142
- <div id="contact-message" style="display:none">
143
- <?php if ( is_jetpack_support_open() ): ?>
144
- <form id="contactme" method="post" action="http://jetpack.me/contact-support/">
145
- <input type="hidden" name="action" value="submit">
146
- <input type="hidden" name="jetpack" value="needs-service">
147
-
148
- <input type="hidden" name="contact_form" id="contact_form" value="1">
149
- <input type="hidden" name="blog_url" id="blog_url" value="<?php echo esc_attr( site_url() ); ?>">
150
- <input type="hidden" name="subject" id="subject" value="from: <?php echo esc_attr( site_url() ); ?> Jetpack contact form">
151
- <div class="formbox">
152
- <label for="message" class="h"><?php esc_html_e( 'Please describe the problem you are having.', 'jetpack' ); ?></label>
153
- <textarea name="message" cols="40" rows="7" id="did"></textarea>
154
- </div>
155
 
156
- <div id="name_div" class="formbox">
157
- <label class="h" for="your_name"><?php esc_html_e( 'Name', 'jetpack' ); ?></label>
158
- <span class="errormsg"><?php esc_html_e( 'Let us know your name.', 'jetpack' ); ?></span>
159
- <input name="your_name" type="text" id="your_name" value="<?php esc_html_e( $current_user->display_name , 'jetpack'); ?>" size="40">
160
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
161
 
162
- <div id="email_div" class="formbox">
163
- <label class="h" for="your_email"><?php esc_html_e( 'E-mail', 'jetpack' ); ?></label>
164
- <span class="errormsg"><?php esc_html_e( 'Use a valid email address.', 'jetpack' ); ?></span>
165
- <input name="your_email" type="text" id="your_email" value="<?php esc_html_e( $current_user->user_email , 'jetpack'); ?>" size="40">
166
- </div>
167
-
168
- <div id="toggle_debug_info" class="formbox">
169
- <p><?php _e( 'The test results and some other useful debug information will be sent to the support team. Please feel free to <a href="#">review/modify</a> this information.', 'jetpack' ); ?></p>
170
- </div>
171
-
172
- <div id="debug_info_div" class="formbox" style="display:none">
173
- <label class="h" for="debug_info"><?php esc_html_e( 'Debug Info', 'jetpack' ); ?></label>
174
- <textarea name="debug_info" cols="40" rows="7" id="debug_info"><?php echo esc_attr( $debug_info ); ?></textarea>
175
- </div>
176
-
177
- <div style="clear: both;"></div>
178
 
179
- <div id="blog_div" class="formbox">
180
- <div id="submit_div" class="contact-support">
181
- <input type="submit" name="submit" value="Contact Support">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
182
  </div>
183
- </div>
184
- <div style="clear: both;"></div>
185
- </form>
186
- <?php endif; ?>
187
  </div>
188
- </div>
189
- <?php
190
- }
191
-
192
- function jetpack_debug_admin_head() {
193
- ?>
194
- <style type="text/css">
195
-
196
- .jetpack-debug-test-container {
197
- margin-top: 20px;
198
- margin-bottom: 30px;
199
- }
200
-
201
- .jetpack-tests-succed {
202
- font-size: large;
203
- color: #8BAB3E;
204
- }
205
-
206
- .jetpack-test-details {
207
- margin: 4px 6px;
208
- padding: 10px;
209
- overflow: auto;
210
- display: none;
211
- }
212
-
213
- .jetpack-test-error {
214
- margin-bottom: 10px;
215
- background: #FFEBE8;
216
- border: solid 1px #C00;
217
- border-radius: 3px;
218
- }
219
-
220
- .jetpack-test-error p {
221
- margin: 0;
222
- padding: 0;
223
- }
224
-
225
- .jetpack-test-error a.jetpack-test-heading {
226
- padding: 4px 6px;
227
- display: block;
228
- text-decoration: none;
229
- color: inherit;
230
- }
231
-
232
- .jetpack-test-error .noticon {
233
- float: right;
234
- }
235
-
236
- form#contactme {
237
- border: 1px solid #dfdfdf;
238
- background: #eaf3fa;
239
- padding: 20px;
240
- margin: 10px;
241
- background-color: #eaf3fa;
242
- border-radius: 5px;
243
- font-size: 15px;
244
- font-family: "Open Sans", "Helvetica Neue", sans-serif;
245
- }
246
-
247
- form#contactme label.h {
248
- color: #444;
249
- display: block;
250
- font-weight: bold;
251
- margin: 0 0 7px 10px;
252
- text-shadow: 1px 1px 0 #fff;
253
- }
254
-
255
- .formbox {
256
- margin: 0 0 25px 0;
257
- }
258
-
259
- .formbox input[type="text"], .formbox input[type="email"], .formbox input[type="url"], .formbox textarea {
260
- border: 1px solid #e5e5e5;
261
- border-radius: 11px;
262
- box-shadow: inset 0 1px 1px rgba(0,0,0,0.1);
263
- color: #666;
264
- font-size: 14px;
265
- padding: 10px;
266
- width: 97%;
267
- }
268
- .formbox .contact-support input[type="submit"] {
269
- float: right;
270
- margin: 0 !important;
271
- border-radius: 20px !important;
272
- cursor: pointer;
273
- font-size: 13pt !important;
274
- height: auto !important;
275
- margin: 0 0 2em 10px !important;
276
- padding: 8px 16px !important;
277
- background-color: #ddd;
278
- border: 1px solid rgba(0,0,0,0.05);
279
- border-top-color: rgba(255,255,255,0.1);
280
- border-bottom-color: rgba(0,0,0,0.15);
281
- color: #333;
282
- font-weight: 400;
283
- display: inline-block;
284
- text-align: center;
285
- text-decoration: none;
286
- }
287
-
288
- .formbox span.errormsg {
289
- margin: 0 0 10px 10px;
290
- color: #d00;
291
- display: none;
292
- }
293
-
294
- .formbox.error span.errormsg {
295
- display: block;
296
- }
297
-
298
- #contact-message ul {
299
- margin: 0 0 20px 10px;
300
- }
301
-
302
- #contact-message li {
303
- margin: 0 0 10px 10px;
304
- list-style: disc;
305
- display: list-item;
306
- }
307
-
308
- </style>
309
- <script type="text/javascript">
310
- jQuery( document ).ready( function($) {
311
-
312
- $('#debug_info').prepend('jQuery version: ' + jQuery.fn.jquery + "\r\n");
313
-
314
- $( '.jetpack-test-error .jetpack-test-heading' ).on( 'click', function() {
315
- $( this ).parents( '.jetpack-test-error' ).find( '.jetpack-test-details' ).slideToggle();
316
- return false;
317
- } );
318
-
319
- $( '.jetpack-show-contact-form a' ).on( 'click', function() {
320
- $('#contact-message').slideToggle();
321
- return false;
322
- } );
323
-
324
- $( '#toggle_debug_info a' ).on( 'click', function() {
325
- $('#debug_info_div').slideToggle();
326
- return false;
327
- } );
328
-
329
- $('form#contactme').on("submit", function(e){
330
- var form = $(this);
331
- var message = form.find('#did');
332
- var name = form.find('#your_name');
333
- var email = form.find('#your_email')
334
- var validation_error = false;
335
- if( !name.val() ) {
336
- name.parents('.formbox').addClass('error');
337
- validation_error = true;
338
  }
339
- if( !email.val() ) {
340
- email.parents('.formbox').addClass('error');
341
- validation_error = true;
 
342
  }
343
- if ( validation_error ) {
344
- return false;
 
 
 
 
345
  }
346
- message.val(message.val() + "\r\n\r\n----------------------------------------------\r\n\r\nDEBUG INFO:\r\n" + $('#debug_info').val() );
347
- return true;
348
- });
349
-
350
- } );
351
- </script>
352
- <?php
353
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  <?php
2
 
3
+ class Jetpack_Debugger {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
 
5
+ private static function is_jetpack_support_open() {
6
+ try {
7
+ $response = wp_remote_request( "http://jetpack.me/is-support-open" );
8
+ $body = wp_remote_retrieve_body( $response );
9
+ $json = json_decode( $body );
10
+ return ( ( bool )$json->is_support_open );
11
+ }
12
+ catch ( Exception $e ) {
13
+ return true;
14
+ }
 
 
15
  }
16
 
17
+ public static function jetpack_increase_timeout($time) {
18
+ $time = 20; //seconds
19
+ return $time;
20
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
 
22
+ public static function jetpack_debug_display_handler() {
23
+ if ( ! current_user_can( 'manage_options' ) )
24
+ wp_die( esc_html__('You do not have sufficient permissions to access this page.', 'jetpack' ) );
 
 
 
 
25
 
26
+ global $current_user;
27
+ get_currentuserinfo();
28
+
29
+ $user_id = get_current_user_id();
30
+ $user_tokens = Jetpack::get_option( 'user_tokens' );
31
+ if ( is_array( $user_tokens ) && array_key_exists( $user_id, $user_tokens ) ) {
32
+ $user_token = $user_tokens[$user_id];
33
+ } else {
34
+ $user_token = '[this user has no token]';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
  }
36
+ unset( $user_tokens );
37
+
38
+ $debug_info = "\r\n";
39
+ foreach ( array(
40
+ 'CLIENT_ID' => 'id',
41
+ 'BLOG_TOKEN' => 'blog_token',
42
+ 'MASTER_USER' => 'master_user',
43
+ 'CERT' => 'fallback_no_verify_ssl_certs',
44
+ 'TIME_DIFF' => 'time_diff',
45
+ 'VERSION' => 'version',
46
+ 'OLD_VERSION' => 'old_version',
47
+ 'PUBLIC' => 'public',
48
+ ) as $label => $option_name ) {
49
+ $debug_info .= "\r\n" . esc_html( $label . ": " . Jetpack::get_option( $option_name ) );
50
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
 
52
+ $debug_info .= "\r\n" . esc_html( "USER_ID: " . $user_id );
53
+ $debug_info .= "\r\n" . esc_html( "USER_TOKEN: " . $user_token );
54
+ $debug_info .= "\r\n" . esc_html( "PHP_VERSION: " . PHP_VERSION );
55
+ $debug_info .= "\r\n" . esc_html( "WORDPRESS_VERSION: " . $GLOBALS['wp_version'] );
56
+ $debug_info .= "\r\n" . esc_html( "JETPACK__VERSION: " . JETPACK__VERSION );
57
+ $debug_info .= "\r\n" . esc_html( "JETPACK__PLUGIN_DIR: " . JETPACK__PLUGIN_DIR );
58
+ $debug_info .= "\r\n" . esc_html( "SITE_URL: " . site_url() );
59
+ $debug_info .= "\r\n" . esc_html( "HOME_URL: " . home_url() );
60
+
61
+ $debug_info .= "\r\n\r\nTEST RESULTS:\r\n\r\n";
62
+ $debug_raw_info = '';
63
+
64
+
65
+ $tests = array();
66
+
67
+ $tests['HTTP']['result'] = wp_remote_get( preg_replace( '/^https:/', 'http:', JETPACK__API_BASE ) . 'test/1/' );
68
+ $tests['HTTP']['fail_message'] = esc_html__( 'Your site isn’t reaching the Jetpack servers.', 'jetpack' );
69
+
70
+ $tests['HTTPS']['result'] = wp_remote_get( preg_replace( '/^http:/', 'https:', JETPACK__API_BASE ) . 'test/1/' );
71
+ $tests['HTTPS']['fail_message'] = esc_html__( 'Your site isn’t securely reaching the Jetpack servers.', 'jetpack' );
72
+
73
+ $self_xml_rpc_url = home_url( 'xmlrpc.php' );
74
 
75
+ $args = array();
76
+ $testsite_url = Jetpack::fix_url_for_bad_hosts( JETPACK__API_BASE . 'testsite/1/?url=', $args );
77
+
78
+ add_filter( 'http_request_timeout', array( 'Jetpack_Debugger', 'jetpack_increase_timeout' ) );
79
+
80
+ $tests['SELF']['result'] = wp_remote_get( $testsite_url . $self_xml_rpc_url );
81
+ $tests['SELF']['fail_message'] = esc_html__( 'It looks like your site can not communicate properly with Jetpack.', 'jetpack' );
 
 
 
 
 
 
 
 
 
82
 
83
+ remove_filter( 'http_request_timeout', array( 'Jetpack_Debugger', 'jetpack_increase_timeout' ) );
84
+
85
+ ?>
86
+ <div class="wrap">
87
+ <h2><?php esc_html_e( 'Jetpack Debugging Center', 'jetpack' ); ?></h2>
88
+ <h3><?php _e( "Testing your site's compatibily with Jetpack...", 'jetpack' ); ?></h3>
89
+ <div class="jetpack-debug-test-container">
90
+ <?php
91
+ ob_start();
92
+ foreach ( $tests as $test_name => $test_info ) :
93
+ if ( is_wp_error( $test_info['result'] ) ||
94
+ false == ( $response_code = wp_remote_retrieve_response_code( $test_info['result'] ) ) ||
95
+ '200' != $response_code ) {
96
+ $debug_info .= $test_name . ": FAIL\r\n";
97
+ ?>
98
+ <div class="jetpack-test-error">
99
+ <p>
100
+ <a class="jetpack-test-heading" href="#"><?php echo $test_info['fail_message']; ?>
101
+ <span class="noticon noticon-collapse"></span>
102
+ </a>
103
+ </p>
104
+ <pre class="jetpack-test-details"><?php esc_html_e( $test_name , 'jetpack'); ?>:
105
+ <?php esc_html_e( is_wp_error( $test_info['result'] ) ? $test_info['result']->get_error_message() : print_r( $test_info['result'], 1 ), 'jetpack' ); ?></pre>
106
+ </div><?php
107
+ } else {
108
+ $debug_info .= $test_name . ": PASS\r\n";
109
+ }
110
+ $debug_raw_info .= "\r\n\r\n" . $test_name . "\r\n" . esc_html( print_r( $test_info['result'], 1 ) );
111
+ ?>
112
+ <?php endforeach;
113
+ $html = ob_get_clean();
114
+
115
+ if ( '' == trim( $html ) ) {
116
+ echo '<div class="jetpack-tests-succed">' . esc_html__( 'Your Jetpack setup looks a-okay!', 'jetpack' ) . '</div>';
117
+ }
118
+ else {
119
+ echo '<h3>' . esc_html__( 'There seems to be a problem with your site’s ability to communicate with Jetpack!', 'jetpack' ) . '</h3>';
120
+ echo $html;
121
+ }
122
+ $debug_info .= "\r\n\r\nRAW TEST RESULTS:" . $debug_raw_info ."\r\n";
123
+ ?>
124
+ </div>
125
+ <div class="entry-content">
126
+ <h3><?php esc_html_e( 'Trouble with Jetpack?', 'jetpack' ); ?></h3>
127
+ <h4><?php esc_html_e( 'It may be caused by one of these issues, which you can diagnose yourself:', 'jetpack' ); ?></h4>
128
+ <ol>
129
+ <li><b><em><?php esc_html_e( 'A known issue.', 'jetpack' ); ?></em></b> <?php echo sprintf( __( 'Some themes and plugins have <a href="%1$s" target="_blank">known conflicts</a> with Jetpack – check the <a href="%2$s" target="_blank">list</a>. (You can also browse the <a href="%3$s">Jetpack support pages</a> or <a href="%4$s">Jetpack support forum</a> to see if others have experienced and solved the problem.)', 'jetpack' ), 'http://jetpack.me/known-issues/', 'http://jetpack.me/known-issues/', 'http://jetpack.me/support/', 'http://wordpress.org/support/plugin/jetpack' ); ?></li>
130
+ <li><b><em><?php esc_html_e( 'An incompatible plugin.', 'jetpack' ); ?></em></b> <?php esc_html_e( "Find out by disabling all plugins except Jetpack. If the problem persists, it's not a plugin issue. If the problem is solved, turn your plugins on one by one until the problem pops up again – there's the culprit! Let us know, and we'll try to help.", 'jetpack' ); ?></li>
131
+ <li><b><em><?php esc_html_e( 'A theme conflict.', 'jetpack' ); ?></em></b> <?php esc_html_e( "If your problem isn't known or caused by a plugin, try activating Twenty Twelve (the default WordPress theme). If this solves the problem, something in your theme is probably broken – let the theme's author know.", 'jetpack' ); ?></li>
132
+ <li><b><em><?php esc_html_e( 'A problem with your XMLRPC file.', 'jetpack' ); ?></em></b> <?php echo sprintf( __( 'Load your <a href="%s">XMLRPC file</a>. It should say “XML-RPC server accepts POST requests only.” on a line by itself.', 'jetpack' ), site_url( 'xmlrpc.php' ) ); ?>
133
+ <ul>
134
+ <li>- <?php esc_html_e( "If it's not by itself, a theme or plugin is displaying extra characters. Try steps 2 and 3.", 'jetpack' ); ?></li>
135
+ <li>- <?php esc_html_e( "If you get a 404 message, contact your web host. Their security may block XMLRPC.", 'jetpack' ); ?></li>
136
+ </ul>
137
+ </li>
138
+ </ol>
139
+ <p class="jetpack-show-contact-form"><?php _e( 'If none of these help you find a solution, <a href="#">click here to contact Jetpack support</a>. Tell us as much as you can about the issue and what steps you\'ve tried to resolve it, and one of our Happiness Engineers will be in touch to help.', 'jetpack' ); ?>
140
+ </p>
141
+ </div>
142
+ <div id="contact-message" style="display:none">
143
+ <?php if ( self::is_jetpack_support_open() ): ?>
144
+ <form id="contactme" method="post" action="http://jetpack.me/contact-support/">
145
+ <input type="hidden" name="action" value="submit">
146
+ <input type="hidden" name="jetpack" value="needs-service">
147
+
148
+ <input type="hidden" name="contact_form" id="contact_form" value="1">
149
+ <input type="hidden" name="blog_url" id="blog_url" value="<?php echo esc_attr( site_url() ); ?>">
150
+ <input type="hidden" name="subject" id="subject" value="from: <?php echo esc_attr( site_url() ); ?> Jetpack contact form">
151
+ <div class="formbox">
152
+ <label for="message" class="h"><?php esc_html_e( 'Please describe the problem you are having.', 'jetpack' ); ?></label>
153
+ <textarea name="message" cols="40" rows="7" id="did"></textarea>
154
+ </div>
155
+
156
+ <div id="name_div" class="formbox">
157
+ <label class="h" for="your_name"><?php esc_html_e( 'Name', 'jetpack' ); ?></label>
158
+ <span class="errormsg"><?php esc_html_e( 'Let us know your name.', 'jetpack' ); ?></span>
159
+ <input name="your_name" type="text" id="your_name" value="<?php esc_html_e( $current_user->display_name , 'jetpack'); ?>" size="40">
160
+ </div>
161
+
162
+ <div id="email_div" class="formbox">
163
+ <label class="h" for="your_email"><?php esc_html_e( 'E-mail', 'jetpack' ); ?></label>
164
+ <span class="errormsg"><?php esc_html_e( 'Use a valid email address.', 'jetpack' ); ?></span>
165
+ <input name="your_email" type="text" id="your_email" value="<?php esc_html_e( $current_user->user_email , 'jetpack'); ?>" size="40">
166
+ </div>
167
+
168
+ <div id="toggle_debug_info" class="formbox">
169
+ <p><?php _e( 'The test results and some other useful debug information will be sent to the support team. Please feel free to <a href="#">review/modify</a> this information.', 'jetpack' ); ?></p>
170
+ </div>
171
+
172
+ <div id="debug_info_div" class="formbox" style="display:none">
173
+ <label class="h" for="debug_info"><?php esc_html_e( 'Debug Info', 'jetpack' ); ?></label>
174
+ <textarea name="debug_info" cols="40" rows="7" id="debug_info"><?php echo esc_attr( $debug_info ); ?></textarea>
175
+ </div>
176
+
177
+ <div style="clear: both;"></div>
178
+
179
+ <div id="blog_div" class="formbox">
180
+ <div id="submit_div" class="contact-support">
181
+ <input type="submit" name="submit" value="Contact Support">
182
+ </div>
183
  </div>
184
+ <div style="clear: both;"></div>
185
+ </form>
186
+ <?php endif; ?>
187
+ </div>
188
  </div>
189
+ <?php
190
+ }
191
+
192
+ public static function jetpack_debug_admin_head() {
193
+ ?>
194
+ <style type="text/css">
195
+
196
+ .jetpack-debug-test-container {
197
+ margin-top: 20px;
198
+ margin-bottom: 30px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
199
  }
200
+
201
+ .jetpack-tests-succed {
202
+ font-size: large;
203
+ color: #8BAB3E;
204
  }
205
+
206
+ .jetpack-test-details {
207
+ margin: 4px 6px;
208
+ padding: 10px;
209
+ overflow: auto;
210
+ display: none;
211
  }
212
+
213
+ .jetpack-test-error {
214
+ margin-bottom: 10px;
215
+ background: #FFEBE8;
216
+ border: solid 1px #C00;
217
+ border-radius: 3px;
218
+ }
219
+
220
+ .jetpack-test-error p {
221
+ margin: 0;
222
+ padding: 0;
223
+ }
224
+
225
+ .jetpack-test-error a.jetpack-test-heading {
226
+ padding: 4px 6px;
227
+ display: block;
228
+ text-decoration: none;
229
+ color: inherit;
230
+ }
231
+
232
+ .jetpack-test-error .noticon {
233
+ float: right;
234
+ }
235
+
236
+ form#contactme {
237
+ border: 1px solid #dfdfdf;
238
+ background: #eaf3fa;
239
+ padding: 20px;
240
+ margin: 10px;
241
+ background-color: #eaf3fa;
242
+ border-radius: 5px;
243
+ font-size: 15px;
244
+ font-family: "Open Sans", "Helvetica Neue", sans-serif;
245
+ }
246
+
247
+ form#contactme label.h {
248
+ color: #444;
249
+ display: block;
250
+ font-weight: bold;
251
+ margin: 0 0 7px 10px;
252
+ text-shadow: 1px 1px 0 #fff;
253
+ }
254
+
255
+ .formbox {
256
+ margin: 0 0 25px 0;
257
+ }
258
+
259
+ .formbox input[type="text"], .formbox input[type="email"], .formbox input[type="url"], .formbox textarea {
260
+ border: 1px solid #e5e5e5;
261
+ border-radius: 11px;
262
+ box-shadow: inset 0 1px 1px rgba(0,0,0,0.1);
263
+ color: #666;
264
+ font-size: 14px;
265
+ padding: 10px;
266
+ width: 97%;
267
+ }
268
+ .formbox .contact-support input[type="submit"] {
269
+ float: right;
270
+ margin: 0 !important;
271
+ border-radius: 20px !important;
272
+ cursor: pointer;
273
+ font-size: 13pt !important;
274
+ height: auto !important;
275
+ margin: 0 0 2em 10px !important;
276
+ padding: 8px 16px !important;
277
+ background-color: #ddd;
278
+ border: 1px solid rgba(0,0,0,0.05);
279
+ border-top-color: rgba(255,255,255,0.1);
280
+ border-bottom-color: rgba(0,0,0,0.15);
281
+ color: #333;
282
+ font-weight: 400;
283
+ display: inline-block;
284
+ text-align: center;
285
+ text-decoration: none;
286
+ }
287
+
288
+ .formbox span.errormsg {
289
+ margin: 0 0 10px 10px;
290
+ color: #d00;
291
+ display: none;
292
+ }
293
+
294
+ .formbox.error span.errormsg {
295
+ display: block;
296
+ }
297
+
298
+ #contact-message ul {
299
+ margin: 0 0 20px 10px;
300
+ }
301
+
302
+ #contact-message li {
303
+ margin: 0 0 10px 10px;
304
+ list-style: disc;
305
+ display: list-item;
306
+ }
307
+
308
+ </style>
309
+ <script type="text/javascript">
310
+ jQuery( document ).ready( function($) {
311
+
312
+ $('#debug_info').prepend('jQuery version: ' + jQuery.fn.jquery + "\r\n");
313
+
314
+ $( '.jetpack-test-error .jetpack-test-heading' ).on( 'click', function() {
315
+ $( this ).parents( '.jetpack-test-error' ).find( '.jetpack-test-details' ).slideToggle();
316
+ return false;
317
+ } );
318
+
319
+ $( '.jetpack-show-contact-form a' ).on( 'click', function() {
320
+ $('#contact-message').slideToggle();
321
+ return false;
322
+ } );
323
+
324
+ $( '#toggle_debug_info a' ).on( 'click', function() {
325
+ $('#debug_info_div').slideToggle();
326
+ return false;
327
+ } );
328
+
329
+ $('form#contactme').on("submit", function(e){
330
+ var form = $(this);
331
+ var message = form.find('#did');
332
+ var name = form.find('#your_name');
333
+ var email = form.find('#your_email')
334
+ var validation_error = false;
335
+ if( !name.val() ) {
336
+ name.parents('.formbox').addClass('error');
337
+ validation_error = true;
338
+ }
339
+ if( !email.val() ) {
340
+ email.parents('.formbox').addClass('error');
341
+ validation_error = true;
342
+ }
343
+ if ( validation_error ) {
344
+ return false;
345
+ }
346
+ message.val(message.val() + "\r\n\r\n----------------------------------------------\r\n\r\nDEBUG INFO:\r\n" + $('#debug_info').val() );
347
+ return true;
348
+ });
349
+
350
+ } );
351
+ </script>
352
+ <?php
353
+ }
354
+ }
class.jetpack-heartbeat.php CHANGED
@@ -73,7 +73,7 @@ class Jetpack_Heartbeat {
73
 
74
  $jetpack = Jetpack::init();
75
 
76
- $jetpack->stat( 'active-modules', implode( ',', $this->jetpack->get_active_modules() ) );
77
  $jetpack->stat( 'active', JETPACK__VERSION );
78
  $jetpack->stat( 'wp-version', get_bloginfo( 'version' ) );
79
  $jetpack->stat( 'php-version', PHP_VERSION );
@@ -108,14 +108,14 @@ class Jetpack_Heartbeat {
108
  public function add_cron_intervals( $schedules ) {
109
  $schedules['jetpack_weekly'] = array(
110
  'interval' => WEEK_IN_SECONDS,
111
- 'display' => __('Jetpack weekly')
112
  );
113
  return $schedules;
114
  }
115
 
116
  public function deactivate() {
117
  $timestamp = wp_next_scheduled( $this->cron_name );
118
- wp_unschedule_event($timestamp, $this->cron_name );
119
  }
120
 
121
  }
73
 
74
  $jetpack = Jetpack::init();
75
 
76
+ $jetpack->stat( 'active-modules', implode( ',', $jetpack->get_active_modules() ) );
77
  $jetpack->stat( 'active', JETPACK__VERSION );
78
  $jetpack->stat( 'wp-version', get_bloginfo( 'version' ) );
79
  $jetpack->stat( 'php-version', PHP_VERSION );
108
  public function add_cron_intervals( $schedules ) {
109
  $schedules['jetpack_weekly'] = array(
110
  'interval' => WEEK_IN_SECONDS,
111
+ 'display' => __( 'Jetpack weekly', 'jetpack' ),
112
  );
113
  return $schedules;
114
  }
115
 
116
  public function deactivate() {
117
  $timestamp = wp_next_scheduled( $this->cron_name );
118
+ wp_unschedule_event( $timestamp, $this->cron_name );
119
  }
120
 
121
  }
class.jetpack-options.php CHANGED
@@ -13,6 +13,7 @@ class Jetpack_Options {
13
  'do_activate',
14
  'publicize',
15
  'widget_twitter',
 
16
  );
17
  }
18
 
13
  'do_activate',
14
  'publicize',
15
  'widget_twitter',
16
+ 'wpcc_options',
17
  );
18
  }
19
 
class.jetpack.php CHANGED
@@ -37,6 +37,7 @@ class Jetpack {
37
  'after-the-deadline' => array( 'after-the-deadline/after-the-deadline.php', 'After The Deadline' ),
38
  'contact-form' => array( 'grunion-contact-form/grunion-contact-form.php', 'Grunion Contact Form' ),
39
  'custom-css' => array( 'safecss/safecss.php', 'WordPress.com Custom CSS' ),
 
40
  );
41
 
42
  var $capability_translations = array(
@@ -85,7 +86,7 @@ class Jetpack {
85
  /**
86
  * Holds the singleton instance of this class
87
  * @since 2.3.3
88
- * @var Jetpack
89
  */
90
  static $instance = false;
91
 
@@ -162,7 +163,7 @@ class Jetpack {
162
 
163
  // Modules should do Jetpack_Sync::sync_options( __FILE__, $option, ... ); instead
164
  // We access the "internal" method here only because the Jetpack object isn't instantiated yet
165
- $this->sync->options( __FILE__,
166
  'home',
167
  'siteurl',
168
  'blogname',
@@ -173,7 +174,7 @@ class Jetpack {
173
  if ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST && isset( $_GET['for'] ) && 'jetpack' == $_GET['for'] ) {
174
  @ini_set( 'display_errors', false ); // Display errors can cause the XML to be not well formed.
175
 
176
- require_once dirname( __FILE__ ) . '/class.jetpack-xmlrpc-server.php';
177
  $this->xmlrpc_server = new Jetpack_XMLRPC_Server();
178
 
179
  $this->require_jetpack_authentication();
@@ -448,7 +449,7 @@ class Jetpack {
448
  do_action( 'jetpack_modules_loaded' );
449
 
450
  // Load module-specific code that is needed even when a module isn't active. Loaded here because code contained therein may need actions such as setup_theme.
451
- require_once( dirname( __FILE__ ) . '/modules/module-extras.php' );
452
  }
453
 
454
  /**
@@ -460,7 +461,7 @@ class Jetpack {
460
  $_jetpack_rest_api_compat_includes = apply_filters( 'jetpack_rest_api_compat', array() );
461
 
462
  if ( function_exists( 'bbpress' ) )
463
- $_jetpack_rest_api_compat_includes[] = dirname( __FILE__ ) . '/class.jetpack-bbpress-json-api-compat.php';
464
 
465
  foreach ( $_jetpack_rest_api_compat_includes as $_jetpack_rest_api_compat_include )
466
  require_once $_jetpack_rest_api_compat_include;
@@ -490,28 +491,35 @@ class Jetpack {
490
  }
491
 
492
  $conflicting_plugins = array(
493
- 'facebook/facebook.php', // Official Facebook plugin
494
- 'wordpress-seo/wp-seo.php', // WordPress SEO by Yoast
495
- 'add-link-to-facebook/add-link-to-facebook.php', // Add Link to Facebook
496
- 'facebook-awd/AWD_facebook.php', // Facebook AWD All in one
497
- 'header-footer/plugin.php', // Header and Footer
498
- 'nextgen-facebook/nextgen-facebook.php', // NextGEN Facebook OG
499
- 'seo-facebook-comments/seofacebook.php', // SEO Facebook Comments
500
- 'seo-ultimate/seo-ultimate.php', // SEO Ultimate
501
- 'sexybookmarks/sexy-bookmarks.php', // Shareaholic
502
- 'shareaholic/sexy-bookmarks.php', // Shareaholic
503
- 'social-discussions/social-discussions.php', // Social Discussions
504
- 'social-networks-auto-poster-facebook-twitter-g/NextScripts_SNAP.php', // NextScripts SNAP
505
- 'wordbooker/wordbooker.php', // Wordbooker
506
- 'socialize/socialize.php', // Socialize
507
- 'simple-facebook-connect/sfc.php', // Simple Facebook Connect
508
- 'social-sharing-toolkit/social_sharing_toolkit.php', // Social Sharing Toolkit
509
- 'wp-facebook-open-graph-protocol/wp-facebook-ogp.php', // WP Facebook Open Graph protocol
510
- 'opengraph/opengraph.php', // Open Graph
511
- 'sharepress/sharepress.php', // SharePress
512
- 'wp-facebook-like-send-open-graph-meta/wp-facebook-like-send-open-graph-meta.php', // WP Facebook Like Send & Open Graph Meta
513
- 'network-publisher/networkpub.php', // Network Publisher
514
- 'wp-ogp/wp-ogp.php', // WP-OGP
 
 
 
 
 
 
 
515
  );
516
 
517
  foreach ( $conflicting_plugins as $plugin ) {
@@ -522,7 +530,7 @@ class Jetpack {
522
  }
523
 
524
  if ( apply_filters( 'jetpack_enable_open_graph', false ) )
525
- require_once dirname( __FILE__ ) . '/functions.opengraph.php';
526
  }
527
 
528
  /* Jetpack Options API */
@@ -701,7 +709,7 @@ class Jetpack {
701
  static $modules = null;
702
 
703
  if ( !isset( $modules ) ) {
704
- $files = Jetpack::glob_php( dirname( __FILE__ ) . '/modules' );
705
 
706
  $modules = array();
707
 
@@ -714,6 +722,8 @@ class Jetpack {
714
  }
715
  }
716
 
 
 
717
  if ( !$min_version && !$max_version ) {
718
  return array_keys( $modules );
719
  }
@@ -741,33 +751,25 @@ class Jetpack {
741
  $return = array();
742
 
743
  foreach ( Jetpack::get_available_modules( $min_version, $max_version ) as $module ) {
744
- // Add special cases here for modules to avoid auto-activation
745
- switch ( $module ) {
746
-
747
- // These modules are default off: they change things blog-side
748
- case 'comments' :
749
- case 'carousel' :
750
- case 'minileven':
751
- case 'infinite-scroll' :
752
- case 'photon' :
753
- case 'tiled-gallery' :
754
- case 'likes' :
755
- break;
756
 
757
- // These modules are default off if we think the site is a private one
758
- case 'enhanced-distribution' :
759
- case 'json-api' :
760
- if ( !Jetpack::get_option( 'public' ) ) {
 
 
 
 
 
 
 
761
  break;
762
- }
763
- // else no break
764
- // The rest are default on
765
- default :
766
- $return[] = $module;
767
  }
 
768
  }
769
 
770
- return $return;
771
  }
772
 
773
  /**
@@ -781,7 +783,7 @@ class Jetpack {
781
  * Generate a module's path from its slug.
782
  */
783
  public static function get_module_path( $slug ) {
784
- return dirname( __FILE__ ) . "/modules/$slug.php";
785
  }
786
 
787
  /**
@@ -799,6 +801,7 @@ class Jetpack {
799
  'deactivate' => 'Deactivate',
800
  'free' => 'Free',
801
  'requires_connection' => 'Requires Connection',
 
802
  );
803
 
804
  $file = Jetpack::get_module_path( Jetpack::get_module_slug( $module ) );
@@ -816,6 +819,13 @@ class Jetpack {
816
  $mod['deactivate'] = empty( $mod['deactivate'] );
817
  $mod['free'] = empty( $mod['free'] );
818
  $mod['requires_connection'] = ( ! empty( $mod['requires_connection'] ) && 'No' == $mod['requires_connection'] ) ? false : true;
 
 
 
 
 
 
 
819
  return $mod;
820
  }
821
 
@@ -988,7 +998,7 @@ class Jetpack {
988
 
989
  $module_data = Jetpack::get_module( $module );
990
 
991
- if ( ! Jetpack::is_active() ) {
992
  if ( ! Jetpack::is_development_mode() )
993
  return false;
994
 
@@ -1101,7 +1111,7 @@ p {
1101
  <?php
1102
  if ( $deactivate ) {
1103
  $plugins = get_option( 'active_plugins' );
1104
- $jetpack = plugin_basename( __FILE__ );
1105
  $update = false;
1106
  foreach ( $plugins as $i => $plugin ) {
1107
  if ( $plugin === $jetpack ) {
@@ -1273,7 +1283,7 @@ p {
1273
 
1274
  add_action( 'load-plugins.php', array( $this, 'intercept_plugin_error_scrape_init' ) );
1275
  add_action( 'admin_head', array( $this, 'admin_menu_css' ) );
1276
- add_filter( 'plugin_action_links_' . plugin_basename( __FILE__ ), array( $this, 'plugin_action_links' ) );
1277
 
1278
  if ( Jetpack::is_active() || Jetpack::is_development_mode() ) {
1279
  // Artificially throw errors in certain whitelisted cases during plugin activation
@@ -1372,10 +1382,9 @@ p {
1372
  }
1373
 
1374
  $hook = add_menu_page( 'Jetpack', $title, 'read', 'jetpack', array( $this, 'admin_page' ), 'div' );
1375
-
1376
- $debugger_hook = add_submenu_page( 'jetpack', 'Jetpack Debugging Center', '', 'manage_options', 'jetpack-debugger', array( $this, 'debugger_page' ) );
1377
- add_action( "admin_head-$debugger_hook", 'jetpack_debug_admin_head' );
1378
 
 
 
1379
 
1380
  add_action( "load-$hook", array( $this, 'admin_page_load' ) );
1381
 
@@ -1404,7 +1413,7 @@ p {
1404
  add_action( "load-$hook", array( $this, 'admin_help' ) );
1405
  add_action( "admin_head-$hook", array( $this, 'admin_head' ) );
1406
  add_action( "admin_print_styles-$hook", array( $this, 'admin_styles' ) );
1407
- add_action( "admin_print_scripts-$hook", array( $this, 'admin_scripts' ) );
1408
  }
1409
  /**/
1410
  function add_remote_request_handlers() {
@@ -1585,7 +1594,7 @@ p {
1585
  '<p><strong>' . __( 'For more information:', 'jetpack' ) . '</strong></p>' .
1586
  '<p><a href="http://jetpack.me/faq/" target="_blank">' . __( 'Jetpack FAQ', 'jetpack' ) . '</a></p>' .
1587
  '<p><a href="http://jetpack.me/support/" target="_blank">' . __( 'Jetpack Support', 'jetpack' ) . '</a></p>' .
1588
- '<p><a href="' . Jetpack::admin_url( array( 'page' => 'jetpack-debugger' ) ) .'">' . __( 'Jetpack Debugging Center', 'jetpack' ) . '</a></p>'
1589
 
1590
  );
1591
  }
@@ -1593,12 +1602,12 @@ p {
1593
  function admin_menu_css() { ?>
1594
  <style type="text/css" id="jetpack-menu-css">
1595
  #toplevel_page_jetpack .wp-menu-image {
1596
- background: url( <?php echo plugins_url( basename( dirname( __FILE__ ) ) . '/_inc/images/menuicon-sprite.png' ) ?> ) 0 90% no-repeat;
1597
  }
1598
  /* Retina Jetpack Menu Icon */
1599
  @media only screen and (-moz-min-device-pixel-ratio: 1.5), only screen and (-o-min-device-pixel-ratio: 3/2), only screen and (-webkit-min-device-pixel-ratio: 1.5), only screen and (min-device-pixel-ratio: 1.5) {
1600
  #toplevel_page_jetpack .wp-menu-image {
1601
- background: url( <?php echo plugins_url( basename( dirname( __FILE__ ) ) . '/_inc/images/menuicon-sprite-2x.png' ) ?> ) 0 90% no-repeat;
1602
  background-size:30px 64px;
1603
  }
1604
  }
@@ -1635,12 +1644,12 @@ p {
1635
 
1636
  function admin_styles() {
1637
  global $wp_styles;
1638
- wp_enqueue_style( 'jetpack', plugins_url( basename( dirname( __FILE__ ) ) . '/_inc/jetpack.css' ), false, JETPACK__VERSION . '-20121016' );
1639
  $wp_styles->add_data( 'jetpack', 'rtl', true );
1640
  }
1641
 
1642
  function admin_scripts() {
1643
- wp_enqueue_script( 'jetpack-js', plugins_url( basename( dirname( __FILE__ ) ) ) . '/_inc/jetpack.js', array( 'jquery' ), JETPACK__VERSION . '-20121111' );
1644
  wp_localize_script( 'jetpack-js', 'jetpackL10n', array(
1645
  'ays_disconnect' => "This will deactivate all Jetpack modules.\nAre you sure you want to disconnect?",
1646
  'ays_unlink' => "This will prevent user-specific modules such as Publicize, Notifications and Post By Email from working.\nAre you sure you want to unlink?",
@@ -1666,7 +1675,7 @@ p {
1666
  return;
1667
  ?>
1668
 
1669
- <div id="message" class="updated jetpack-message jp-connect">
1670
  <div id="jp-dismiss" class="jetpack-close-button-container">
1671
  <a class="jetpack-close-button" href="?page=jetpack&jetpack-notice=dismiss" title="<?php _e( 'Dismiss this notice and deactivate Jetpack.', 'jetpack' ); ?>"><?php _e( 'Dismiss this notice and deactivate Jetpack.', 'jetpack' ); ?></a>
1672
  </div>
@@ -2371,10 +2380,10 @@ p {
2371
  }
2372
 
2373
  function dismiss_jetpack_notice() {
2374
- if ( isset( $_GET['jetpack-notice'] ) && 'dismiss' == $_GET['jetpack-notice'] && ! is_plugin_active_for_network( plugin_basename( __FILE__ ) ) ) {
2375
  require_once ABSPATH . 'wp-admin/includes/plugin.php';
2376
 
2377
- deactivate_plugins( plugin_basename( __FILE__ ), false, false );
2378
 
2379
  wp_safe_redirect( admin_url() . 'plugins.php?deactivate=true&plugin_status=all&paged=1&s=' );
2380
  exit;
@@ -2434,7 +2443,7 @@ p {
2434
  ?>
2435
  <?php if ( ! $is_connected ) : ?>
2436
 
2437
- <div id="message" class="updated jetpack-message jp-connect">
2438
  <div id="jp-dismiss" class="jetpack-close-button-container">
2439
  <a class="jetpack-close-button" href="?page=jetpack&jetpack-notice=dismiss" title="<?php _e( 'Dismiss this notice.', 'jetpack' ); ?>"><?php _e( 'Dismiss this notice.', 'jetpack' ); ?></a>
2440
  </div>
@@ -2452,7 +2461,7 @@ p {
2452
 
2453
  <?php elseif ( ! $is_user_connected ) : ?>
2454
 
2455
- <div id="message" class="updated jetpack-message jp-connect">
2456
  <div class="jetpack-wrap-container">
2457
  <div class="jetpack-text-container">
2458
  <h4>
@@ -2650,7 +2659,7 @@ p {
2650
  if ( !current_user_can( 'manage_options' ) ) {
2651
  die( '-1' );
2652
  }
2653
- jetpack_debug_display_handler();
2654
  exit;
2655
  }
2656
 
@@ -2679,7 +2688,7 @@ p {
2679
  }
2680
 
2681
  function admin_screen_list_modules() {
2682
- require_once dirname( __FILE__ ) . '/modules/module-info.php';
2683
  $jetpack_connected = true;
2684
  if ( !Jetpack::is_active() )
2685
  $jetpack_connected = false;
@@ -2912,9 +2921,9 @@ p {
2912
 
2913
  /**
2914
  * Checks to see if the URL is using SSL to connect with Jetpack
2915
- *
2916
  * @since 2.3.3
2917
- * @return boolean
2918
  */
2919
  public static function permit_ssl( $force_recheck = false ) {
2920
  // Do some fancy tests to see if ssl is being supported
@@ -2934,7 +2943,7 @@ p {
2934
  break;
2935
  }
2936
 
2937
- // If it's not 'NEVER', test to see
2938
  if ( $ssl ) {
2939
  $response = wp_remote_get( JETPACK__API_BASE . 'test/1/' );
2940
  if ( is_wp_error( $response ) || ( 'OK' !== wp_remote_retrieve_body( $response ) ) ) {
@@ -3088,7 +3097,7 @@ p {
3088
  */
3089
  public static function load_xml_rpc_client() {
3090
  require_once ABSPATH . WPINC . '/class-IXR.php';
3091
- require_once dirname( __FILE__ ) . '/class.jetpack-ixr-client.php';
3092
  }
3093
 
3094
  function verify_xml_rpc_signature() {
@@ -3135,7 +3144,7 @@ p {
3135
  return false;
3136
  }
3137
 
3138
- require_once dirname( __FILE__ ) . '/class.jetpack-signature.php';
3139
 
3140
  $jetpack_signature = new Jetpack_Signature( $token->secret, (int) Jetpack::get_option( 'time_diff' ) );
3141
  if ( isset( $_POST['_jetpack_is_multipart'] ) ) {
@@ -3503,7 +3512,7 @@ p {
3503
 
3504
  // Verifies the request by checking the signature
3505
  function verify_json_api_authorization_request() {
3506
- require_once dirname( __FILE__ ) . '/class.jetpack-signature.php';
3507
 
3508
  $token = Jetpack_Data::get_access_token( JETPACK_MASTER_USER );
3509
  if ( !$token || empty( $token->secret ) ) {
@@ -3587,7 +3596,8 @@ p {
3587
  * Get $content_width, but with a <s>twist</s> filter.
3588
  */
3589
  public static function get_content_width() {
3590
- return apply_filters( 'jetpack_content_width', $GLOBALS['content_width'] );
 
3591
  }
3592
 
3593
  /**
@@ -3597,7 +3607,7 @@ p {
3597
  * @param int $size Size of the avatar image
3598
  * @param string $default URL to a default image to use if no avatar is available
3599
  * @param bool $force_display Whether to force it to return an avatar even if show_avatars is disabled
3600
- *
3601
  * @return array First element is the URL, second is the class.
3602
  */
3603
  public static function get_avatar_url( $id_or_email, $size = 96, $default = '', $force_display = false ) {
37
  'after-the-deadline' => array( 'after-the-deadline/after-the-deadline.php', 'After The Deadline' ),
38
  'contact-form' => array( 'grunion-contact-form/grunion-contact-form.php', 'Grunion Contact Form' ),
39
  'custom-css' => array( 'safecss/safecss.php', 'WordPress.com Custom CSS' ),
40
+ 'random-redirect' => array( 'random-redirect/random-redirect.php', 'Random Redirect' ),
41
  );
42
 
43
  var $capability_translations = array(
86
  /**
87
  * Holds the singleton instance of this class
88
  * @since 2.3.3
89
+ * @var Jetpack
90
  */
91
  static $instance = false;
92
 
163
 
164
  // Modules should do Jetpack_Sync::sync_options( __FILE__, $option, ... ); instead
165
  // We access the "internal" method here only because the Jetpack object isn't instantiated yet
166
+ $this->sync->options( JETPACK__PLUGIN_DIR . 'jetpack.php',
167
  'home',
168
  'siteurl',
169
  'blogname',
174
  if ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST && isset( $_GET['for'] ) && 'jetpack' == $_GET['for'] ) {
175
  @ini_set( 'display_errors', false ); // Display errors can cause the XML to be not well formed.
176
 
177
+ require_once JETPACK__PLUGIN_DIR . 'class.jetpack-xmlrpc-server.php';
178
  $this->xmlrpc_server = new Jetpack_XMLRPC_Server();
179
 
180
  $this->require_jetpack_authentication();
449
  do_action( 'jetpack_modules_loaded' );
450
 
451
  // Load module-specific code that is needed even when a module isn't active. Loaded here because code contained therein may need actions such as setup_theme.
452
+ require_once( JETPACK__PLUGIN_DIR . 'modules/module-extras.php' );
453
  }
454
 
455
  /**
461
  $_jetpack_rest_api_compat_includes = apply_filters( 'jetpack_rest_api_compat', array() );
462
 
463
  if ( function_exists( 'bbpress' ) )
464
+ $_jetpack_rest_api_compat_includes[] = JETPACK__PLUGIN_DIR . 'class.jetpack-bbpress-json-api-compat.php';
465
 
466
  foreach ( $_jetpack_rest_api_compat_includes as $_jetpack_rest_api_compat_include )
467
  require_once $_jetpack_rest_api_compat_include;
491
  }
492
 
493
  $conflicting_plugins = array(
494
+ 'facebook/facebook.php', // Official Facebook plugin
495
+ 'wordpress-seo/wp-seo.php', // WordPress SEO by Yoast
496
+ 'add-link-to-facebook/add-link-to-facebook.php', // Add Link to Facebook
497
+ 'facebook-awd/AWD_facebook.php', // Facebook AWD All in one
498
+ 'header-footer/plugin.php', // Header and Footer
499
+ 'nextgen-facebook/nextgen-facebook.php', // NextGEN Facebook OG
500
+ 'seo-facebook-comments/seofacebook.php', // SEO Facebook Comments
501
+ 'seo-ultimate/seo-ultimate.php', // SEO Ultimate
502
+ 'sexybookmarks/sexy-bookmarks.php', // Shareaholic
503
+ 'shareaholic/sexy-bookmarks.php', // Shareaholic
504
+ 'social-discussions/social-discussions.php', // Social Discussions
505
+ 'social-networks-auto-poster-facebook-twitter-g/NextScripts_SNAP.php', // NextScripts SNAP
506
+ 'wordbooker/wordbooker.php', // Wordbooker
507
+ 'socialize/socialize.php', // Socialize
508
+ 'simple-facebook-connect/sfc.php', // Simple Facebook Connect
509
+ 'social-sharing-toolkit/social_sharing_toolkit.php', // Social Sharing Toolkit
510
+ 'wp-facebook-open-graph-protocol/wp-facebook-ogp.php', // WP Facebook Open Graph protocol
511
+ 'opengraph/opengraph.php', // Open Graph
512
+ 'sharepress/sharepress.php', // SharePress
513
+ 'wp-facebook-like-send-open-graph-meta/wp-facebook-like-send-open-graph-meta.php', // WP Facebook Like Send & Open Graph Meta
514
+ 'network-publisher/networkpub.php', // Network Publisher
515
+ 'wp-ogp/wp-ogp.php', // WP-OGP
516
+ 'twitter-cards/twitter-cards.php', // Twitter Cards
517
+ 'twitter-cards-meta/twitter-cards-meta.php', // Twitter Cards Meta
518
+ 'ig-twitter-cards/ig-twitter-cards.php', // IG:Twitter Cards
519
+ 'kevinjohn-gallagher-pure-web-brilliants-social-graph-twitter-cards-extention/kevinjohn_gallagher___social_graph_twitter_output.php', // Pure Web Brilliant's Social Graph Twitter Cards Extention
520
+ 'jm-twitter-cards/jm-twitter-cards.php', // JM Twitter Cards
521
+ 'wp-twitter-cards/twitter_cards.php', // WP Twitter Cards
522
+ 'eewee-twitter-card/index.php', // eewee twitter card
523
  );
524
 
525
  foreach ( $conflicting_plugins as $plugin ) {
530
  }
531
 
532
  if ( apply_filters( 'jetpack_enable_open_graph', false ) )
533
+ require_once JETPACK__PLUGIN_DIR . 'functions.opengraph.php';
534
  }
535
 
536
  /* Jetpack Options API */
709
  static $modules = null;
710
 
711
  if ( !isset( $modules ) ) {
712
+ $files = Jetpack::glob_php( JETPACK__PLUGIN_DIR . 'modules' );
713
 
714
  $modules = array();
715
 
722
  }
723
  }
724
 
725
+ $modules = apply_filters( 'jetpack_get_available_modules', $modules, $min_version, $max_version );
726
+
727
  if ( !$min_version && !$max_version ) {
728
  return array_keys( $modules );
729
  }
751
  $return = array();
752
 
753
  foreach ( Jetpack::get_available_modules( $min_version, $max_version ) as $module ) {
754
+ $module_data = Jetpack::get_module( $module );
 
 
 
 
 
 
 
 
 
 
 
755
 
756
+ switch ( strtolower( $module_data['auto_activate'] ) ) {
757
+ case 'yes' :
758
+ $return[] = $module;
759
+ break;
760
+ case 'public' :
761
+ if ( Jetpack::get_option( 'public' ) ) {
762
+ $return[] = $module;
763
+ }
764
+ break;
765
+ case 'no' :
766
+ default :
767
  break;
 
 
 
 
 
768
  }
769
+
770
  }
771
 
772
+ return apply_filters( 'jetpack_get_default_modules', $return, $min_version, $max_version );
773
  }
774
 
775
  /**
783
  * Generate a module's path from its slug.
784
  */
785
  public static function get_module_path( $slug ) {
786
+ return JETPACK__PLUGIN_DIR . "modules/$slug.php";
787
  }
788
 
789
  /**
801
  'deactivate' => 'Deactivate',
802
  'free' => 'Free',
803
  'requires_connection' => 'Requires Connection',
804
+ 'auto_activate' => 'Auto Activate',
805
  );
806
 
807
  $file = Jetpack::get_module_path( Jetpack::get_module_slug( $module ) );
819
  $mod['deactivate'] = empty( $mod['deactivate'] );
820
  $mod['free'] = empty( $mod['free'] );
821
  $mod['requires_connection'] = ( ! empty( $mod['requires_connection'] ) && 'No' == $mod['requires_connection'] ) ? false : true;
822
+
823
+ if ( empty( $mod['auto_activate'] ) || ! in_array( strtolower( $mod['auto_activate'] ), array( 'yes', 'no', 'public' ) ) ) {
824
+ $mod['auto_activate'] = 'No';
825
+ } else {
826
+ $mod['auto_activate'] = (string) $mod['auto_activate'];
827
+ }
828
+
829
  return $mod;
830
  }
831
 
998
 
999
  $module_data = Jetpack::get_module( $module );
1000
 
1001
+ if ( ! Jetpack::is_active() ) {
1002
  if ( ! Jetpack::is_development_mode() )
1003
  return false;
1004
 
1111
  <?php
1112
  if ( $deactivate ) {
1113
  $plugins = get_option( 'active_plugins' );
1114
+ $jetpack = plugin_basename( JETPACK__PLUGIN_DIR . 'jetpack.php' );
1115
  $update = false;
1116
  foreach ( $plugins as $i => $plugin ) {
1117
  if ( $plugin === $jetpack ) {
1283
 
1284
  add_action( 'load-plugins.php', array( $this, 'intercept_plugin_error_scrape_init' ) );
1285
  add_action( 'admin_head', array( $this, 'admin_menu_css' ) );
1286
+ add_filter( 'plugin_action_links_' . plugin_basename( JETPACK__PLUGIN_DIR . 'jetpack.php' ), array( $this, 'plugin_action_links' ) );
1287
 
1288
  if ( Jetpack::is_active() || Jetpack::is_development_mode() ) {
1289
  // Artificially throw errors in certain whitelisted cases during plugin activation
1382
  }
1383
 
1384
  $hook = add_menu_page( 'Jetpack', $title, 'read', 'jetpack', array( $this, 'admin_page' ), 'div' );
 
 
 
1385
 
1386
+ $debugger_hook = add_submenu_page( null, __( 'Jetpack Debugging Center', 'jetpack' ), '', 'manage_options', 'jetpack-debugger', array( $this, 'debugger_page' ) );
1387
+ add_action( "admin_head-$debugger_hook", array( 'Jetpack_Debugger', 'jetpack_debug_admin_head' ) );
1388
 
1389
  add_action( "load-$hook", array( $this, 'admin_page_load' ) );
1390
 
1413
  add_action( "load-$hook", array( $this, 'admin_help' ) );
1414
  add_action( "admin_head-$hook", array( $this, 'admin_head' ) );
1415
  add_action( "admin_print_styles-$hook", array( $this, 'admin_styles' ) );
1416
+ add_action( "admin_print_scripts-$hook", array( $this, 'admin_scripts' ) );
1417
  }
1418
  /**/
1419
  function add_remote_request_handlers() {
1594
  '<p><strong>' . __( 'For more information:', 'jetpack' ) . '</strong></p>' .
1595
  '<p><a href="http://jetpack.me/faq/" target="_blank">' . __( 'Jetpack FAQ', 'jetpack' ) . '</a></p>' .
1596
  '<p><a href="http://jetpack.me/support/" target="_blank">' . __( 'Jetpack Support', 'jetpack' ) . '</a></p>' .
1597
+ '<p><a href="' . Jetpack::admin_url( array( 'page' => 'jetpack-debugger' ) ) .'">' . __( 'Jetpack Debugging Center', 'jetpack' ) . '</a></p>'
1598
 
1599
  );
1600
  }
1602
  function admin_menu_css() { ?>
1603
  <style type="text/css" id="jetpack-menu-css">
1604
  #toplevel_page_jetpack .wp-menu-image {
1605
+ background: url( <?php echo plugins_url( '_inc/images/menuicon-sprite.png', __FILE__ ) ?> ) 0 90% no-repeat;
1606
  }
1607
  /* Retina Jetpack Menu Icon */
1608
  @media only screen and (-moz-min-device-pixel-ratio: 1.5), only screen and (-o-min-device-pixel-ratio: 3/2), only screen and (-webkit-min-device-pixel-ratio: 1.5), only screen and (min-device-pixel-ratio: 1.5) {
1609
  #toplevel_page_jetpack .wp-menu-image {
1610
+ background: url( <?php echo plugins_url( '_inc/images/menuicon-sprite-2x.png', __FILE__ ) ?> ) 0 90% no-repeat;
1611
  background-size:30px 64px;
1612
  }
1613
  }
1644
 
1645
  function admin_styles() {
1646
  global $wp_styles;
1647
+ wp_enqueue_style( 'jetpack', plugins_url( '_inc/jetpack.css', __FILE__ ), false, JETPACK__VERSION . '-20121016' );
1648
  $wp_styles->add_data( 'jetpack', 'rtl', true );
1649
  }
1650
 
1651
  function admin_scripts() {
1652
+ wp_enqueue_script( 'jetpack-js', plugins_url( '_inc/jetpack.js', __FILE__ ), array( 'jquery' ), JETPACK__VERSION . '-20121111' );
1653
  wp_localize_script( 'jetpack-js', 'jetpackL10n', array(
1654
  'ays_disconnect' => "This will deactivate all Jetpack modules.\nAre you sure you want to disconnect?",
1655
  'ays_unlink' => "This will prevent user-specific modules such as Publicize, Notifications and Post By Email from working.\nAre you sure you want to unlink?",
1675
  return;
1676
  ?>
1677
 
1678
+ <div id="message" class="updated jetpack-message jp-connect" style="display:block !important;">
1679
  <div id="jp-dismiss" class="jetpack-close-button-container">
1680
  <a class="jetpack-close-button" href="?page=jetpack&jetpack-notice=dismiss" title="<?php _e( 'Dismiss this notice and deactivate Jetpack.', 'jetpack' ); ?>"><?php _e( 'Dismiss this notice and deactivate Jetpack.', 'jetpack' ); ?></a>
1681
  </div>
2380
  }
2381
 
2382
  function dismiss_jetpack_notice() {
2383
+ if ( isset( $_GET['jetpack-notice'] ) && 'dismiss' == $_GET['jetpack-notice'] && ! is_plugin_active_for_network( plugin_basename( JETPACK__PLUGIN_DIR . 'jetpack.php' ) ) ) {
2384
  require_once ABSPATH . 'wp-admin/includes/plugin.php';
2385
 
2386
+ deactivate_plugins( JETPACK__PLUGIN_DIR . 'jetpack.php', false, false );
2387
 
2388
  wp_safe_redirect( admin_url() . 'plugins.php?deactivate=true&plugin_status=all&paged=1&s=' );
2389
  exit;
2443
  ?>
2444
  <?php if ( ! $is_connected ) : ?>
2445
 
2446
+ <div id="message" class="updated jetpack-message jp-connect" style="display:block !important;">
2447
  <div id="jp-dismiss" class="jetpack-close-button-container">
2448
  <a class="jetpack-close-button" href="?page=jetpack&jetpack-notice=dismiss" title="<?php _e( 'Dismiss this notice.', 'jetpack' ); ?>"><?php _e( 'Dismiss this notice.', 'jetpack' ); ?></a>
2449
  </div>
2461
 
2462
  <?php elseif ( ! $is_user_connected ) : ?>
2463
 
2464
+ <div id="message" class="updated jetpack-message jp-connect" style="display:block !important;">
2465
  <div class="jetpack-wrap-container">
2466
  <div class="jetpack-text-container">
2467
  <h4>
2659
  if ( !current_user_can( 'manage_options' ) ) {
2660
  die( '-1' );
2661
  }
2662
+ Jetpack_Debugger::jetpack_debug_display_handler();
2663
  exit;
2664
  }
2665
 
2688
  }
2689
 
2690
  function admin_screen_list_modules() {
2691
+ require_once JETPACK__PLUGIN_DIR . 'modules/module-info.php';
2692
  $jetpack_connected = true;
2693
  if ( !Jetpack::is_active() )
2694
  $jetpack_connected = false;
2921
 
2922
  /**
2923
  * Checks to see if the URL is using SSL to connect with Jetpack
2924
+ *
2925
  * @since 2.3.3
2926
+ * @return boolean
2927
  */
2928
  public static function permit_ssl( $force_recheck = false ) {
2929
  // Do some fancy tests to see if ssl is being supported
2943
  break;
2944
  }
2945
 
2946
+ // If it's not 'NEVER', test to see
2947
  if ( $ssl ) {
2948
  $response = wp_remote_get( JETPACK__API_BASE . 'test/1/' );
2949
  if ( is_wp_error( $response ) || ( 'OK' !== wp_remote_retrieve_body( $response ) ) ) {
3097
  */
3098
  public static function load_xml_rpc_client() {
3099
  require_once ABSPATH . WPINC . '/class-IXR.php';
3100
+ require_once JETPACK__PLUGIN_DIR . 'class.jetpack-ixr-client.php';
3101
  }
3102
 
3103
  function verify_xml_rpc_signature() {
3144
  return false;
3145
  }
3146
 
3147
+ require_once JETPACK__PLUGIN_DIR . 'class.jetpack-signature.php';
3148
 
3149
  $jetpack_signature = new Jetpack_Signature( $token->secret, (int) Jetpack::get_option( 'time_diff' ) );
3150
  if ( isset( $_POST['_jetpack_is_multipart'] ) ) {
3512
 
3513
  // Verifies the request by checking the signature
3514
  function verify_json_api_authorization_request() {
3515
+ require_once JETPACK__PLUGIN_DIR . 'class.jetpack-signature.php';
3516
 
3517
  $token = Jetpack_Data::get_access_token( JETPACK_MASTER_USER );
3518
  if ( !$token || empty( $token->secret ) ) {
3596
  * Get $content_width, but with a <s>twist</s> filter.
3597
  */
3598
  public static function get_content_width() {
3599
+ $content_width = isset( $GLOBALS['content_width'] ) ? $GLOBALS['content_width'] : false;
3600
+ return apply_filters( 'jetpack_content_width', $content_width );
3601
  }
3602
 
3603
  /**
3607
  * @param int $size Size of the avatar image
3608
  * @param string $default URL to a default image to use if no avatar is available
3609
  * @param bool $force_display Whether to force it to return an avatar even if show_avatars is disabled
3610
+ *
3611
  * @return array First element is the URL, second is the class.
3612
  */
3613
  public static function get_avatar_url( $id_or_email, $size = 96, $default = '', $force_display = false ) {
class.json-api-endpoints.php CHANGED
@@ -880,6 +880,7 @@ EOPHP;
880
  $name = $author->comment_author;
881
  $URL = $author->comment_author_url;
882
  $profile_URL = 'http://en.gravatar.com/' . md5( strtolower( trim( $email ) ) );
 
883
  } else {
884
  if ( isset( $author->post_author ) ) {
885
  if ( 0 == $author->post_author )
@@ -902,6 +903,7 @@ EOPHP;
902
  $email = $user->user_email;
903
  $name = $user->display_name;
904
  $URL = $user->user_url;
 
905
  if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
906
  $profile_URL = "http://en.gravatar.com/{$user->user_login}";
907
  } else {
@@ -917,6 +919,7 @@ EOPHP;
917
  'ID' => (int) $ID,
918
  'email' => $email, // (string|bool)
919
  'name' => (string) $name,
 
920
  'URL' => (string) esc_url_raw( $URL ),
921
  'avatar_URL' => (string) esc_url_raw( $avatar_URL ),
922
  'profile_URL' => (string) esc_url_raw( $profile_URL ),
@@ -2230,7 +2233,11 @@ class WPCOM_JSON_API_Update_Taxonomy_Endpoint extends WPCOM_JSON_API_Taxonomy_En
2230
  )
2231
  );
2232
 
 
 
 
2233
  $taxonomy = get_term_by( 'id', $data['term_id'], $taxonomy_type );
 
2234
  $return = $this->get_taxonomy( $taxonomy->slug, $taxonomy_type, $args['context'] );
2235
  if ( !$return || is_wp_error( $return ) ) {
2236
  return $return;
880
  $name = $author->comment_author;
881
  $URL = $author->comment_author_url;
882
  $profile_URL = 'http://en.gravatar.com/' . md5( strtolower( trim( $email ) ) );
883
+ $nice = '';
884
  } else {
885
  if ( isset( $author->post_author ) ) {
886
  if ( 0 == $author->post_author )
903
  $email = $user->user_email;
904
  $name = $user->display_name;
905
  $URL = $user->user_url;
906
+ $nice = $user->user_nicename;
907
  if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
908
  $profile_URL = "http://en.gravatar.com/{$user->user_login}";
909
  } else {
919
  'ID' => (int) $ID,
920
  'email' => $email, // (string|bool)
921
  'name' => (string) $name,
922
+ 'nice_name' => (string) $nice,
923
  'URL' => (string) esc_url_raw( $URL ),
924
  'avatar_URL' => (string) esc_url_raw( $avatar_URL ),
925
  'profile_URL' => (string) esc_url_raw( $profile_URL ),
2233
  )
2234
  );
2235
 
2236
+ if ( is_wp_error( $data ) )
2237
+ return $data;
2238
+
2239
  $taxonomy = get_term_by( 'id', $data['term_id'], $taxonomy_type );
2240
+
2241
  $return = $this->get_taxonomy( $taxonomy->slug, $taxonomy_type, $args['context'] );
2242
  if ( !$return || is_wp_error( $return ) ) {
2243
  return $return;
class.photon.php CHANGED
@@ -444,7 +444,7 @@ class Jetpack_Photon {
444
  ) );
445
 
446
  // Bail if scheme isn't http or port is set that isn't port 80
447
- if ( 'http' != $url_info['scheme'] || ! in_array( $url_info['port'], array( 80, null ) ) )
448
  return false;
449
 
450
  // Bail if no host is found
444
  ) );
445
 
446
  // Bail if scheme isn't http or port is set that isn't port 80
447
+ if ( ( 'http' != $url_info['scheme'] || ! in_array( $url_info['port'], array( 80, null ) ) ) && apply_filters( 'jetpack_photon_reject_https', true ) )
448
  return false;
449
 
450
  // Bail if no host is found
functions.twitter-cards.php ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /* Twitter Cards
4
+ *
5
+ * Hooks onto the Open Graph protocol and extends it by adding only the tags
6
+ * we need for twitter cards.
7
+ *
8
+ * @see /wp-content/blog-plugins/open-graph.php
9
+ * @see https://dev.twitter.com/docs/cards
10
+ */
11
+ function wpcom_twitter_cards_tags( $og_tags ) {
12
+ global $post, $wpdb;
13
+
14
+ $og_tags['twitter:site'] = '@wordpressdotcom';
15
+
16
+ if ( ! is_singular() || ! empty( $og_tags['twitter:card'] ) )
17
+ return $og_tags;
18
+
19
+ $img_count = 0;
20
+ foreach ( $og_tags as $key => $value ) {
21
+ if ( 'og:image' != $key || ! is_array( $value ) || empty( $value[0] ) )
22
+ continue;
23
+
24
+ $img_count = 0;
25
+ foreach ( (array) $value as $counter => $image ) {
26
+ $og_tags['twitter:image' . $counter] = $image;
27
+ $img_count++;
28
+ if ( $img_count >= 4 )
29
+ break; // Only 4 images allowed
30
+ }
31
+ }
32
+
33
+ // Figure out what kind of card this is, based on the number of images found
34
+ if ( 0 == $img_count ) {
35
+ // No images = summary
36
+ $card = 'summary';
37
+ } else if ( $img_count <= 3 ) {
38
+ // < 4 images = photo
39
+ $card = 'photo';
40
+ $og_tags['twitter:image'] = $og_tags['twitter:image0']; // Rename back to photo format (from gallery)
41
+ unset( $og_tags['twitter:image0'] );
42
+ for ( $i = 1; $i < 4; $i++ ) {
43
+ unset( $og_tags['twitter:image' . $i] ); // Remove >0 image references
44
+ }
45
+ } else if ( $img_count >= 4 ) {
46
+ // >= 4 images = gallery
47
+ $card = 'gallery';
48
+ }
49
+ $og_tags['twitter:card'] = $card;
50
+
51
+ // If we have information on the author/creator, then include that as well
52
+ if ( ! empty( $post ) && ! empty( $post->post_author ) ) {
53
+ $handle = apply_filters( 'jetpack_sharing_twitter_via', '', $post->ID );
54
+ if ( !empty( $handle ) )
55
+ $og_tags['twitter:creator'] = '@' . $handle;
56
+ }
57
+
58
+ return $og_tags;
59
+ }
60
+
61
+ add_filter( 'jetpack_open_graph_tags', 'wpcom_twitter_cards_tags' );
62
+
63
+ function wpcom_twitter_cards_output( $og_tag ) {
64
+ return ( false !== strpos( $og_tag, 'twitter:' ) ) ? preg_replace( '/property="([^"]+)"/', 'name="\1"', $og_tag ) : $og_tag;
65
+ }
66
+
67
+ add_filter( 'jetpack_open_graph_output', 'wpcom_twitter_cards_output' );
jetpack.php CHANGED
@@ -5,7 +5,7 @@
5
  * Plugin URI: http://wordpress.org/extend/plugins/jetpack/
6
  * Description: Bring the power of the WordPress.com cloud to your self-hosted WordPress. Jetpack enables you to connect your blog to a WordPress.com account to use the powerful features normally only available to WordPress.com users.
7
  * Author: Automattic
8
- * Version: 2.3.8
9
  * Author URI: http://jetpack.me
10
  * License: GPL2+
11
  * Text Domain: jetpack
@@ -17,7 +17,7 @@ define( 'JETPACK__API_VERSION', 1 );
17
  define( 'JETPACK__MINIMUM_WP_VERSION', '3.5' );
18
  defined( 'JETPACK_CLIENT__AUTH_LOCATION' ) or define( 'JETPACK_CLIENT__AUTH_LOCATION', 'header' );
19
  defined( 'JETPACK_CLIENT__HTTPS' ) or define( 'JETPACK_CLIENT__HTTPS', 'AUTO' );
20
- define( 'JETPACK__VERSION', '2.3.8' );
21
  define( 'JETPACK__PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
22
  defined( 'JETPACK__GLOTPRESS_LOCALES_PATH' ) or define( 'JETPACK__GLOTPRESS_LOCALES_PATH', JETPACK__PLUGIN_DIR . 'locales.php' );
23
 
@@ -49,6 +49,7 @@ require_once( JETPACK__PLUGIN_DIR . 'class.photon.php' );
49
  require_once( JETPACK__PLUGIN_DIR . 'functions.photon.php' );
50
  require_once( JETPACK__PLUGIN_DIR . 'functions.compat.php' );
51
  require_once( JETPACK__PLUGIN_DIR . 'functions.gallery.php' );
 
52
 
53
  register_activation_hook( __FILE__, array( 'Jetpack', 'plugin_activation' ) );
54
  register_deactivation_hook( __FILE__, array( 'Jetpack', 'plugin_deactivation' ) );
@@ -57,10 +58,26 @@ add_action( 'init', array( 'Jetpack', 'init' ) );
57
  add_action( 'plugins_loaded', array( 'Jetpack', 'load_modules' ), 100 );
58
  add_filter( 'jetpack_static_url', array( 'Jetpack', 'staticize_subdomain' ) );
59
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
  /*
61
  if ( is_admin() && ! Jetpack::check_identity_crisis() ) {
62
  Jetpack_Sync::sync_options( __FILE__, 'db_version', 'jetpack_active_modules', 'active_plugins' );
63
  }
64
  */
65
-
66
- Jetpack_Sync::sync_options( __FILE__, 'widget_twitter' );
5
  * Plugin URI: http://wordpress.org/extend/plugins/jetpack/
6
  * Description: Bring the power of the WordPress.com cloud to your self-hosted WordPress. Jetpack enables you to connect your blog to a WordPress.com account to use the powerful features normally only available to WordPress.com users.
7
  * Author: Automattic
8
+ * Version: 2.4.5
9
  * Author URI: http://jetpack.me
10
  * License: GPL2+
11
  * Text Domain: jetpack
17
  define( 'JETPACK__MINIMUM_WP_VERSION', '3.5' );
18
  defined( 'JETPACK_CLIENT__AUTH_LOCATION' ) or define( 'JETPACK_CLIENT__AUTH_LOCATION', 'header' );
19
  defined( 'JETPACK_CLIENT__HTTPS' ) or define( 'JETPACK_CLIENT__HTTPS', 'AUTO' );
20
+ define( 'JETPACK__VERSION', '2.4.5' );
21
  define( 'JETPACK__PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
22
  defined( 'JETPACK__GLOTPRESS_LOCALES_PATH' ) or define( 'JETPACK__GLOTPRESS_LOCALES_PATH', JETPACK__PLUGIN_DIR . 'locales.php' );
23
 
49
  require_once( JETPACK__PLUGIN_DIR . 'functions.photon.php' );
50
  require_once( JETPACK__PLUGIN_DIR . 'functions.compat.php' );
51
  require_once( JETPACK__PLUGIN_DIR . 'functions.gallery.php' );
52
+ require_once( JETPACK__PLUGIN_DIR . 'functions.twitter-cards.php' );
53
 
54
  register_activation_hook( __FILE__, array( 'Jetpack', 'plugin_activation' ) );
55
  register_deactivation_hook( __FILE__, array( 'Jetpack', 'plugin_deactivation' ) );
58
  add_action( 'plugins_loaded', array( 'Jetpack', 'load_modules' ), 100 );
59
  add_filter( 'jetpack_static_url', array( 'Jetpack', 'staticize_subdomain' ) );
60
 
61
+ add_filter( 'jetpack_open_graph_tags', 'change_twitter_site_param' );
62
+
63
+ function change_twitter_site_param( $og_tags ) {
64
+ $og_tags['twitter:site'] = '@jetpack';
65
+ return $og_tags;
66
+ }
67
+
68
+ /**
69
+ * Add an easy way to photon-ize a URL that is safe to call even if Jetpack isn't active.
70
+ *
71
+ * See: http://jetpack.me/2013/07/11/photon-and-themes/
72
+ */
73
+ if ( Jetpack::init()->is_module_active( 'photon' ) ) {
74
+ add_filter( 'jetpack_photon_url', 'jetpack_photon_url', 10, 3 );
75
+ } else {
76
+ remove_filter( 'jetpack_photon_url', 'jetpack_photon_url', 10, 3 );
77
+ }
78
+
79
  /*
80
  if ( is_admin() && ! Jetpack::check_identity_crisis() ) {
81
  Jetpack_Sync::sync_options( __FILE__, 'db_version', 'jetpack_active_modules', 'active_plugins' );
82
  }
83
  */
 
 
languages/jetpack-ar.mo CHANGED
Binary file
languages/jetpack-az.mo CHANGED
Binary file
languages/jetpack-bs_BA.mo CHANGED
Binary file
languages/jetpack-ca.mo CHANGED
Binary file
languages/jetpack-cs_CZ.mo CHANGED
Binary file
languages/jetpack-da_DK.mo CHANGED
Binary file
languages/jetpack-de_DE.mo CHANGED
Binary file
languages/jetpack-el.mo CHANGED
Binary file
languages/jetpack-es_ES.mo CHANGED
Binary file
languages/jetpack-fa_IR.mo CHANGED
Binary file
languages/jetpack-fi.mo CHANGED
Binary file
languages/jetpack-fr_FR.mo CHANGED
Binary file
languages/jetpack-gl_ES.mo CHANGED
Binary file
languages/jetpack-he_IL.mo CHANGED
Binary file
languages/jetpack-hr.mo CHANGED
Binary file
languages/jetpack-hu_HU.mo CHANGED
Binary file
languages/jetpack-id_ID.mo CHANGED
Binary file
languages/jetpack-it_IT.mo CHANGED
Binary file
languages/jetpack-ja.mo CHANGED
Binary file
languages/jetpack-ko_KR.mo CHANGED
Binary file
languages/jetpack-lt_LT.mo CHANGED
Binary file
languages/jetpack-mk_MK.mo CHANGED
Binary file
languages/jetpack-my_MM.mo CHANGED
Binary file
languages/jetpack-nb_NO.mo CHANGED
Binary file
languages/jetpack-nl_NL.mo CHANGED
Binary file
languages/jetpack-nn_NO.mo CHANGED
Binary file
languages/jetpack-pl_PL.mo CHANGED
Binary file
languages/jetpack-pt_BR.mo CHANGED
Binary file
languages/jetpack-pt_PT.mo CHANGED
Binary file
languages/jetpack-ro_RO.mo CHANGED
Binary file
languages/jetpack-ru_RU.mo CHANGED
Binary file
languages/jetpack-sa_IN.mo CHANGED
Binary file
languages/jetpack-sk_SK.mo CHANGED
Binary file
languages/jetpack-sq.mo CHANGED
Binary file
languages/jetpack-sr_RS.mo CHANGED
Binary file
languages/jetpack-sv_SE.mo CHANGED
Binary file
languages/jetpack-th.mo CHANGED
Binary file
languages/jetpack-tr_TR.mo CHANGED
Binary file
languages/jetpack-uk.mo CHANGED
Binary file
languages/jetpack-ur.mo CHANGED
Binary file
languages/jetpack-zh_CN.mo CHANGED
Binary file
languages/jetpack-zh_TW.mo CHANGED
Binary file
modules/after-the-deadline.php CHANGED
@@ -5,6 +5,7 @@
5
  * Sort Order: 6
6
  * First Introduced: 1.1
7
  * Requires Connection: Yes
 
8
  */
9
 
10
  add_action( 'jetpack_modules_loaded', 'AtD_load' );
5
  * Sort Order: 6
6
  * First Introduced: 1.1
7
  * Requires Connection: Yes
8
+ * Auto Activate: Yes
9
  */
10
 
11
  add_action( 'jetpack_modules_loaded', 'AtD_load' );
modules/after-the-deadline/config-unignore.php CHANGED
@@ -32,6 +32,9 @@ function AtD_process_unignore_update() {
32
  if ( ! AtD_is_allowed() )
33
  return;
34
 
 
 
 
35
  $user = wp_get_current_user();
36
 
37
  if ( ! $user || $user->ID == 0 )
32
  if ( ! AtD_is_allowed() )
33
  return;
34
 
35
+ if ( ! isset( $_POST['AtD_ignored_phrases'] ) )
36
+ return;
37
+
38
  $user = wp_get_current_user();
39
 
40
  if ( ! $user || $user->ID == 0 )
modules/carousel.php CHANGED
@@ -6,6 +6,7 @@
6
  * Sort Order: 4
7
  * First Introduced: 1.5
8
  * Requires Connection: No
 
9
  */
10
 
11
  include dirname( __FILE__ ) . '/carousel/jetpack-carousel.php';
6
  * Sort Order: 4
7
  * First Introduced: 1.5
8
  * Requires Connection: No
9
+ * Auto Activate: No
10
  */
11
 
12
  include dirname( __FILE__ ) . '/carousel/jetpack-carousel.php';
modules/comments.php CHANGED
@@ -6,6 +6,7 @@
6
  * First Introduced: 1.4
7
  * Sort Order: 2
8
  * Requires Connection: Yes
 
9
  */
10
 
11
  require dirname( __FILE__ ) . '/comments/comments.php';
6
  * First Introduced: 1.4
7
  * Sort Order: 2
8
  * Requires Connection: Yes
9
+ * Auto Activate: No
10
  */
11
 
12
  require dirname( __FILE__ ) . '/comments/comments.php';
modules/contact-form.php CHANGED
@@ -5,6 +5,7 @@
5
  * Sort Order: 9
6
  * First Introduced: 1.3
7
  * Requires Connection: No
 
8
  */
9
 
10
  include dirname( __FILE__ ) . '/contact-form/grunion-contact-form.php';
5
  * Sort Order: 9
6
  * First Introduced: 1.3
7
  * Requires Connection: No
8
+ * Auto Activate: Yes
9
  */
10
 
11
  include dirname( __FILE__ ) . '/contact-form/grunion-contact-form.php';
modules/contact-form/admin.php CHANGED
@@ -402,7 +402,12 @@ jQuery(document).ready( function($) {
402
  break;
403
 
404
  case 'feedback_date':
405
- echo get_the_date( __( 'Y-m-d @ g:i:s A', 'jetpack' ) );
 
 
 
 
 
406
  break;
407
  }
408
  }
402
  break;
403
 
404
  case 'feedback_date':
405
+
406
+ $date_time_format = _x( '%1$s \a\t %2$s', '{$date_format} \a\t {$time_format}', 'jetpack' );
407
+ $date_time_format = sprintf( $date_time_format, get_option( 'date_format' ), get_option( 'time_format' ) );
408
+ $time = date_i18n( $date_time_format, get_the_time( 'U' ) );
409
+
410
+ echo $time;
411
  break;
412
  }
413
  }
modules/contact-form/css/menu-alter.css CHANGED
@@ -12,11 +12,11 @@
12
  background: url(../images/grunion-menu.png) no-repeat 7px 7px !important;
13
  }
14
 
15
- body.admin-color-mp6 #adminmenu .menu-icon-feedback div.wp-menu-image {
16
  background: none !important;
17
  }
18
 
19
- body.admin-color-mp6 #adminmenu .menu-icon-feedback div.wp-menu-image:before {
20
  content: '\f175';
21
  margin-left: -1px;
22
  }
12
  background: url(../images/grunion-menu.png) no-repeat 7px 7px !important;
13
  }
14
 
15
+ body.mp6 #adminmenu .menu-icon-feedback div.wp-menu-image {
16
  background: none !important;
17
  }
18
 
19
+ body.mp6 #adminmenu .menu-icon-feedback div.wp-menu-image:before {
20
  content: '\f175';
21
  margin-left: -1px;
22
  }
modules/contact-form/css/rtl/menu-alter-rtl.css CHANGED
@@ -14,15 +14,15 @@
14
  background: url(../../images/grunion-menu.png) no-repeat 7px 7px !important;
15
  }
16
 
17
- body.admin-color-mp6 #adminmenu .toplevel_page_feedback div.wp-menu-image img {
18
  display: none;
19
  }
20
 
21
- body.admin-color-mp6 #adminmenu .menu-icon-feedback div.wp-menu-image, body.admin-color-mp6 #adminmenu .toplevel_page_feedback div.wp-menu-image {
22
  background: none !important;
23
  }
24
 
25
- body.admin-color-mp6 #adminmenu .menu-icon-feedback div.wp-menu-image:before, body.admin-color-mp6 #adminmenu .toplevel_page_feedback div.wp-menu-image:before {
26
  content: '\f175';
27
  margin-right: -1px;
28
  }
14
  background: url(../../images/grunion-menu.png) no-repeat 7px 7px !important;
15
  }
16
 
17
+ body.mp6 #adminmenu .toplevel_page_feedback div.wp-menu-image img {
18
  display: none;
19
  }
20
 
21
+ body.mp6 #adminmenu .menu-icon-feedback div.wp-menu-image, body.mp6 #adminmenu .toplevel_page_feedback div.wp-menu-image {
22
  background: none !important;
23
  }
24
 
25
+ body.mp6 #adminmenu .menu-icon-feedback div.wp-menu-image:before, body.mp6 #adminmenu .toplevel_page_feedback div.wp-menu-image:before {
26
  content: '\f175';
27
  margin-right: -1px;
28
  }
modules/contact-form/grunion-contact-form.php CHANGED
@@ -359,7 +359,7 @@ class Grunion_Contact_Form_Plugin {
359
  <?php wp_nonce_field( 'feedback_export','feedback_export_nonce' ); ?>
360
 
361
  <input name="action" value="feedback_export" type="hidden">
362
- <label for="post"><? _e( 'Select feedback to download', 'jetpack' ) ?></label>
363
  <select name="post">
364
  <option value="all"><?php esc_html_e( 'All posts', 'jetpack' ) ?></option>
365
  <?php echo $this->get_feedbacks_as_options() ?>
359
  <?php wp_nonce_field( 'feedback_export','feedback_export_nonce' ); ?>
360
 
361
  <input name="action" value="feedback_export" type="hidden">
362
+ <label for="post"><?php _e( 'Select feedback to download', 'jetpack' ) ?></label>
363
  <select name="post">
364
  <option value="all"><?php esc_html_e( 'All posts', 'jetpack' ) ?></option>
365
  <?php echo $this->get_feedbacks_as_options() ?>
modules/custom-css.php CHANGED
@@ -6,6 +6,7 @@
6
  * Sort Order: 11
7
  * First Introduced: 1.7
8
  * Requires Connection: No
 
9
  */
10
 
11
  function jetpack_load_custom_css() {
6
  * Sort Order: 11
7
  * First Introduced: 1.7
8
  * Requires Connection: No
9
+ * Auto Activate: Yes
10
  */
11
 
12
  function jetpack_load_custom_css() {
modules/custom-css/custom-css.php CHANGED
@@ -901,14 +901,25 @@ class Jetpack_Custom_CSS {
901
 
902
  /**
903
  * Render metabox listing CSS revisions and the themes that correspond to the revisions.
904
- * Called by afecss_admin *
905
- * @param array $safecss_post
906
  * @global $post
907
- * @uses WP_Query, wp_post_revision_title, esc_html, add_query_arg, menu_page_url, wp_reset_query
 
 
 
 
 
 
 
908
  * @return string
909
  */
910
  static function revisions_meta_box( $safecss_post ) {
911
- $max_revisions = defined( 'WP_POST_REVISIONS' ) && is_numeric( WP_POST_REVISIONS ) ? (int) WP_POST_REVISIONS : 25;
 
 
 
 
912
  $posts_per_page = isset( $_GET['show_all_rev'] ) ? $max_revisions : 6;
913
 
914
  $revisions = new WP_Query( array(
901
 
902
  /**
903
  * Render metabox listing CSS revisions and the themes that correspond to the revisions.
904
+ * Called by safecss_admin
905
+ *
906
  * @global $post
907
+ * @param array $safecss_post
908
+ * @uses wp_revisions_to_keep
909
+ * @uses WP_Query
910
+ * @uses wp_post_revision_title
911
+ * @uses esc_html
912
+ * @uses add_query_arg
913
+ * @uses menu_page_url
914
+ * @uses wp_reset_query
915
  * @return string
916
  */
917
  static function revisions_meta_box( $safecss_post ) {
918
+ if ( function_exists( 'wp_revisions_to_keep' ) )
919
+ $max_revisions = wp_revisions_to_keep( $safecss_post );
920
+ else
921
+ $max_revisions = defined( 'WP_POST_REVISIONS' ) && is_numeric( WP_POST_REVISIONS ) ? (int) WP_POST_REVISIONS : 25;
922
+
923
  $posts_per_page = isset( $_GET['show_all_rev'] ) ? $max_revisions : 6;
924
 
925
  $revisions = new WP_Query( array(
modules/custom-css/custom-css/css/css-editor.css CHANGED
@@ -21,4 +21,7 @@
21
 
22
  .misc-pub-section > div {
23
  margin-top: 3px;
 
 
 
24
  }
21
 
22
  .misc-pub-section > div {
23
  margin-top: 3px;
24
+ }
25
+ #safecss-ace .ace_gutter {
26
+ z-index: 1;
27
  }
modules/custom-css/custom-css/preprocessors/lessc.inc.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
 
3
  /**
4
- * lessphp v0.3.8
5
  * http://leafo.net/lessphp
6
  *
7
  * LESS css compiler, adapted from http://lesscss.org
@@ -38,7 +38,7 @@
38
  * handling things like indentation.
39
  */
40
  class lessc {
41
- static public $VERSION = "v0.3.8";
42
  static protected $TRUE = array("keyword", "true");
43
  static protected $FALSE = array("keyword", "false");
44
 
@@ -55,6 +55,8 @@ class lessc {
55
 
56
  protected $numberPrecision = null;
57
 
 
 
58
  // set to the parser that generated the current line when compiling
59
  // so we know how to create error messages
60
  protected $sourceParser = null;
@@ -103,12 +105,17 @@ class lessc {
103
  if (substr_compare($url, '.css', -4, 4) === 0) return false;
104
 
105
  $realPath = $this->findImport($url);
 
106
  if ($realPath === null) return false;
107
 
108
  if ($this->importDisabled) {
109
  return array(false, "/* import disabled */");
110
  }
111
 
 
 
 
 
112
  $this->addParsedFile($realPath);
113
  $parser = $this->makeParser($realPath);
114
  $root = $parser->parse(file_get_contents($realPath));
@@ -276,6 +283,8 @@ class lessc {
276
  foreach ($this->sortProps($block->props) as $prop) {
277
  $this->compileProp($prop, $block, $out);
278
  }
 
 
279
  }
280
 
281
  protected function sortProps($props, $split = false) {
@@ -327,6 +336,9 @@ class lessc {
327
  $parts[] = "($q[1])";
328
  }
329
  break;
 
 
 
330
  }
331
  }
332
 
@@ -434,7 +446,7 @@ class lessc {
434
  foreach ($selectors as $s) {
435
  if (is_array($s)) {
436
  list(, $value) = $s;
437
- $out[] = $this->compileValue($this->reduce($value));
438
  } else {
439
  $out[] = $s;
440
  }
@@ -447,7 +459,7 @@ class lessc {
447
  return $left == $right;
448
  }
449
 
450
- protected function patternMatch($block, $callingArgs) {
451
  // match the guards if it has them
452
  // any one of the groups must have all its guards pass for a match
453
  if (!empty($block->guards)) {
@@ -455,7 +467,7 @@ class lessc {
455
  foreach ($block->guards as $guardGroup) {
456
  foreach ($guardGroup as $guard) {
457
  $this->pushEnv();
458
- $this->zipSetArgs($block->args, $callingArgs);
459
 
460
  $negate = false;
461
  if ($guard[0] == "negate") {
@@ -484,24 +496,34 @@ class lessc {
484
  }
485
  }
486
 
487
- $numCalling = count($callingArgs);
488
-
489
  if (empty($block->args)) {
490
- return $block->isVararg || $numCalling == 0;
 
 
 
 
 
 
 
 
 
 
 
 
491
  }
492
 
493
  $i = -1; // no args
494
  // try to match by arity or by argument literal
495
- foreach ($block->args as $i => $arg) {
496
  switch ($arg[0]) {
497
  case "lit":
498
- if (empty($callingArgs[$i]) || !$this->eq($arg[1], $callingArgs[$i])) {
499
  return false;
500
  }
501
  break;
502
  case "arg":
503
  // no arg and no default value
504
- if (!isset($callingArgs[$i]) && !isset($arg[2])) {
505
  return false;
506
  }
507
  break;
@@ -516,14 +538,19 @@ class lessc {
516
  } else {
517
  $numMatched = $i + 1;
518
  // greater than becuase default values always match
519
- return $numMatched >= $numCalling;
520
  }
521
  }
522
 
523
- protected function patternMatchAll($blocks, $callingArgs) {
524
  $matches = null;
525
  foreach ($blocks as $block) {
526
- if ($this->patternMatch($block, $callingArgs)) {
 
 
 
 
 
527
  $matches[] = $block;
528
  }
529
  }
@@ -532,7 +559,7 @@ class lessc {
532
  }
533
 
534
  // attempt to find blocks matched by path and args
535
- protected function findBlocks($searchIn, $path, $args, $seen=array()) {
536
  if ($searchIn == null) return null;
537
  if (isset($seen[$searchIn->id])) return null;
538
  $seen[$searchIn->id] = true;
@@ -542,7 +569,7 @@ class lessc {
542
  if (isset($searchIn->children[$name])) {
543
  $blocks = $searchIn->children[$name];
544
  if (count($path) == 1) {
545
- $matches = $this->patternMatchAll($blocks, $args);
546
  if (!empty($matches)) {
547
  // This will return all blocks that match in the closest
548
  // scope that has any matching block, like lessjs
@@ -552,7 +579,7 @@ class lessc {
552
  $matches = array();
553
  foreach ($blocks as $subBlock) {
554
  $subMatches = $this->findBlocks($subBlock,
555
- array_slice($path, 1), $args, $seen);
556
 
557
  if (!is_null($subMatches)) {
558
  foreach ($subMatches as $sm) {
@@ -564,39 +591,51 @@ class lessc {
564
  return count($matches) > 0 ? $matches : null;
565
  }
566
  }
567
-
568
  if ($searchIn->parent === $searchIn) return null;
569
- return $this->findBlocks($searchIn->parent, $path, $args, $seen);
570
  }
571
 
572
  // sets all argument names in $args to either the default value
573
  // or the one passed in through $values
574
- protected function zipSetArgs($args, $values) {
575
- $i = 0;
576
  $assignedValues = array();
577
- foreach ($args as $a) {
 
 
578
  if ($a[0] == "arg") {
579
- if ($i < count($values) && !is_null($values[$i])) {
580
- $value = $values[$i];
 
 
 
 
 
581
  } elseif (isset($a[2])) {
 
582
  $value = $a[2];
583
- } else $value = null;
 
 
 
584
 
585
  $value = $this->reduce($value);
586
  $this->set($a[1], $value);
587
  $assignedValues[] = $value;
 
 
 
588
  }
589
- $i++;
590
  }
591
 
592
  // check for a rest
593
  $last = end($args);
594
  if ($last[0] == "rest") {
595
- $rest = array_slice($values, count($args) - 1);
596
  $this->set($last[1], $this->reduce(array("list", " ", $rest)));
597
  }
598
 
599
- $this->env->arguments = $assignedValues;
 
600
  }
601
 
602
  // compile a prop and update $lines or $blocks appropriately
@@ -621,8 +660,28 @@ class lessc {
621
  case 'mixin':
622
  list(, $path, $args, $suffix) = $prop;
623
 
624
- $args = array_map(array($this, "reduce"), (array)$args);
625
- $mixins = $this->findBlocks($block, $path, $args);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
626
 
627
  if ($mixins === null) {
628
  // fwrite(STDERR,"failed to find block: ".implode(" > ", $path)."\n");
@@ -630,6 +689,10 @@ class lessc {
630
  }
631
 
632
  foreach ($mixins as $mixin) {
 
 
 
 
633
  $haveScope = false;
634
  if (isset($mixin->parent->scope)) {
635
  $haveScope = true;
@@ -641,7 +704,7 @@ class lessc {
641
  if (isset($mixin->args)) {
642
  $haveArgs = true;
643
  $this->pushEnv();
644
- $this->zipSetArgs($mixin->args, $args);
645
  }
646
 
647
  $oldParent = $mixin->parent;
@@ -698,7 +761,9 @@ class lessc {
698
  list(,$importId) = $prop;
699
  $import = $this->env->imports[$importId];
700
  if ($import[0] === false) {
701
- $out->lines[] = $import[1];
 
 
702
  } else {
703
  list(, $bottom, $parser, $importDir) = $import;
704
  $this->compileImportedProps($bottom, $block, $out, $parser, $importDir);
@@ -786,6 +851,60 @@ class lessc {
786
  }
787
  }
788
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
789
  protected function lib_isnumber($value) {
790
  return $this->toBool($value[0] == "number");
791
  }
@@ -814,6 +933,10 @@ class lessc {
814
  return $this->toBool($value[0] == "number" && $value[2] == "em");
815
  }
816
 
 
 
 
 
817
  protected function lib_rgbahex($color) {
818
  $color = $this->coerceColor($color);
819
  if (is_null($color))
@@ -890,6 +1013,16 @@ class lessc {
890
  return array("number", round($value), $arg[2]);
891
  }
892
 
 
 
 
 
 
 
 
 
 
 
893
  /**
894
  * Helper function to get arguments for color manipulation functions.
895
  * takes a list that contains a color like thing and a percentage
@@ -996,19 +1129,24 @@ class lessc {
996
  }
997
 
998
  // mixes two colors by weight
999
- // mix(@color1, @color2, @weight);
1000
  // http://sass-lang.com/docs/yardoc/Sass/Script/Functions.html#mix-instance_method
1001
  protected function lib_mix($args) {
1002
- if ($args[0] != "list" || count($args[2]) < 3)
1003
  $this->throwError("mix expects (color1, color2, weight)");
1004
 
1005
- list($first, $second, $weight) = $args[2];
1006
  $first = $this->assertColor($first);
1007
  $second = $this->assertColor($second);
1008
 
1009
  $first_a = $this->lib_alpha($first);
1010
  $second_a = $this->lib_alpha($second);
1011
- $weight = $weight[1] / 100.0;
 
 
 
 
 
1012
 
1013
  $w = $weight * 2 - 1;
1014
  $a = $first_a - $second_a;
@@ -1029,6 +1167,25 @@ class lessc {
1029
  return $this->fixColor($new);
1030
  }
1031
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1032
  protected function assertColor($value, $error = "expected color value") {
1033
  $color = $this->coerceColor($value);
1034
  if (is_null($color)) $this->throwError($error);
@@ -1040,6 +1197,25 @@ class lessc {
1040
  $this->throwError($error);
1041
  }
1042
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1043
  protected function toHSL($color) {
1044
  if ($color[0] == 'hsl') return $color;
1045
 
@@ -1091,7 +1267,7 @@ class lessc {
1091
  * Expects H to be in range of 0 to 360, S and L in 0 to 100
1092
  */
1093
  protected function toRGB($color) {
1094
- if ($color == 'color') return $color;
1095
 
1096
  $H = $color[1] / 360;
1097
  $S = $color[2] / 100;
@@ -1179,6 +1355,18 @@ class lessc {
1179
 
1180
  protected function reduce($value, $forExpression = false) {
1181
  switch ($value[0]) {
 
 
 
 
 
 
 
 
 
 
 
 
1182
  case "variable":
1183
  $key = $value[1];
1184
  if (is_array($key)) {
@@ -1299,8 +1487,12 @@ class lessc {
1299
  case 'keyword':
1300
  $name = $value[1];
1301
  if (isset(self::$cssColors[$name])) {
1302
- list($r, $g, $b) = explode(',', self::$cssColors[$name]);
1303
- return array('color', $r, $g, $b);
 
 
 
 
1304
  }
1305
  return null;
1306
  }
@@ -1445,6 +1637,34 @@ class lessc {
1445
  return $this->fixColor($out);
1446
  }
1447
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1448
  // operator on two numbers
1449
  protected function op_number_number($op, $left, $right) {
1450
  $unit = empty($left[2]) ? $right[2] : $left[2];
@@ -1605,7 +1825,6 @@ class lessc {
1605
  $this->importDir = (array)$this->importDir;
1606
  $this->importDir[] = $pi['dirname'].'/';
1607
 
1608
- $this->allParsedFiles = array();
1609
  $this->addParsedFile($fname);
1610
 
1611
  $out = $this->compile(file_get_contents($fname), $fname);
@@ -1945,6 +2164,7 @@ class lessc {
1945
  'teal' => '0,128,128',
1946
  'thistle' => '216,191,216',
1947
  'tomato' => '255,99,71',
 
1948
  'turquoise' => '64,224,208',
1949
  'violet' => '238,130,238',
1950
  'wheat' => '245,222,179',
@@ -1988,7 +2208,7 @@ class lessc_parser {
1988
  static protected $supressDivisionProps =
1989
  array('/border-radius$/i', '/^font$/i');
1990
 
1991
- protected $blockDirectives = array("font-face", "keyframes", "page", "-moz-document");
1992
  protected $lineDirectives = array("charset");
1993
 
1994
  /**
@@ -2227,7 +2447,7 @@ class lessc_parser {
2227
 
2228
  // mixin
2229
  if ($this->mixinTags($tags) &&
2230
- ($this->argumentValues($argv) || true) &&
2231
  ($this->keyword($suffix) || true) && $this->end())
2232
  {
2233
  $tags = $this->fixTags($tags);
@@ -2519,6 +2739,9 @@ class lessc_parser {
2519
  $out = array("mediaExp", $feature);
2520
  if ($value) $out[] = $value;
2521
  return true;
 
 
 
2522
  }
2523
 
2524
  $this->seek($s);
@@ -2572,12 +2795,10 @@ class lessc_parser {
2572
  continue;
2573
  }
2574
 
2575
- if (in_array($tok, $rejectStrs)) {
2576
- $count = null;
2577
  break;
2578
  }
2579
 
2580
-
2581
  $content[] = $tok;
2582
  $this->count+= strlen($tok);
2583
  }
@@ -2652,10 +2873,10 @@ class lessc_parser {
2652
 
2653
  $s = $this->seek();
2654
  if ($this->literal("@{") &&
2655
- $this->keyword($var) &&
2656
  $this->literal("}", false))
2657
  {
2658
- $out = array("variable", $this->lessc->vPrefix . $var);
2659
  $this->eatWhiteDefault = $oldWhite;
2660
  if ($this->eatWhiteDefault) $this->whitespace();
2661
  return true;
@@ -2694,38 +2915,18 @@ class lessc_parser {
2694
  return false;
2695
  }
2696
 
2697
- // consume a list of property values delimited by ; and wrapped in ()
2698
- protected function argumentValues(&$args, $delim = ',') {
2699
- $s = $this->seek();
2700
- if (!$this->literal('(')) return false;
2701
-
2702
- $values = array();
2703
- while (true) {
2704
- if ($this->expressionList($value)) $values[] = $value;
2705
- if (!$this->literal($delim)) break;
2706
- else {
2707
- if ($value == null) $values[] = null;
2708
- $value = null;
2709
- }
2710
- }
2711
-
2712
- if (!$this->literal(')')) {
2713
- $this->seek($s);
2714
- return false;
2715
- }
2716
-
2717
- $args = $values;
2718
- return true;
2719
- }
2720
-
2721
  // consume an argument definition list surrounded by ()
2722
  // each argument is a variable name with optional value
2723
  // or at the end a ... or a variable named followed by ...
2724
- protected function argumentDef(&$args, &$isVararg, $delim = ',') {
 
 
2725
  $s = $this->seek();
2726
  if (!$this->literal('(')) return false;
2727
 
2728
  $values = array();
 
 
2729
 
2730
  $isVararg = false;
2731
  while (true) {
@@ -2734,28 +2935,77 @@ class lessc_parser {
2734
  break;
2735
  }
2736
 
2737
- if ($this->variable($vname)) {
2738
- $arg = array("arg", $vname);
2739
- $ss = $this->seek();
2740
- if ($this->assign() && $this->expressionList($value)) {
2741
- $arg[] = $value;
2742
- } else {
2743
- $this->seek($ss);
2744
- if ($this->literal("...")) {
2745
- $arg[0] = "rest";
2746
- $isVararg = true;
 
 
 
2747
  }
 
 
 
 
 
 
2748
  }
2749
- $values[] = $arg;
2750
- if ($isVararg) break;
2751
- continue;
2752
  }
2753
 
2754
- if ($this->value($literal)) {
2755
- $values[] = array("lit", $literal);
2756
- }
2757
 
2758
- if (!$this->literal($delim)) break;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2759
  }
2760
 
2761
  if (!$this->literal(')')) {
@@ -2797,70 +3047,136 @@ class lessc_parser {
2797
  }
2798
 
2799
  // a bracketed value (contained within in a tag definition)
2800
- protected function tagBracket(&$value) {
2801
  // speed shortcut
2802
  if (isset($this->buffer[$this->count]) && $this->buffer[$this->count] != "[") {
2803
  return false;
2804
  }
2805
 
2806
  $s = $this->seek();
2807
- if ($this->literal('[') && $this->to(']', $c, true) && $this->literal(']', false)) {
2808
- $value = '['.$c.']';
2809
- // whitespace?
2810
- if ($this->whitespace()) $value .= " ";
2811
 
2812
- // escape parent selector, (yuck)
2813
- $value = str_replace($this->lessc->parentSelector, "$&$", $value);
2814
- return true;
2815
- }
2816
 
2817
- $this->seek($s);
2818
- return false;
2819
- }
 
 
 
 
 
2820
 
2821
- protected function tagExpression(&$value) {
2822
- $s = $this->seek();
2823
- if ($this->literal("(") && $this->expression($exp) && $this->literal(")")) {
2824
- $value = array('exp', $exp);
2825
- return true;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2826
  }
2827
 
2828
  $this->seek($s);
2829
  return false;
2830
  }
2831
 
2832
- // a single tag
2833
  protected function tag(&$tag, $simple = false) {
2834
  if ($simple)
2835
- $chars = '^,:;{}\][>\(\) "\'';
2836
  else
2837
- $chars = '^,;{}["\'';
2838
 
2839
- if (!$simple && $this->tagExpression($tag)) {
2840
- return true;
2841
- }
2842
 
2843
- $tag = '';
2844
- while ($this->tagBracket($first)) $tag .= $first;
 
 
 
 
2845
 
2846
  while (true) {
2847
  if ($this->match('(['.$chars.'0-9]['.$chars.']*)', $m)) {
2848
- $tag .= $m[1];
2849
  if ($simple) break;
2850
 
2851
- while ($this->tagBracket($brack)) $tag .= $brack;
2852
  continue;
2853
- } elseif ($this->unit($unit)) { // for keyframes
2854
- $tag .= $unit[1] . $unit[2];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2855
  continue;
2856
  }
 
2857
  break;
2858
  }
2859
 
 
 
 
 
 
2860
 
2861
- $tag = trim($tag);
2862
- if ($tag == '') return false;
 
 
 
2863
 
 
2864
  return true;
2865
  }
2866
 
@@ -2948,7 +3264,7 @@ class lessc_parser {
2948
  protected function end() {
2949
  if ($this->literal(';')) {
2950
  return true;
2951
- } elseif ($this->count == strlen($this->buffer) || $this->buffer{$this->count} == '}') {
2952
  // if there is end of file or a closing block next then we don't need a ;
2953
  return true;
2954
  }
@@ -3212,7 +3528,7 @@ class lessc_parser {
3212
  break;
3213
  case '"':
3214
  case "'":
3215
- if (preg_match('/'.$min[0].'.*?'.$min[0].'/', $text, $m, 0, $count))
3216
  $count += strlen($m[0]) - 1;
3217
  break;
3218
  case '//':
@@ -3356,4 +3672,3 @@ class lessc_formatter_lessjs extends lessc_formatter_classic {
3356
  public $selectorSeparator = ",";
3357
  }
3358
 
3359
-
1
  <?php
2
 
3
  /**
4
+ * lessphp v0.4.0
5
  * http://leafo.net/lessphp
6
  *
7
  * LESS css compiler, adapted from http://lesscss.org
38
  * handling things like indentation.
39
  */
40
  class lessc {
41
+ static public $VERSION = "v0.4.0";
42
  static protected $TRUE = array("keyword", "true");
43
  static protected $FALSE = array("keyword", "false");
44
 
55
 
56
  protected $numberPrecision = null;
57
 
58
+ protected $allParsedFiles = array();
59
+
60
  // set to the parser that generated the current line when compiling
61
  // so we know how to create error messages
62
  protected $sourceParser = null;
105
  if (substr_compare($url, '.css', -4, 4) === 0) return false;
106
 
107
  $realPath = $this->findImport($url);
108
+
109
  if ($realPath === null) return false;
110
 
111
  if ($this->importDisabled) {
112
  return array(false, "/* import disabled */");
113
  }
114
 
115
+ if (isset($this->allParsedFiles[realpath($realPath)])) {
116
+ return array(false, null);
117
+ }
118
+
119
  $this->addParsedFile($realPath);
120
  $parser = $this->makeParser($realPath);
121
  $root = $parser->parse(file_get_contents($realPath));
283
  foreach ($this->sortProps($block->props) as $prop) {
284
  $this->compileProp($prop, $block, $out);
285
  }
286
+
287
+ $out->lines = array_values(array_unique($out->lines));
288
  }
289
 
290
  protected function sortProps($props, $split = false) {
336
  $parts[] = "($q[1])";
337
  }
338
  break;
339
+ case "variable":
340
+ $parts[] = $this->compileValue($this->reduce($q));
341
+ break;
342
  }
343
  }
344
 
446
  foreach ($selectors as $s) {
447
  if (is_array($s)) {
448
  list(, $value) = $s;
449
+ $out[] = trim($this->compileValue($this->reduce($value)));
450
  } else {
451
  $out[] = $s;
452
  }
459
  return $left == $right;
460
  }
461
 
462
+ protected function patternMatch($block, $orderedArgs, $keywordArgs) {
463
  // match the guards if it has them
464
  // any one of the groups must have all its guards pass for a match
465
  if (!empty($block->guards)) {
467
  foreach ($block->guards as $guardGroup) {
468
  foreach ($guardGroup as $guard) {
469
  $this->pushEnv();
470
+ $this->zipSetArgs($block->args, $orderedArgs, $keywordArgs);
471
 
472
  $negate = false;
473
  if ($guard[0] == "negate") {
496
  }
497
  }
498
 
 
 
499
  if (empty($block->args)) {
500
+ return $block->isVararg || empty($orderedArgs) && empty($keywordArgs);
501
+ }
502
+
503
+ $remainingArgs = $block->args;
504
+ if ($keywordArgs) {
505
+ $remainingArgs = array();
506
+ foreach ($block->args as $arg) {
507
+ if ($arg[0] == "arg" && isset($keywordArgs[$arg[1]])) {
508
+ continue;
509
+ }
510
+
511
+ $remainingArgs[] = $arg;
512
+ }
513
  }
514
 
515
  $i = -1; // no args
516
  // try to match by arity or by argument literal
517
+ foreach ($remainingArgs as $i => $arg) {
518
  switch ($arg[0]) {
519
  case "lit":
520
+ if (empty($orderedArgs[$i]) || !$this->eq($arg[1], $orderedArgs[$i])) {
521
  return false;
522
  }
523
  break;
524
  case "arg":
525
  // no arg and no default value
526
+ if (!isset($orderedArgs[$i]) && !isset($arg[2])) {
527
  return false;
528
  }
529
  break;
538
  } else {
539
  $numMatched = $i + 1;
540
  // greater than becuase default values always match
541
+ return $numMatched >= count($orderedArgs);
542
  }
543
  }
544
 
545
+ protected function patternMatchAll($blocks, $orderedArgs, $keywordArgs, $skip=array()) {
546
  $matches = null;
547
  foreach ($blocks as $block) {
548
+ // skip seen blocks that don't have arguments
549
+ if (isset($skip[$block->id]) && !isset($block->args)) {
550
+ continue;
551
+ }
552
+
553
+ if ($this->patternMatch($block, $orderedArgs, $keywordArgs)) {
554
  $matches[] = $block;
555
  }
556
  }
559
  }
560
 
561
  // attempt to find blocks matched by path and args
562
+ protected function findBlocks($searchIn, $path, $orderedArgs, $keywordArgs, $seen=array()) {
563
  if ($searchIn == null) return null;
564
  if (isset($seen[$searchIn->id])) return null;
565
  $seen[$searchIn->id] = true;
569
  if (isset($searchIn->children[$name])) {
570
  $blocks = $searchIn->children[$name];
571
  if (count($path) == 1) {
572
+ $matches = $this->patternMatchAll($blocks, $orderedArgs, $keywordArgs, $seen);
573
  if (!empty($matches)) {
574
  // This will return all blocks that match in the closest
575
  // scope that has any matching block, like lessjs
579
  $matches = array();
580
  foreach ($blocks as $subBlock) {
581
  $subMatches = $this->findBlocks($subBlock,
582
+ array_slice($path, 1), $orderedArgs, $keywordArgs, $seen);
583
 
584
  if (!is_null($subMatches)) {
585
  foreach ($subMatches as $sm) {
591
  return count($matches) > 0 ? $matches : null;
592
  }
593
  }
 
594
  if ($searchIn->parent === $searchIn) return null;
595
+ return $this->findBlocks($searchIn->parent, $path, $orderedArgs, $keywordArgs, $seen);
596
  }
597
 
598
  // sets all argument names in $args to either the default value
599
  // or the one passed in through $values
600
+ protected function zipSetArgs($args, $orderedValues, $keywordValues) {
 
601
  $assignedValues = array();
602
+
603
+ $i = 0;
604
+ foreach ($args as $a) {
605
  if ($a[0] == "arg") {
606
+ if (isset($keywordValues[$a[1]])) {
607
+ // has keyword arg
608
+ $value = $keywordValues[$a[1]];
609
+ } elseif (isset($orderedValues[$i])) {
610
+ // has ordered arg
611
+ $value = $orderedValues[$i];
612
+ $i++;
613
  } elseif (isset($a[2])) {
614
+ // has default value
615
  $value = $a[2];
616
+ } else {
617
+ $this->throwError("Failed to assign arg " . $a[1]);
618
+ $value = null; // :(
619
+ }
620
 
621
  $value = $this->reduce($value);
622
  $this->set($a[1], $value);
623
  $assignedValues[] = $value;
624
+ } else {
625
+ // a lit
626
+ $i++;
627
  }
 
628
  }
629
 
630
  // check for a rest
631
  $last = end($args);
632
  if ($last[0] == "rest") {
633
+ $rest = array_slice($orderedValues, count($args) - 1);
634
  $this->set($last[1], $this->reduce(array("list", " ", $rest)));
635
  }
636
 
637
+ // wow is this the only true use of PHP's + operator for arrays?
638
+ $this->env->arguments = $assignedValues + $orderedValues;
639
  }
640
 
641
  // compile a prop and update $lines or $blocks appropriately
660
  case 'mixin':
661
  list(, $path, $args, $suffix) = $prop;
662
 
663
+ $orderedArgs = array();
664
+ $keywordArgs = array();
665
+ foreach ((array)$args as $arg) {
666
+ $argval = null;
667
+ switch ($arg[0]) {
668
+ case "arg":
669
+ if (!isset($arg[2])) {
670
+ $orderedArgs[] = $this->reduce(array("variable", $arg[1]));
671
+ } else {
672
+ $keywordArgs[$arg[1]] = $this->reduce($arg[2]);
673
+ }
674
+ break;
675
+
676
+ case "lit":
677
+ $orderedArgs[] = $this->reduce($arg[1]);
678
+ break;
679
+ default:
680
+ $this->throwError("Unknown arg type: " . $arg[0]);
681
+ }
682
+ }
683
+
684
+ $mixins = $this->findBlocks($block, $path, $orderedArgs, $keywordArgs);
685
 
686
  if ($mixins === null) {
687
  // fwrite(STDERR,"failed to find block: ".implode(" > ", $path)."\n");
689
  }
690
 
691
  foreach ($mixins as $mixin) {
692
+ if ($mixin === $block && !$orderedArgs) {
693
+ continue;
694
+ }
695
+
696
  $haveScope = false;
697
  if (isset($mixin->parent->scope)) {
698
  $haveScope = true;
704
  if (isset($mixin->args)) {
705
  $haveArgs = true;
706
  $this->pushEnv();
707
+ $this->zipSetArgs($mixin->args, $orderedArgs, $keywordArgs);
708
  }
709
 
710
  $oldParent = $mixin->parent;
761
  list(,$importId) = $prop;
762
  $import = $this->env->imports[$importId];
763
  if ($import[0] === false) {
764
+ if (isset($import[1])) {
765
+ $out->lines[] = $import[1];
766
+ }
767
  } else {
768
  list(, $bottom, $parser, $importDir) = $import;
769
  $this->compileImportedProps($bottom, $block, $out, $parser, $importDir);
851
  }
852
  }
853
 
854
+ protected function lib_pow($args) {
855
+ list($base, $exp) = $this->assertArgs($args, 2, "pow");
856
+ return pow($this->assertNumber($base), $this->assertNumber($exp));
857
+ }
858
+
859
+ protected function lib_pi() {
860
+ return pi();
861
+ }
862
+
863
+ protected function lib_mod($args) {
864
+ list($a, $b) = $this->assertArgs($args, 2, "mod");
865
+ return $this->assertNumber($a) % $this->assertNumber($b);
866
+ }
867
+
868
+ protected function lib_tan($num) {
869
+ return tan($this->assertNumber($num));
870
+ }
871
+
872
+ protected function lib_sin($num) {
873
+ return sin($this->assertNumber($num));
874
+ }
875
+
876
+ protected function lib_cos($num) {
877
+ return cos($this->assertNumber($num));
878
+ }
879
+
880
+ protected function lib_atan($num) {
881
+ $num = atan($this->assertNumber($num));
882
+ return array("number", $num, "rad");
883
+ }
884
+
885
+ protected function lib_asin($num) {
886
+ $num = asin($this->assertNumber($num));
887
+ return array("number", $num, "rad");
888
+ }
889
+
890
+ protected function lib_acos($num) {
891
+ $num = acos($this->assertNumber($num));
892
+ return array("number", $num, "rad");
893
+ }
894
+
895
+ protected function lib_sqrt($num) {
896
+ return sqrt($this->assertNumber($num));
897
+ }
898
+
899
+ protected function lib_extract($value) {
900
+ list($list, $idx) = $this->assertArgs($value, 2, "extract");
901
+ $idx = $this->assertNumber($idx);
902
+ // 1 indexed
903
+ if ($list[0] == "list" && isset($list[2][$idx - 1])) {
904
+ return $list[2][$idx - 1];
905
+ }
906
+ }
907
+
908
  protected function lib_isnumber($value) {
909
  return $this->toBool($value[0] == "number");
910
  }
933
  return $this->toBool($value[0] == "number" && $value[2] == "em");
934
  }
935
 
936
+ protected function lib_isrem($value) {
937
+ return $this->toBool($value[0] == "number" && $value[2] == "rem");
938
+ }
939
+
940
  protected function lib_rgbahex($color) {
941
  $color = $this->coerceColor($color);
942
  if (is_null($color))
1013
  return array("number", round($value), $arg[2]);
1014
  }
1015
 
1016
+ protected function lib_unit($arg) {
1017
+ if ($arg[0] == "list") {
1018
+ list($number, $newUnit) = $arg[2];
1019
+ return array("number", $this->assertNumber($number),
1020
+ $this->compileValue($this->lib_e($newUnit)));
1021
+ } else {
1022
+ return array("number", $this->assertNumber($arg), "");
1023
+ }
1024
+ }
1025
+
1026
  /**
1027
  * Helper function to get arguments for color manipulation functions.
1028
  * takes a list that contains a color like thing and a percentage
1129
  }
1130
 
1131
  // mixes two colors by weight
1132
+ // mix(@color1, @color2, [@weight: 50%]);
1133
  // http://sass-lang.com/docs/yardoc/Sass/Script/Functions.html#mix-instance_method
1134
  protected function lib_mix($args) {
1135
+ if ($args[0] != "list" || count($args[2]) < 2)
1136
  $this->throwError("mix expects (color1, color2, weight)");
1137
 
1138
+ list($first, $second) = $args[2];
1139
  $first = $this->assertColor($first);
1140
  $second = $this->assertColor($second);
1141
 
1142
  $first_a = $this->lib_alpha($first);
1143
  $second_a = $this->lib_alpha($second);
1144
+
1145
+ if (isset($args[2][2])) {
1146
+ $weight = $args[2][2][1] / 100.0;
1147
+ } else {
1148
+ $weight = 0.5;
1149
+ }
1150
 
1151
  $w = $weight * 2 - 1;
1152
  $a = $first_a - $second_a;
1167
  return $this->fixColor($new);
1168
  }
1169
 
1170
+ protected function lib_contrast($args) {
1171
+ if ($args[0] != 'list' || count($args[2]) < 3) {
1172
+ return array(array('color', 0, 0, 0), 0);
1173
+ }
1174
+
1175
+ list($inputColor, $darkColor, $lightColor) = $args[2];
1176
+
1177
+ $inputColor = $this->assertColor($inputColor);
1178
+ $darkColor = $this->assertColor($darkColor);
1179
+ $lightColor = $this->assertColor($lightColor);
1180
+ $hsl = $this->toHSL($inputColor);
1181
+
1182
+ if ($hsl[3] > 50) {
1183
+ return $darkColor;
1184
+ }
1185
+
1186
+ return $lightColor;
1187
+ }
1188
+
1189
  protected function assertColor($value, $error = "expected color value") {
1190
  $color = $this->coerceColor($value);
1191
  if (is_null($color)) $this->throwError($error);
1197
  $this->throwError($error);
1198
  }
1199
 
1200
+ protected function assertArgs($value, $expectedArgs, $name="") {
1201
+ if ($expectedArgs == 1) {
1202
+ return $value;
1203
+ } else {
1204
+ if ($value[0] !== "list" || $value[1] != ",") $this->throwError("expecting list");
1205
+ $values = $value[2];
1206
+ $numValues = count($values);
1207
+ if ($expectedArgs != $numValues) {
1208
+ if ($name) {
1209
+ $name = $name . ": ";
1210
+ }
1211
+
1212
+ $this->throwError("${name}expecting $expectedArgs arguments, got $numValues");
1213
+ }
1214
+
1215
+ return $values;
1216
+ }
1217
+ }
1218
+
1219
  protected function toHSL($color) {
1220
  if ($color[0] == 'hsl') return $color;
1221
 
1267
  * Expects H to be in range of 0 to 360, S and L in 0 to 100
1268
  */
1269
  protected function toRGB($color) {
1270
+ if ($color[0] == 'color') return $color;
1271
 
1272
  $H = $color[1] / 360;
1273
  $S = $color[2] / 100;
1355
 
1356
  protected function reduce($value, $forExpression = false) {
1357
  switch ($value[0]) {
1358
+ case "interpolate":
1359
+ $reduced = $this->reduce($value[1]);
1360
+ $var = $this->compileValue($reduced);
1361
+ $res = $this->reduce(array("variable", $this->vPrefix . $var));
1362
+
1363
+ if ($res[0] == "raw_color") {
1364
+ $res = $this->coerceColor($res);
1365
+ }
1366
+
1367
+ if (empty($value[2])) $res = $this->lib_e($res);
1368
+
1369
+ return $res;
1370
  case "variable":
1371
  $key = $value[1];
1372
  if (is_array($key)) {
1487
  case 'keyword':
1488
  $name = $value[1];
1489
  if (isset(self::$cssColors[$name])) {
1490
+ $rgba = explode(',', self::$cssColors[$name]);
1491
+
1492
+ if(isset($rgba[3]))
1493
+ return array('color', $rgba[0], $rgba[1], $rgba[2], $rgba[3]);
1494
+
1495
+ return array('color', $rgba[0], $rgba[1], $rgba[2]);
1496
  }
1497
  return null;
1498
  }
1637
  return $this->fixColor($out);
1638
  }
1639
 
1640
+ function lib_red($color){
1641
+ $color = $this->coerceColor($color);
1642
+ if (is_null($color)) {
1643
+ $this->throwError('color expected for red()');
1644
+ }
1645
+
1646
+ return $color[1];
1647
+ }
1648
+
1649
+ function lib_green($color){
1650
+ $color = $this->coerceColor($color);
1651
+ if (is_null($color)) {
1652
+ $this->throwError('color expected for green()');
1653
+ }
1654
+
1655
+ return $color[2];
1656
+ }
1657
+
1658
+ function lib_blue($color){
1659
+ $color = $this->coerceColor($color);
1660
+ if (is_null($color)) {
1661
+ $this->throwError('color expected for blue()');
1662
+ }
1663
+
1664
+ return $color[3];
1665
+ }
1666
+
1667
+
1668
  // operator on two numbers
1669
  protected function op_number_number($op, $left, $right) {
1670
  $unit = empty($left[2]) ? $right[2] : $left[2];
1825
  $this->importDir = (array)$this->importDir;
1826
  $this->importDir[] = $pi['dirname'].'/';
1827
 
 
1828
  $this->addParsedFile($fname);
1829
 
1830
  $out = $this->compile(file_get_contents($fname), $fname);
2164
  'teal' => '0,128,128',
2165
  'thistle' => '216,191,216',
2166
  'tomato' => '255,99,71',
2167
+ 'transparent' => '0,0,0,0',
2168
  'turquoise' => '64,224,208',
2169
  'violet' => '238,130,238',
2170
  'wheat' => '245,222,179',
2208
  static protected $supressDivisionProps =
2209
  array('/border-radius$/i', '/^font$/i');
2210
 
2211
+ protected $blockDirectives = array("font-face", "keyframes", "page", "-moz-document", "viewport", "-moz-viewport", "-o-viewport", "-ms-viewport");
2212
  protected $lineDirectives = array("charset");
2213
 
2214
  /**
2447
 
2448
  // mixin
2449
  if ($this->mixinTags($tags) &&
2450
+ ($this->argumentDef($argv, $isVararg) || true) &&
2451
  ($this->keyword($suffix) || true) && $this->end())
2452
  {
2453
  $tags = $this->fixTags($tags);
2739
  $out = array("mediaExp", $feature);
2740
  if ($value) $out[] = $value;
2741
  return true;
2742
+ } elseif ($this->variable($variable)) {
2743
+ $out = array('variable', $variable);
2744
+ return true;
2745
  }
2746
 
2747
  $this->seek($s);
2795
  continue;
2796
  }
2797
 
2798
+ if (!empty($rejectStrs) && in_array($tok, $rejectStrs)) {
 
2799
  break;
2800
  }
2801
 
 
2802
  $content[] = $tok;
2803
  $this->count+= strlen($tok);
2804
  }
2873
 
2874
  $s = $this->seek();
2875
  if ($this->literal("@{") &&
2876
+ $this->openString("}", $interp, null, array("'", '"', ";")) &&
2877
  $this->literal("}", false))
2878
  {
2879
+ $out = array("interpolate", $interp);
2880
  $this->eatWhiteDefault = $oldWhite;
2881
  if ($this->eatWhiteDefault) $this->whitespace();
2882
  return true;
2915
  return false;
2916
  }
2917
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2918
  // consume an argument definition list surrounded by ()
2919
  // each argument is a variable name with optional value
2920
  // or at the end a ... or a variable named followed by ...
2921
+ // arguments are separated by , unless a ; is in the list, then ; is the
2922
+ // delimiter.
2923
+ protected function argumentDef(&$args, &$isVararg) {
2924
  $s = $this->seek();
2925
  if (!$this->literal('(')) return false;
2926
 
2927
  $values = array();
2928
+ $delim = ",";
2929
+ $method = "expressionList";
2930
 
2931
  $isVararg = false;
2932
  while (true) {
2935
  break;
2936
  }
2937
 
2938
+ if ($this->$method($value)) {
2939
+ if ($value[0] == "variable") {
2940
+ $arg = array("arg", $value[1]);
2941
+ $ss = $this->seek();
2942
+
2943
+ if ($this->assign() && $this->$method($rhs)) {
2944
+ $arg[] = $rhs;
2945
+ } else {
2946
+ $this->seek($ss);
2947
+ if ($this->literal("...")) {
2948
+ $arg[0] = "rest";
2949
+ $isVararg = true;
2950
+ }
2951
  }
2952
+
2953
+ $values[] = $arg;
2954
+ if ($isVararg) break;
2955
+ continue;
2956
+ } else {
2957
+ $values[] = array("lit", $value);
2958
  }
 
 
 
2959
  }
2960
 
 
 
 
2961
 
2962
+ if (!$this->literal($delim)) {
2963
+ if ($delim == "," && $this->literal(";")) {
2964
+ // found new delim, convert existing args
2965
+ $delim = ";";
2966
+ $method = "propertyValue";
2967
+
2968
+ // transform arg list
2969
+ if (isset($values[1])) { // 2 items
2970
+ $newList = array();
2971
+ foreach ($values as $i => $arg) {
2972
+ switch($arg[0]) {
2973
+ case "arg":
2974
+ if ($i) {
2975
+ $this->throwError("Cannot mix ; and , as delimiter types");
2976
+ }
2977
+ $newList[] = $arg[2];
2978
+ break;
2979
+ case "lit":
2980
+ $newList[] = $arg[1];
2981
+ break;
2982
+ case "rest":
2983
+ $this->throwError("Unexpected rest before semicolon");
2984
+ }
2985
+ }
2986
+
2987
+ $newList = array("list", ", ", $newList);
2988
+
2989
+ switch ($values[0][0]) {
2990
+ case "arg":
2991
+ $newArg = array("arg", $values[0][1], $newList);
2992
+ break;
2993
+ case "lit":
2994
+ $newArg = array("lit", $newList);
2995
+ break;
2996
+ }
2997
+
2998
+ } elseif ($values) { // 1 item
2999
+ $newArg = $values[0];
3000
+ }
3001
+
3002
+ if ($newArg) {
3003
+ $values = array($newArg);
3004
+ }
3005
+ } else {
3006
+ break;
3007
+ }
3008
+ }
3009
  }
3010
 
3011
  if (!$this->literal(')')) {
3047
  }
3048
 
3049
  // a bracketed value (contained within in a tag definition)
3050
+ protected function tagBracket(&$parts, &$hasExpression) {
3051
  // speed shortcut
3052
  if (isset($this->buffer[$this->count]) && $this->buffer[$this->count] != "[") {
3053
  return false;
3054
  }
3055
 
3056
  $s = $this->seek();
 
 
 
 
3057
 
3058
+ $hasInterpolation = false;
 
 
 
3059
 
3060
+ if ($this->literal("[", false)) {
3061
+ $attrParts = array("[");
3062
+ // keyword, string, operator
3063
+ while (true) {
3064
+ if ($this->literal("]", false)) {
3065
+ $this->count--;
3066
+ break; // get out early
3067
+ }
3068
 
3069
+ if ($this->match('\s+', $m)) {
3070
+ $attrParts[] = " ";
3071
+ continue;
3072
+ }
3073
+ if ($this->string($str)) {
3074
+ // escape parent selector, (yuck)
3075
+ foreach ($str[2] as &$chunk) {
3076
+ $chunk = str_replace($this->lessc->parentSelector, "$&$", $chunk);
3077
+ }
3078
+
3079
+ $attrParts[] = $str;
3080
+ $hasInterpolation = true;
3081
+ continue;
3082
+ }
3083
+
3084
+ if ($this->keyword($word)) {
3085
+ $attrParts[] = $word;
3086
+ continue;
3087
+ }
3088
+
3089
+ if ($this->interpolation($inter, false)) {
3090
+ $attrParts[] = $inter;
3091
+ $hasInterpolation = true;
3092
+ continue;
3093
+ }
3094
+
3095
+ // operator, handles attr namespace too
3096
+ if ($this->match('[|-~\$\*\^=]+', $m)) {
3097
+ $attrParts[] = $m[0];
3098
+ continue;
3099
+ }
3100
+
3101
+ break;
3102
+ }
3103
+
3104
+ if ($this->literal("]", false)) {
3105
+ $attrParts[] = "]";
3106
+ foreach ($attrParts as $part) {
3107
+ $parts[] = $part;
3108
+ }
3109
+ $hasExpression = $hasExpression || $hasInterpolation;
3110
+ return true;
3111
+ }
3112
+ $this->seek($s);
3113
  }
3114
 
3115
  $this->seek($s);
3116
  return false;
3117
  }
3118
 
3119
+ // a space separated list of selectors
3120
  protected function tag(&$tag, $simple = false) {
3121
  if ($simple)
3122
+ $chars = '^@,:;{}\][>\(\) "\'';
3123
  else
3124
+ $chars = '^@,;{}["\'';
3125
 
3126
+ $s = $this->seek();
 
 
3127
 
3128
+ $hasExpression = false;
3129
+ $parts = array();
3130
+ while ($this->tagBracket($parts, $hasExpression));
3131
+
3132
+ $oldWhite = $this->eatWhiteDefault;
3133
+ $this->eatWhiteDefault = false;
3134
 
3135
  while (true) {
3136
  if ($this->match('(['.$chars.'0-9]['.$chars.']*)', $m)) {
3137
+ $parts[] = $m[1];
3138
  if ($simple) break;
3139
 
3140
+ while ($this->tagBracket($parts, $hasExpression));
3141
  continue;
3142
+ }
3143
+
3144
+ if (isset($this->buffer[$this->count]) && $this->buffer[$this->count] == "@") {
3145
+ if ($this->interpolation($interp)) {
3146
+ $hasExpression = true;
3147
+ $interp[2] = true; // don't unescape
3148
+ $parts[] = $interp;
3149
+ continue;
3150
+ }
3151
+
3152
+ if ($this->literal("@")) {
3153
+ $parts[] = "@";
3154
+ continue;
3155
+ }
3156
+ }
3157
+
3158
+ if ($this->unit($unit)) { // for keyframes
3159
+ $parts[] = $unit[1];
3160
+ $parts[] = $unit[2];
3161
  continue;
3162
  }
3163
+
3164
  break;
3165
  }
3166
 
3167
+ $this->eatWhiteDefault = $oldWhite;
3168
+ if (!$parts) {
3169
+ $this->seek($s);
3170
+ return false;
3171
+ }
3172
 
3173
+ if ($hasExpression) {
3174
+ $tag = array("exp", array("string", "", $parts));
3175
+ } else {
3176
+ $tag = trim(implode($parts));
3177
+ }
3178
 
3179
+ $this->whitespace();
3180
  return true;
3181
  }
3182
 
3264
  protected function end() {
3265
  if ($this->literal(';')) {
3266
  return true;
3267
+ } elseif ($this->count == strlen($this->buffer) || $this->buffer[$this->count] == '}') {
3268
  // if there is end of file or a closing block next then we don't need a ;
3269
  return true;
3270
  }
3528
  break;
3529
  case '"':
3530
  case "'":
3531
+ if (preg_match('/'.$min[0].'.*?(?<!\\\\)'.$min[0].'/', $text, $m, 0, $count))
3532
  $count += strlen($m[0]) - 1;
3533
  break;
3534
  case '//':
3672
  public $selectorSeparator = ",";
3673
  }
3674
 
 
modules/custom-css/custom-css/preprocessors/scss.inc.php CHANGED
@@ -1,7 +1,49 @@
1
  <?php
2
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  class scssc {
4
- static public $VERSION = "v0.0.4";
5
 
6
  static protected $operatorNames = array(
7
  '+' => "add",
@@ -25,7 +67,7 @@ class scssc {
25
  "function" => "^",
26
  );
27
 
28
- static protected $numberPrecision = 3;
29
  static protected $unitTable = array(
30
  "in" => array(
31
  "in" => 1,
@@ -39,6 +81,7 @@ class scssc {
39
 
40
  static public $true = array("keyword", "true");
41
  static public $false = array("keyword", "false");
 
42
 
43
  static public $defaultValue = array("keyword", "");
44
  static public $selfSelector = array("self");
@@ -69,17 +112,28 @@ class scssc {
69
  $this->scope = null;
70
 
71
  $this->compileRoot($tree);
72
- $this->flattenSelectors($this->scope);
73
 
74
- ob_start();
75
- $this->formatter->block($this->scope);
76
- $out = ob_get_clean();
77
 
78
  setlocale(LC_NUMERIC, $locale);
79
  return $out;
80
  }
81
 
 
 
 
 
 
 
 
 
 
 
82
  protected function pushExtends($target, $origin) {
 
 
 
 
83
  $i = count($this->extends);
84
  $this->extends[] = array($target, $origin);
85
 
@@ -93,7 +147,7 @@ class scssc {
93
  }
94
 
95
  protected function makeOutputBlock($type, $selectors = null) {
96
- $out = new stdclass;
97
  $out->type = $type;
98
  $out->lines = array();
99
  $out->children = array();
@@ -104,7 +158,7 @@ class scssc {
104
  return $out;
105
  }
106
 
107
- protected function matchExtendsSingle($single, &$out_origin, &$out_rem) {
108
  $counts = array();
109
  foreach ($single as $part) {
110
  if (!is_string($part)) return false; // hmm
@@ -117,20 +171,30 @@ class scssc {
117
  }
118
  }
119
 
 
 
 
120
  foreach ($counts as $idx => $count) {
121
  list($target, $origin) = $this->extends[$idx];
 
122
  // check count
123
  if ($count != count($target)) continue;
 
124
  // check if target is subset of single
125
  if (array_diff(array_intersect($single, $target), $target)) continue;
126
 
127
- $out_origin = $origin;
128
- $out_rem = array_diff($single, $target);
129
 
130
- return true;
 
 
 
 
 
 
131
  }
132
 
133
- return false;
134
  }
135
 
136
  protected function combineSelectorSingle($base, $other) {
@@ -139,7 +203,7 @@ class scssc {
139
 
140
  foreach (array($base, $other) as $single) {
141
  foreach ($single as $part) {
142
- if (preg_match('/^[^.#:]/', $part)) {
143
  $tag = $part;
144
  } else {
145
  $out[] = $part;
@@ -158,15 +222,13 @@ class scssc {
158
  foreach ($selector as $i => $part) {
159
  if ($i < $from) continue;
160
 
161
- if ($this->matchExtendsSingle($part, $origin, $rem)) {
162
  $before = array_slice($selector, 0, $i);
163
  $after = array_slice($selector, $i + 1);
164
 
165
  foreach ($origin as $new) {
166
- $new[count($new) - 1] =
167
- $this->combineSelectorSingle(end($new), $rem);
168
-
169
  $k = 0;
 
170
  // remove shared parts
171
  if ($initial) {
172
  foreach ($before as $k => $val) {
@@ -203,7 +265,7 @@ class scssc {
203
  }
204
  }
205
 
206
- protected function flattenSelectors($block) {
207
  if ($block->selectors) {
208
  $selectors = array();
209
  foreach ($block->selectors as $s) {
@@ -215,19 +277,34 @@ class scssc {
215
  }
216
  }
217
 
218
- $selectors = array_map(array($this, "compileSelector"), $selectors);
219
- $block->selectors = $selectors;
 
 
 
 
 
 
 
 
 
 
 
 
220
  }
221
 
222
- foreach ($block->children as $child) {
223
- $this->flattenSelectors($child);
224
  }
225
  }
226
 
227
  protected function compileRoot($rootBlock) {
228
  $this->pushEnv($rootBlock);
229
  $this->scope = $this->makeOutputBlock("root");
 
230
  $this->compileChildren($rootBlock->children, $this->scope);
 
 
231
  $this->popEnv();
232
  }
233
 
@@ -241,6 +318,24 @@ class scssc {
241
 
242
  $parentScope->children[] = $this->scope;
243
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
244
  $this->compileChildren($media->children, $this->scope);
245
 
246
  $this->scope = $this->scope->parent;
@@ -270,6 +365,24 @@ class scssc {
270
  $this->popEnv();
271
  }
272
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
273
  protected function compileBlock($block) {
274
  $env = $this->pushEnv($block);
275
 
@@ -289,7 +402,7 @@ class scssc {
289
  foreach ($single as $part) {
290
  if (empty($joined) ||
291
  !is_string($part) ||
292
- preg_match('/[.:#]/', $part))
293
  {
294
  $joined[] = $part;
295
  continue;
@@ -318,6 +431,9 @@ class scssc {
318
  case "interpolate":
319
  $p = $this->compileValue($p);
320
  break;
 
 
 
321
  }
322
  }
323
 
@@ -350,6 +466,21 @@ class scssc {
350
  return implode($piece);
351
  }
352
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
353
  protected function compileChildren($stms, $out) {
354
  foreach ($stms as $stm) {
355
  $ret = $this->compileChild($stm, $out);
@@ -365,13 +496,13 @@ class scssc {
365
  foreach ($query as $q) {
366
  switch ($q[0]) {
367
  case "mediaType":
368
- $parts[] = implode(" ", array_slice($q, 1));
369
  break;
370
  case "mediaExp":
371
  if (isset($q[2])) {
372
- $parts[] = "($q[1]" . $this->formatter->assignSeparator . $this->compileValue($q[2]) . ")";
373
  } else {
374
- $parts[] = "($q[1])";
375
  }
376
  break;
377
  }
@@ -398,7 +529,8 @@ class scssc {
398
  return true;
399
  }
400
  return false;
401
- } if ($rawPath[0] == "list") {
 
402
  // handle a list of strings
403
  if (count($rawPath[2]) == 0) return false;
404
  foreach ($rawPath[2] as $path) {
@@ -417,6 +549,9 @@ class scssc {
417
 
418
  // return a value to halt execution
419
  protected function compileChild($child, $out) {
 
 
 
420
  switch ($child[0]) {
421
  case "import":
422
  list(,$rawPath) = $child;
@@ -446,15 +581,31 @@ class scssc {
446
  list(,$name, $value) = $child;
447
  if ($name[0] == "var") {
448
  $isDefault = !empty($child[3]);
449
- if (!$isDefault || $this->get($name[1], true) === true) {
 
 
 
 
 
 
450
  $this->set($name[1], $this->reduce($value));
451
  }
452
  break;
453
  }
454
 
 
 
 
 
 
 
 
 
 
 
455
  $out->lines[] = $this->formatter->property(
456
- $this->compileValue($child[1]),
457
- $this->compileValue($child[2]));
458
  break;
459
  case "comment":
460
  $out->lines[] = $child[1];
@@ -474,12 +625,12 @@ class scssc {
474
  break;
475
  case "if":
476
  list(, $if) = $child;
477
- if ($this->reduce($if->cond, true) != self::$false) {
478
  return $this->compileChildren($if->children, $out);
479
  } else {
480
  foreach ($if->cases as $case) {
481
  if ($case->type == "else" ||
482
- $case->type == "elseif" && ($this->reduce($case->cond) != self::$false))
483
  {
484
  return $this->compileChildren($case->children, $out);
485
  }
@@ -490,7 +641,7 @@ class scssc {
490
  return $this->reduce($child[1], true);
491
  case "each":
492
  list(,$each) = $child;
493
- $list = $this->reduce($this->coerceList($each->list));
494
  foreach ($list[2] as $item) {
495
  $this->pushEnv();
496
  $this->set($each->var, $item);
@@ -501,7 +652,7 @@ class scssc {
501
  break;
502
  case "while":
503
  list(,$while) = $child;
504
- while ($this->reduce($while->cond, true) != self::$false) {
505
  $ret = $this->compileChildren($while->children, $out);
506
  if ($ret) return $ret;
507
  }
@@ -547,12 +698,17 @@ class scssc {
547
  case "include": // including a mixin
548
  list(,$name, $argValues, $content) = $child;
549
  $mixin = $this->get(self::$namespaces["mixin"] . $name, false);
550
- if (!$mixin) break; // throw error?
 
 
551
 
552
  $callingScope = $this->env;
553
 
554
  // push scope, apply args
555
  $this->pushEnv();
 
 
 
556
 
557
  if (!is_null($content)) {
558
  $content->scope = $callingScope;
@@ -573,12 +729,14 @@ class scssc {
573
  case "mixin_content":
574
  $content = $this->get(self::$namespaces["special"] . "content");
575
  if (is_null($content)) {
576
- throw new \Exception("Unexpected @content inside of mixin");
577
  }
578
 
579
- $this->storeEnv = $content->scope;
580
-
581
  foreach ($content->children as $child) {
 
 
 
 
582
  $this->compileChild($child, $out);
583
  }
584
 
@@ -591,20 +749,24 @@ class scssc {
591
  fwrite(STDERR, "Line $line DEBUG: $value\n");
592
  break;
593
  default:
594
- throw new exception("unknown child type: $child[0]");
595
  }
596
  }
597
 
598
  protected function expToString($exp) {
599
  list(, $op, $left, $right, $inParens, $whiteLeft, $whiteRight) = $exp;
600
- $content = array($left);
601
  if ($whiteLeft) $content[] = " ";
602
  $content[] = $op;
603
  if ($whiteRight) $content[] = " ";
604
- $content[] = $right;
605
  return array("string", "", $content);
606
  }
607
 
 
 
 
 
608
  // should $value cause its operand to eval
609
  protected function shouldEval($value) {
610
  switch ($value[0]) {
@@ -662,7 +824,7 @@ class scssc {
662
  $left[0] == "number" && $right[0] == "number")
663
  {
664
  if ($opName == "mod" && $right[2] != "") {
665
- throw new \Exception(sprintf('Cannot modulo by a number with units: %s%s.', $right[1], $right[2]));
666
  }
667
 
668
  $unitChange = true;
@@ -796,6 +958,27 @@ class scssc {
796
  }
797
  }
798
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
799
  // just does physical lengths for now
800
  protected function normalizeNumber($number) {
801
  list(, $value, $unit) = $number;
@@ -887,12 +1070,16 @@ class scssc {
887
  break;
888
  case '/':
889
  if ($rval == 0) {
890
- throw new exception("color: Can't divide by zero");
891
  }
892
  $out[] = $lval / $rval;
893
  break;
 
 
 
 
894
  default:
895
- throw new exception("color: unknow op $op");
896
  }
897
  }
898
 
@@ -948,6 +1135,19 @@ class scssc {
948
  return $thing ? self::$true : self::$false;
949
  }
950
 
 
 
 
 
 
 
 
 
 
 
 
 
 
951
  protected function compileValue($value) {
952
  $value = $this->reduce($value);
953
 
@@ -990,10 +1190,14 @@ class scssc {
990
  if ($value[0] != "list") return $this->compileValue($value);
991
 
992
  list(, $delim, $items) = $value;
993
- foreach ($items as &$item) {
994
- $item = $this->compileValue($item);
 
 
 
995
  }
996
- return implode("$delim ", $items);
 
997
  case "interpolated": # node created by extractInterpolation
998
  list(, $interpolate, $left, $right) = $value;
999
  list(,, $whiteLeft, $whiteRight) = $interpolate;
@@ -1011,14 +1215,20 @@ class scssc {
1011
 
1012
  // strip quotes if it's a string
1013
  $reduced = $this->reduce($exp);
1014
- if ($reduced[0] == "string") {
1015
- $reduced = array("keyword",
1016
- $this->compileStringContent($reduced));
 
 
 
 
1017
  }
1018
 
1019
  return $this->compileValue($reduced);
 
 
1020
  default:
1021
- throw new exception("unknown value type: $type");
1022
  }
1023
  }
1024
 
@@ -1049,28 +1259,28 @@ class scssc {
1049
  }
1050
 
1051
  // find the final set of selectors
1052
- protected function multiplySelectors($env, $childSelectors = null) {
1053
- if (is_null($env)) {
1054
- return $childSelectors;
1055
- }
1056
-
1057
- // skip env, has no selectors
1058
- if (empty($env->selectors)) {
1059
- return $this->multiplySelectors($env->parent, $childSelectors);
1060
- }
1061
 
1062
- if (is_null($childSelectors)) {
1063
- $selectors = $env->selectors;
1064
- } else {
1065
  $selectors = array();
1066
- foreach ($env->selectors as $parent) {
1067
- foreach ($childSelectors as $child) {
1068
- $selectors[] = $this->joinSelectors($parent, $child);
1069
  }
1070
  }
 
1071
  }
1072
 
1073
- return $this->multiplySelectors($env->parent, $selectors);
1074
  }
1075
 
1076
  // looks for & to replace, or append parent before child
@@ -1142,31 +1352,69 @@ class scssc {
1142
  }
1143
 
1144
  protected function applyArguments($argDef, $argValues) {
1145
- $argValues = (array)$argValues;
 
 
 
 
 
 
1146
 
1147
  $keywordArgs = array();
 
1148
  $remaining = array();
1149
-
1150
  // assign the keyword args
1151
- foreach ($argValues as $arg) {
1152
  if (!empty($arg[0])) {
1153
- $keywordArgs[$arg[0][1]] = $arg[1];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1154
  } else {
1155
  $remaining[] = $arg[1];
1156
  }
1157
  }
1158
 
1159
- foreach ($argDef as $i => $arg) {
1160
- list($name, $default) = $arg;
1161
-
1162
- if (isset($remaining[$i])) {
 
 
 
 
 
 
 
1163
  $val = $remaining[$i];
1164
  } elseif (isset($keywordArgs[$name])) {
1165
  $val = $keywordArgs[$name];
1166
  } elseif (!empty($default)) {
1167
  $val = $default;
1168
  } else {
1169
- $val = self::$defaultValue;
1170
  }
1171
 
1172
  $this->set($name, $this->reduce($val, true), true);
@@ -1174,7 +1422,7 @@ class scssc {
1174
  }
1175
 
1176
  protected function pushEnv($block=null) {
1177
- $env = new stdclass;
1178
  $env->parent = $this->env;
1179
  $env->store = array();
1180
  $env->block = $block;
@@ -1194,6 +1442,7 @@ class scssc {
1194
 
1195
  protected function set($name, $value, $shadow=false) {
1196
  $name = $this->normalizeName($name);
 
1197
  if ($shadow) {
1198
  $this->setRaw($name, $value);
1199
  } else {
@@ -1226,7 +1475,7 @@ class scssc {
1226
 
1227
  if (isset($env->store[$name])) {
1228
  return $env->store[$name];
1229
- } elseif (!is_null($env->parent)) {
1230
  return $this->get($name, $defaultValue, $env->parent);
1231
  }
1232
 
@@ -1270,7 +1519,7 @@ class scssc {
1270
  $tree = $this->importCache[$realPath];
1271
  } else {
1272
  $code = file_get_contents($path);
1273
- $parser = new scss_parser($path);
1274
  $tree = $parser->parse($code);
1275
  $this->parsedFiles[] = $path;
1276
 
@@ -1336,7 +1585,7 @@ class scssc {
1336
  $val = $this->reduce($val, true);
1337
  }
1338
  $returnValue = call_user_func($f, $sorted, $this);
1339
- } else if (isset($this->userFunctions[$name])) {
1340
  // see if we can find a user function
1341
  $fn = $this->userFunctions[$name];
1342
 
@@ -1420,7 +1669,7 @@ class scssc {
1420
  $name = $value[1];
1421
  if (isset(self::$cssColors[$name])) {
1422
  list($r, $g, $b) = explode(',', self::$cssColors[$name]);
1423
- return array('color', $r, $g, $b);
1424
  }
1425
  return null;
1426
  }
@@ -1438,14 +1687,20 @@ class scssc {
1438
  return null;
1439
  }
1440
 
 
 
 
 
 
 
1441
  protected function assertColor($value) {
1442
  if ($color = $this->coerceColor($value)) return $color;
1443
- throw new exception("expecting color");
1444
  }
1445
 
1446
  protected function assertNumber($value) {
1447
  if ($value[0] != "number")
1448
- throw new exception("expecting number");
1449
  return $value[1];
1450
  }
1451
 
@@ -1469,74 +1724,71 @@ class scssc {
1469
  return $c;
1470
  }
1471
 
1472
- function toHSL($r, $g, $b) {
1473
- $r = $r / 255;
1474
- $g = $g / 255;
1475
- $b = $b / 255;
1476
 
1477
  $min = min($r, $g, $b);
1478
  $max = max($r, $g, $b);
 
 
1479
 
1480
- $L = ($min + $max) / 2;
1481
  if ($min == $max) {
1482
- $S = $H = 0;
1483
  } else {
1484
- if ($L < 0.5)
1485
- $S = ($max - $min)/($max + $min);
1486
  else
1487
- $S = ($max - $min)/(2.0 - $max - $min);
1488
-
1489
- if ($r == $max) $H = ($g - $b)/($max - $min);
1490
- elseif ($g == $max) $H = 2.0 + ($b - $r)/($max - $min);
1491
- elseif ($b == $max) $H = 4.0 + ($r - $g)/($max - $min);
1492
 
 
 
 
 
 
 
1493
  }
1494
 
1495
- return array('hsl',
1496
- ($H < 0 ? $H + 6 : $H)*60,
1497
- $S*100,
1498
- $L*100,
1499
- );
1500
  }
1501
 
1502
- function toRGB_helper($comp, $temp1, $temp2) {
1503
- if ($comp < 0) $comp += 1.0;
1504
- elseif ($comp > 1) $comp -= 1.0;
 
 
1505
 
1506
- if (6 * $comp < 1) return $temp1 + ($temp2 - $temp1) * 6 * $comp;
1507
- if (2 * $comp < 1) return $temp2;
1508
- if (3 * $comp < 2) return $temp1 + ($temp2 - $temp1)*((2/3) - $comp) * 6;
1509
 
1510
- return $temp1;
1511
- }
1512
 
1513
- // H from 0 to 360, S and L from 0 to 100
1514
- function toRGB($H, $S, $L) {
1515
- $H = $H % 360;
1516
- if ($H < 0) $H += 360;
1517
 
1518
- $S = min(100, max(0, $S));
1519
- $L = min(100, max(0, $L));
1520
 
1521
- $H = $H / 360;
1522
- $S = $S / 100;
1523
- $L = $L / 100;
 
 
1524
 
1525
- if ($S == 0) {
1526
- $r = $g = $b = $L;
1527
- } else {
1528
- $temp2 = $L < 0.5 ?
1529
- $L*(1.0 + $S) :
1530
- $L + $S - $L * $S;
1531
 
1532
- $temp1 = 2.0 * $L - $temp2;
 
1533
 
1534
- $r = $this->toRGB_helper($H + 1/3, $temp1, $temp2);
1535
- $g = $this->toRGB_helper($H, $temp1, $temp2);
1536
- $b = $this->toRGB_helper($H - 1/3, $temp1, $temp2);
1537
- }
1538
 
1539
- $out = array('color', $r*255, $g*255, $b*255);
1540
  return $out;
1541
  }
1542
 
@@ -1549,6 +1801,20 @@ class scssc {
1549
  return $t;
1550
  }
1551
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1552
  protected static $lib_rgb = array("red", "green", "blue");
1553
  protected function lib_rgb($args) {
1554
  list($r,$g,$b) = $args;
@@ -1687,11 +1953,13 @@ class scssc {
1687
  }
1688
 
1689
  // this might be the IE function, so return value unchanged
1690
- return array("function", "alpha", array("list", ",", $args));
1691
  }
1692
 
1693
  protected static $lib_opacity = array("color");
1694
  protected function lib_opacity($args) {
 
 
1695
  return $this->lib_alpha($args);
1696
  }
1697
 
@@ -1708,11 +1976,11 @@ class scssc {
1708
  $weight = $this->coercePercent($weight);
1709
  }
1710
 
1711
- $first_a = isset($first[4]) ? $first[4] : 1;
1712
- $second_a = isset($second[4]) ? $second[4] : 1;
1713
 
1714
  $w = $weight * 2 - 1;
1715
- $a = $first_a - $second_a;
1716
 
1717
  $w1 = (($w * $a == -1 ? $w : ($w + $a)/(1 + $w * $a)) + 1) / 2.0;
1718
  $w2 = 1.0 - $w1;
@@ -1723,8 +1991,8 @@ class scssc {
1723
  $w1 * $first[3] + $w2 * $second[3],
1724
  );
1725
 
1726
- if ($first_a != 1.0 || $second_a != 1.0) {
1727
- $new[] = $first_a * $weight + $second_a * ($weight - 1);
1728
  }
1729
 
1730
  return $this->fixColor($new);
@@ -1766,7 +2034,6 @@ class scssc {
1766
  return array("number", $hsl[3], "%");
1767
  }
1768
 
1769
-
1770
  protected function adjustHsl($color, $idx, $amount) {
1771
  $hsl = $this->toHSL($color[1], $color[2], $color[3]);
1772
  $hsl[$idx] += $amount;
@@ -1798,7 +2065,9 @@ class scssc {
1798
 
1799
  protected static $lib_saturate = array("color", "amount");
1800
  protected function lib_saturate($args) {
1801
- $color = $this->assertColor($args[0]);
 
 
1802
  $amount = 100*$this->coercePercent($args[1]);
1803
  return $this->adjustHsl($color, 2, $amount);
1804
  }
@@ -1812,7 +2081,9 @@ class scssc {
1812
 
1813
  protected static $lib_grayscale = array("color");
1814
  protected function lib_grayscale($args) {
1815
- return $this->adjustHsl($this->assertColor($args[0]), 2, -100);
 
 
1816
  }
1817
 
1818
  protected static $lib_complement = array("color");
@@ -1822,14 +2093,15 @@ class scssc {
1822
 
1823
  protected static $lib_invert = array("color");
1824
  protected function lib_invert($args) {
1825
- $color = $this->assertColor($args[0]);
 
 
1826
  $color[1] = 255 - $color[1];
1827
  $color[2] = 255 - $color[2];
1828
  $color[3] = 255 - $color[3];
1829
  return $color;
1830
  }
1831
 
1832
-
1833
  // increases opacity by amount
1834
  protected static $lib_opacify = array("color", "amount");
1835
  protected function lib_opacify($args) {
@@ -1942,14 +2214,14 @@ class scssc {
1942
  $numbers = array();
1943
  foreach ($args as $key => $item) {
1944
  if ('number' != $item[0]) {
1945
- throw new Exception(sprintf('%s is not a number', $item[0]));
1946
  }
1947
  $number = $this->normalizeNumber($item);
1948
 
1949
  if (null === $unit) {
1950
  $unit = $number[2];
1951
  } elseif ($unit !== $number[2]) {
1952
- throw new \Exception(sprintf('Incompatible units: "%s" and "%s".', $originalUnit, $item[2]));
1953
  }
1954
 
1955
  $originalUnit = $item[2];
@@ -2002,6 +2274,27 @@ class scssc {
2002
  return array("list", $sep, array_merge($list1[2], array($value)));
2003
  }
2004
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2005
 
2006
  protected static $lib_type_of = array("value");
2007
  protected function lib_type_of($args) {
@@ -2037,10 +2330,29 @@ class scssc {
2037
  return $value[0] == "number" && empty($value[2]);
2038
  }
2039
 
2040
-
2041
  protected static $lib_comparable = array("number-1", "number-2");
2042
  protected function lib_comparable($args) {
2043
- return true; // TODO: THIS
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2044
  }
2045
 
2046
  static protected $cssColors = array(
@@ -2194,6 +2506,11 @@ class scssc {
2194
  );
2195
  }
2196
 
 
 
 
 
 
2197
  class scss_parser {
2198
  static protected $precedence = array(
2199
  "or" => 0,
@@ -2225,8 +2542,9 @@ class scss_parser {
2225
  static protected $commentMultiLeft = "/*";
2226
  static protected $commentMultiRight = "*/";
2227
 
2228
- function __construct($sourceName = null) {
2229
  $this->sourceName = $sourceName;
 
2230
 
2231
  if (empty(self::$operatorStr)) {
2232
  self::$operatorStr = $this->makeOperatorStr(self::$operators);
@@ -2268,6 +2586,45 @@ class scss_parser {
2268
  return $this->env;
2269
  }
2270
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2271
  protected function parseChunk() {
2272
  $s = $this->seek();
2273
 
@@ -2309,7 +2666,7 @@ class scss_parser {
2309
  $include = $this->pushSpecialBlock("include");
2310
  $include->child = $child;
2311
  } else {
2312
- $this->append($child);
2313
  }
2314
 
2315
  return true;
@@ -2321,7 +2678,7 @@ class scss_parser {
2321
  $this->valueList($importPath) &&
2322
  $this->end())
2323
  {
2324
- $this->append(array("import", $importPath));
2325
  return true;
2326
  } else {
2327
  $this->seek($s);
@@ -2331,19 +2688,19 @@ class scss_parser {
2331
  $this->selectors($selector) &&
2332
  $this->end())
2333
  {
2334
- $this->append(array("extend", $selector));
2335
  return true;
2336
  } else {
2337
  $this->seek($s);
2338
  }
2339
 
2340
  if ($this->literal("@function") &&
2341
- $this->keyword($fn_name) &&
2342
  $this->argumentDef($args) &&
2343
  $this->literal("{"))
2344
  {
2345
  $func = $this->pushSpecialBlock("function");
2346
- $func->name = $fn_name;
2347
  $func->args = $args;
2348
  return true;
2349
  } else {
@@ -2351,7 +2708,7 @@ class scss_parser {
2351
  }
2352
 
2353
  if ($this->literal("@return") && $this->valueList($retVal) && $this->end()) {
2354
- $this->append(array("return", $retVal));
2355
  return true;
2356
  } else {
2357
  $this->seek($s);
@@ -2413,14 +2770,14 @@ class scss_parser {
2413
  if (($this->literal("@debug") || $this->literal("@warn")) &&
2414
  $this->valueList($value) &&
2415
  $this->end()) {
2416
- $this->append(array("debug", $value, $s));
2417
  return true;
2418
  } else {
2419
  $this->seek($s);
2420
  }
2421
 
2422
  if ($this->literal("@content") && $this->end()) {
2423
- $this->append(array("mixin_content"));
2424
  return true;
2425
  } else {
2426
  $this->seek($s);
@@ -2450,7 +2807,7 @@ class scss_parser {
2450
  if ($this->literal("@charset") &&
2451
  $this->valueList($charset) && $this->end())
2452
  {
2453
- $this->append(array("charset", $charset));
2454
  return true;
2455
  } else {
2456
  $this->seek($s);
@@ -2479,7 +2836,7 @@ class scss_parser {
2479
  $this->end())
2480
  {
2481
  $name = array("string", "", array($name));
2482
- $this->append(array("assign", $name, $value));
2483
  return true;
2484
  } else {
2485
  $this->seek($s);
@@ -2490,17 +2847,9 @@ class scss_parser {
2490
  $this->literal(":") &&
2491
  $this->valueList($value) && $this->end())
2492
  {
2493
- $defaultVar = false;
2494
  // check for !default
2495
- if ($value[0] == "list") {
2496
- $def = end($value[2]);
2497
- if ($def[0] == "keyword" && $def[1] == "!default") {
2498
- array_pop($value[2]);
2499
- $value = $this->flattenList($value);
2500
- $defaultVar = true;
2501
- }
2502
- }
2503
- $this->append(array("assign", $name, $value, $defaultVar));
2504
  return true;
2505
  } else {
2506
  $this->seek($s);
@@ -2527,7 +2876,7 @@ class scss_parser {
2527
  if ($this->propertyName($name) && $this->literal(":")) {
2528
  $foundSomething = false;
2529
  if ($this->valueList($value)) {
2530
- $this->append(array("assign", $name, $value));
2531
  $foundSomething = true;
2532
  }
2533
 
@@ -2555,10 +2904,10 @@ class scss_parser {
2555
  $include = $block->child;
2556
  unset($block->child);
2557
  $include[3] = $block;
2558
- $this->append($include);
2559
- } else if (empty($block->dontAppend)) {
2560
  $type = isset($block->type) ? $block->type : "block";
2561
- $this->append(array($type, $block));
2562
  }
2563
  return true;
2564
  }
@@ -2573,19 +2922,35 @@ class scss_parser {
2573
  return false;
2574
  }
2575
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2576
  protected function literal($what, $eatWhitespace = null) {
2577
  if (is_null($eatWhitespace)) $eatWhitespace = $this->eatWhiteDefault;
2578
 
2579
- // this is here mainly prevent notice from { } string accessor
2580
- if ($this->count >= strlen($this->buffer)) return false;
2581
-
2582
  // shortcut on single letter
2583
- if (!$eatWhitespace && strlen($what) == 1) {
2584
- if ($this->buffer{$this->count} == $what) {
2585
- $this->count++;
2586
- return true;
 
 
 
 
 
2587
  }
2588
- else return false;
2589
  }
2590
 
2591
  return $this->match($this->preg_quote($what), $m, $eatWhitespace);
@@ -2594,7 +2959,7 @@ class scss_parser {
2594
  // tree builders
2595
 
2596
  protected function pushBlock($selectors) {
2597
- $b = new stdclass;
2598
  $b->parent = $this->env; // not sure if we need this yet
2599
 
2600
  $b->selectors = $selectors;
@@ -2621,7 +2986,11 @@ class scss_parser {
2621
  return $old;
2622
  }
2623
 
2624
- protected function append($statement) {
 
 
 
 
2625
  $this->env->children[] = $statement;
2626
  }
2627
 
@@ -2644,20 +3013,23 @@ class scss_parser {
2644
  $expressions = null;
2645
  $parts = array();
2646
 
2647
- if (($this->literal("only") && ($only = true) || $this->literal("not") && ($not = true) || true) && $this->keyword($mediaType)) {
2648
  $prop = array("mediaType");
2649
- if (isset($only)) $prop[] = "only";
2650
- if (isset($not)) $prop[] = "not";
2651
- $prop[] = $mediaType;
 
 
 
 
 
 
 
 
2652
  $parts[] = $prop;
2653
- } else {
2654
- $this->seek($s);
2655
  }
2656
 
2657
-
2658
- if (!empty($mediaType) && !$this->literal("and")) {
2659
- // ~
2660
- } else {
2661
  $this->genericList($expressions, "mediaExpression", "and", false);
2662
  if (is_array($expressions)) $parts = array_merge($parts, $expressions[2]);
2663
  }
@@ -2670,7 +3042,7 @@ class scss_parser {
2670
  $s = $this->seek();
2671
  $value = null;
2672
  if ($this->literal("(") &&
2673
- $this->keyword($feature) &&
2674
  ($this->literal(":") && $this->expression($value) || true) &&
2675
  $this->literal(")"))
2676
  {
@@ -2701,7 +3073,13 @@ class scss_parser {
2701
  }
2702
 
2703
  if ($this->genericList($value, "expression")) {
2704
- $out = array($keyword, $value);
 
 
 
 
 
 
2705
  return true;
2706
  }
2707
 
@@ -2710,11 +3088,11 @@ class scss_parser {
2710
 
2711
 
2712
  protected function valueList(&$out) {
2713
- return $this->genericList($out, "commaList");
2714
  }
2715
 
2716
- protected function commaList(&$out) {
2717
- return $this->genericList($out, "expression", ",");
2718
  }
2719
 
2720
  protected function genericList(&$out, $parseItem, $delim="", $flatten=true) {
@@ -2838,7 +3216,11 @@ class scss_parser {
2838
  if ($this->progid($out)) return true;
2839
 
2840
  if ($this->keyword($keyword)) {
2841
- $out = array("keyword", $keyword);
 
 
 
 
2842
  return true;
2843
  }
2844
 
@@ -2890,7 +3272,12 @@ class scss_parser {
2890
  if ($this->keyword($name, false) &&
2891
  $this->literal("("))
2892
  {
2893
- if ($name != "expression" && false == preg_match("/^(-[a-z]+-)?calc$/", $name)) {
 
 
 
 
 
2894
  $ss = $this->seek();
2895
  if ($this->argValues($args) && $this->literal(")")) {
2896
  $func = array("fncall", $name, $args);
@@ -2916,21 +3303,64 @@ class scss_parser {
2916
  return false;
2917
  }
2918
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2919
  protected function argumentDef(&$out) {
2920
  $s = $this->seek();
2921
  $this->literal("(");
2922
 
2923
  $args = array();
2924
  while ($this->variable($var)) {
2925
- $arg = array($var[1], null);
2926
 
2927
  $ss = $this->seek();
2928
- if ($this->literal(":") && $this->expression($defaultVal)) {
2929
  $arg[1] = $defaultVal;
2930
  } else {
2931
  $this->seek($ss);
2932
  }
2933
 
 
 
 
 
 
 
 
 
 
 
 
 
2934
  $args[] = $arg;
2935
  if (!$this->literal(",")) break;
2936
  }
@@ -2990,15 +3420,10 @@ class scss_parser {
2990
  }
2991
 
2992
  $content = array();
2993
-
2994
- // look for either ending delim , escape, or string interpolation
2995
- $patt = '([^\n]*?)(#\{|\\\\|' .
2996
- $this->preg_quote($delim).')';
2997
-
2998
  $oldWhite = $this->eatWhiteDefault;
2999
  $this->eatWhiteDefault = false;
3000
 
3001
- while ($this->match($patt, $m, false)) {
3002
  $content[] = $m[1];
3003
  if ($m[2] == "#{") {
3004
  $this->count -= strlen($m[2]);
@@ -3056,6 +3481,10 @@ class scss_parser {
3056
 
3057
  if (count($parts) == 0) return false;
3058
 
 
 
 
 
3059
  $out = $parts;
3060
  return true;
3061
  }
@@ -3075,7 +3504,7 @@ class scss_parser {
3075
 
3076
  $content = array();
3077
  while ($this->match($patt, $m, false)) {
3078
- if (!empty($m[1])) {
3079
  $content[] = $m[1];
3080
  if ($nestingOpen) {
3081
  $nestingLevel += substr_count($m[1], $nestingOpen);
@@ -3209,7 +3638,7 @@ class scss_parser {
3209
  return true;
3210
  }
3211
 
3212
- // whitepsace separated list of selectorSingle
3213
  protected function selector(&$out) {
3214
  $selector = array();
3215
 
@@ -3219,6 +3648,8 @@ class scss_parser {
3219
  } elseif ($this->selectorSingle($part)) {
3220
  $selector[] = $part;
3221
  $this->whitespace();
 
 
3222
  } else {
3223
  break;
3224
  }
@@ -3234,7 +3665,7 @@ class scss_parser {
3234
  }
3235
 
3236
  // the parts that make up
3237
- // div[yes=no]#something.hello.world:nth-child(-2n+1)
3238
  protected function selectorSingle(&$out) {
3239
  $oldWhite = $this->eatWhiteDefault;
3240
  $this->eatWhiteDefault = false;
@@ -3285,6 +3716,12 @@ class scss_parser {
3285
  continue;
3286
  }
3287
 
 
 
 
 
 
 
3288
  if ($this->literal("#", false)) {
3289
  $parts[] = "#";
3290
  continue;
@@ -3395,11 +3832,19 @@ class scss_parser {
3395
  return false;
3396
  }
3397
 
 
 
 
 
 
 
 
 
3398
  // consume an end of statement delimiter
3399
  protected function end() {
3400
  if ($this->literal(';')) {
3401
  return true;
3402
- } elseif ($this->count == strlen($this->buffer) || $this->buffer{$this->count} == '}') {
3403
  // if there is end of file or a closing block next then we don't need a ;
3404
  return true;
3405
  }
@@ -3421,7 +3866,7 @@ class scss_parser {
3421
  return true;
3422
  }
3423
 
3424
- protected function throwParseError($msg = "parse error", $count = null) {
3425
  $count = is_null($count) ? $this->count : $count;
3426
 
3427
  $line = $this->getLineNo($count);
@@ -3433,9 +3878,9 @@ class scss_parser {
3433
  }
3434
 
3435
  if ($this->peek("(.*?)(\n|$)", $m, $count)) {
3436
- throw new exception("$msg: failed at `$m[1]` $loc");
3437
  } else {
3438
- throw new exception("$msg: $loc");
3439
  }
3440
  }
3441
 
@@ -3443,6 +3888,48 @@ class scss_parser {
3443
  return 1 + substr_count(substr($this->buffer, 0, $pos), "\n");
3444
  }
3445
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3446
  // try to match something on head of buffer
3447
  protected function match($regex, &$out, $eatWhitespace = null) {
3448
  if (is_null($eatWhitespace)) $eatWhitespace = $this->eatWhiteDefault;
@@ -3507,6 +3994,11 @@ class scss_parser {
3507
  }
3508
  }
3509
 
 
 
 
 
 
3510
  class scss_formatter {
3511
  public $indentChar = " ";
3512
 
@@ -3528,7 +4020,7 @@ class scss_formatter {
3528
  return $name . $this->assignSeparator . $value . ";";
3529
  }
3530
 
3531
- public function block($block) {
3532
  if (empty($block->lines) && empty($block->children)) return;
3533
 
3534
  $inner = $pre = $this->indentStr();
@@ -3559,9 +4051,21 @@ class scss_formatter {
3559
  echo $pre . $this->close . $this->break;
3560
  }
3561
  }
3562
- }
3563
 
 
 
 
 
 
 
 
 
3564
 
 
 
 
 
 
3565
  class scss_formatter_nested extends scss_formatter {
3566
  public $close = " }";
3567
 
@@ -3578,6 +4082,21 @@ class scss_formatter_nested extends scss_formatter {
3578
  }
3579
  $children[] = $child;
3580
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3581
  $block->children = $children;
3582
 
3583
  // make relative to parent
@@ -3587,7 +4106,7 @@ class scss_formatter_nested extends scss_formatter {
3587
  }
3588
  }
3589
 
3590
- public function block($block) {
3591
  if ($block->type == "root") {
3592
  $this->adjustAllChildren($block);
3593
  }
@@ -3633,6 +4152,11 @@ class scss_formatter_nested extends scss_formatter {
3633
  }
3634
  }
3635
 
 
 
 
 
 
3636
  class scss_formatter_compressed extends scss_formatter {
3637
  public $open = "{";
3638
  public $tagSeparator = ",";
@@ -3644,37 +4168,86 @@ class scss_formatter_compressed extends scss_formatter {
3644
  }
3645
  }
3646
 
 
 
 
 
 
3647
  class scss_server {
3648
-
 
 
 
 
 
 
 
3649
  protected function join($left, $right) {
3650
- return rtrim($left, "/") . "/" . ltrim($right, "/");
3651
  }
3652
 
 
 
 
 
 
3653
  protected function inputName() {
3654
- if (isset($_GET["p"])) return $_GET["p"];
3655
-
3656
- if (isset($_SERVER["PATH_INFO"])) return $_SERVER["PATH_INFO"];
3657
- if (isset($_SERVER["DOCUMENT_URI"])) {
3658
- return substr($_SERVER["DOCUMENT_URI"], strlen($_SERVER["SCRIPT_NAME"]));
 
 
3659
  }
3660
  }
3661
 
 
 
 
 
 
3662
  protected function findInput() {
3663
- if ($input = $this->inputName()) {
 
 
 
3664
  $name = $this->join($this->dir, $input);
3665
- if (is_readable($name)) return $name;
 
 
 
3666
  }
 
3667
  return false;
3668
  }
3669
 
 
 
 
 
 
3670
  protected function cacheName($fname) {
3671
- return $this->join($this->cacheDir, md5($fname) . ".css");
3672
  }
3673
 
 
 
 
 
 
3674
  protected function importsCacheName($out) {
3675
- return $out . ".imports";
3676
  }
3677
 
 
 
 
 
 
 
 
 
3678
  protected function needsCompile($in, $out) {
3679
  if (!is_file($out)) return true;
3680
 
@@ -3692,13 +4265,21 @@ class scss_server {
3692
  return false;
3693
  }
3694
 
 
 
 
 
 
 
 
 
3695
  protected function compile($in, $out) {
3696
  $start = microtime(true);
3697
  $css = $this->scss->compile(file_get_contents($in), $in);
3698
  $elapsed = round((microtime(true) - $start), 4);
3699
 
3700
  $v = scssc::$VERSION;
3701
- $t = date("r");
3702
  $css = "/* compiled by scssphp $v on $t (${elapsed}s) */\n\n" . $css;
3703
 
3704
  file_put_contents($out, $css);
@@ -3707,17 +4288,20 @@ class scss_server {
3707
  return $css;
3708
  }
3709
 
 
 
 
3710
  public function serve() {
3711
  if ($input = $this->findInput()) {
3712
  $output = $this->cacheName($input);
3713
- header("Content-type: text/css");
3714
 
3715
  if ($this->needsCompile($input, $output)) {
3716
  try {
3717
  echo $this->compile($input, $output);
3718
- } catch (exception $e) {
3719
  header('HTTP/1.1 500 Internal Server Error');
3720
- echo "Parse error: " . $e->getMessage() . "\n";
3721
  }
3722
  } else {
3723
  header('X-SCSS-Cache: true');
@@ -3728,16 +4312,23 @@ class scss_server {
3728
  }
3729
 
3730
  header('HTTP/1.0 404 Not Found');
3731
- header("Content-type: text");
3732
  $v = scssc::$VERSION;
3733
  echo "/* INPUT NOT FOUND scss $v */\n";
3734
  }
3735
 
 
 
 
 
 
 
 
3736
  public function __construct($dir, $cacheDir=null, $scss=null) {
3737
  $this->dir = $dir;
3738
 
3739
  if (is_null($cacheDir)) {
3740
- $cacheDir = $this->join($dir, "scss_cache");
3741
  }
3742
 
3743
  $this->cacheDir = $cacheDir;
@@ -3750,10 +4341,13 @@ class scss_server {
3750
  $this->scss = $scss;
3751
  }
3752
 
 
 
 
 
 
3753
  static public function serveFrom($path) {
3754
  $server = new self($path);
3755
  $server->serve();
3756
  }
3757
  }
3758
-
3759
-
1
  <?php
2
+ /**
3
+ * SCSS compiler written in PHP
4
+ *
5
+ * @copyright 2012-2013 Leaf Corcoran
6
+ *
7
+ * @license http://opensource.org/licenses/gpl-license GPL-3.0
8
+ * @license http://opensource.org/licenses/MIT MIT
9
+ *
10
+ * @link http://leafo.net/scssphp
11
+ */
12
+
13
+ /**
14
+ * The scss compiler and parser.
15
+ *
16
+ * Converting SCSS to CSS is a three stage process. The incoming file is parsed
17
+ * by `scssc_parser` into a syntax tree, then it is compiled into another tree
18
+ * representing the CSS structure by `scssc`. The CSS tree is fed into a
19
+ * formatter, like `scssc_formatter` which then outputs CSS as a string.
20
+ *
21
+ * During the first compile, all values are *reduced*, which means that their
22
+ * types are brought to the lowest form before being dump as strings. This
23
+ * handles math equations, variable dereferences, and the like.
24
+ *
25
+ * The `parse` function of `scssc` is the entry point.
26
+ *
27
+ * In summary:
28
+ *
29
+ * The `scssc` class creates an instance of the parser, feeds it SCSS code,
30
+ * then transforms the resulting tree to a CSS tree. This class also holds the
31
+ * evaluation context, such as all available mixins and variables at any given
32
+ * time.
33
+ *
34
+ * The `scssc_parser` class is only concerned with parsing its input.
35
+ *
36
+ * The `scssc_formatter` takes a CSS tree, and dumps it to a formatted string,
37
+ * handling things like indentation.
38
+ */
39
+
40
+ /**
41
+ * SCSS compiler
42
+ *
43
+ * @author Leaf Corcoran <leafot@gmail.com>
44
+ */
45
  class scssc {
46
+ static public $VERSION = "v0.0.7";
47
 
48
  static protected $operatorNames = array(
49
  '+' => "add",
67
  "function" => "^",
68
  );
69
 
70
+ static protected $numberPrecision = 5;
71
  static protected $unitTable = array(
72
  "in" => array(
73
  "in" => 1,
81
 
82
  static public $true = array("keyword", "true");
83
  static public $false = array("keyword", "false");
84
+ static public $null = array("null");
85
 
86
  static public $defaultValue = array("keyword", "");
87
  static public $selfSelector = array("self");
112
  $this->scope = null;
113
 
114
  $this->compileRoot($tree);
 
115
 
116
+ $out = $this->formatter->format($this->scope);
 
 
117
 
118
  setlocale(LC_NUMERIC, $locale);
119
  return $out;
120
  }
121
 
122
+ protected function isSelfExtend($target, $origin) {
123
+ foreach ($origin as $sel) {
124
+ if (in_array($target, $sel)) {
125
+ return true;
126
+ }
127
+ }
128
+
129
+ return false;
130
+ }
131
+
132
  protected function pushExtends($target, $origin) {
133
+ if ($this->isSelfExtend($target, $origin)) {
134
+ return;
135
+ }
136
+
137
  $i = count($this->extends);
138
  $this->extends[] = array($target, $origin);
139
 
147
  }
148
 
149
  protected function makeOutputBlock($type, $selectors = null) {
150
+ $out = new stdClass;
151
  $out->type = $type;
152
  $out->lines = array();
153
  $out->children = array();
158
  return $out;
159
  }
160
 
161
+ protected function matchExtendsSingle($single, &$outOrigin) {
162
  $counts = array();
163
  foreach ($single as $part) {
164
  if (!is_string($part)) return false; // hmm
171
  }
172
  }
173
 
174
+ $outOrigin = array();
175
+ $found = false;
176
+
177
  foreach ($counts as $idx => $count) {
178
  list($target, $origin) = $this->extends[$idx];
179
+
180
  // check count
181
  if ($count != count($target)) continue;
182
+
183
  // check if target is subset of single
184
  if (array_diff(array_intersect($single, $target), $target)) continue;
185
 
186
+ $rem = array_diff($single, $target);
 
187
 
188
+ foreach ($origin as $j => $new) {
189
+ $origin[$j][count($origin[$j]) - 1] = $this->combineSelectorSingle(end($new), $rem);
190
+ }
191
+
192
+ $outOrigin = array_merge($outOrigin, $origin);
193
+
194
+ $found = true;
195
  }
196
 
197
+ return $found;
198
  }
199
 
200
  protected function combineSelectorSingle($base, $other) {
203
 
204
  foreach (array($base, $other) as $single) {
205
  foreach ($single as $part) {
206
+ if (preg_match('/^[^\[.#:]/', $part)) {
207
  $tag = $part;
208
  } else {
209
  $out[] = $part;
222
  foreach ($selector as $i => $part) {
223
  if ($i < $from) continue;
224
 
225
+ if ($this->matchExtendsSingle($part, $origin)) {
226
  $before = array_slice($selector, 0, $i);
227
  $after = array_slice($selector, $i + 1);
228
 
229
  foreach ($origin as $new) {
 
 
 
230
  $k = 0;
231
+
232
  // remove shared parts
233
  if ($initial) {
234
  foreach ($before as $k => $val) {
265
  }
266
  }
267
 
268
+ protected function flattenSelectors($block, $parentKey = null) {
269
  if ($block->selectors) {
270
  $selectors = array();
271
  foreach ($block->selectors as $s) {
277
  }
278
  }
279
 
280
+ $block->selectors = array();
281
+ $placeholderSelector = false;
282
+ foreach ($selectors as $selector) {
283
+ if ($this->hasSelectorPlaceholder($selector)) {
284
+ $placeholderSelector = true;
285
+ continue;
286
+ }
287
+ $block->selectors[] = $this->compileSelector($selector);
288
+ }
289
+
290
+ if ($placeholderSelector && 0 == count($block->selectors) && null !== $parentKey) {
291
+ unset($block->parent->children[$parentKey]);
292
+ return;
293
+ }
294
  }
295
 
296
+ foreach ($block->children as $key => $child) {
297
+ $this->flattenSelectors($child, $key);
298
  }
299
  }
300
 
301
  protected function compileRoot($rootBlock) {
302
  $this->pushEnv($rootBlock);
303
  $this->scope = $this->makeOutputBlock("root");
304
+
305
  $this->compileChildren($rootBlock->children, $this->scope);
306
+ $this->flattenSelectors($this->scope);
307
+
308
  $this->popEnv();
309
  }
310
 
318
 
319
  $parentScope->children[] = $this->scope;
320
 
321
+ // top level properties in a media cause it to be wrapped
322
+ $needsWrap = false;
323
+ foreach ($media->children as $child) {
324
+ $type = $child[0];
325
+ if ($type !== 'block' && $type !== 'media' && $type !== 'directive') {
326
+ $needsWrap = true;
327
+ break;
328
+ }
329
+ }
330
+
331
+ if ($needsWrap) {
332
+ $wrapped = (object)array(
333
+ "selectors" => array(),
334
+ "children" => $media->children
335
+ );
336
+ $media->children = array(array("block", $wrapped));
337
+ }
338
+
339
  $this->compileChildren($media->children, $this->scope);
340
 
341
  $this->scope = $this->scope->parent;
365
  $this->popEnv();
366
  }
367
 
368
+ /**
369
+ * Recursively compiles a block.
370
+ *
371
+ * A block is analogous to a CSS block in most cases. A single SCSS document
372
+ * is encapsulated in a block when parsed, but it does not have parent tags
373
+ * so all of its children appear on the root level when compiled.
374
+ *
375
+ * Blocks are made up of selectors and children.
376
+ *
377
+ * The children of a block are just all the blocks that are defined within.
378
+ *
379
+ * Compiling the block involves pushing a fresh environment on the stack,
380
+ * and iterating through the props, compiling each one.
381
+ *
382
+ * @see scss::compileChild()
383
+ *
384
+ * @param \StdClass $block
385
+ */
386
  protected function compileBlock($block) {
387
  $env = $this->pushEnv($block);
388
 
402
  foreach ($single as $part) {
403
  if (empty($joined) ||
404
  !is_string($part) ||
405
+ preg_match('/[\[.:#%]/', $part))
406
  {
407
  $joined[] = $part;
408
  continue;
431
  case "interpolate":
432
  $p = $this->compileValue($p);
433
  break;
434
+ case "string":
435
+ $p = $this->compileValue($p);
436
+ break;
437
  }
438
  }
439
 
466
  return implode($piece);
467
  }
468
 
469
+ protected function hasSelectorPlaceholder($selector)
470
+ {
471
+ if (!is_array($selector)) return false;
472
+
473
+ foreach ($selector as $parts) {
474
+ foreach ($parts as $part) {
475
+ if ('%' == $part[0]) {
476
+ return true;
477
+ }
478
+ }
479
+ }
480
+
481
+ return false;
482
+ }
483
+
484
  protected function compileChildren($stms, $out) {
485
  foreach ($stms as $stm) {
486
  $ret = $this->compileChild($stm, $out);
496
  foreach ($query as $q) {
497
  switch ($q[0]) {
498
  case "mediaType":
499
+ $parts[] = implode(" ", array_map(array($this, "compileValue"), array_slice($q, 1)));
500
  break;
501
  case "mediaExp":
502
  if (isset($q[2])) {
503
+ $parts[] = "(". $this->compileValue($q[1]) . $this->formatter->assignSeparator . $this->compileValue($q[2]) . ")";
504
  } else {
505
+ $parts[] = "(" . $this->compileValue($q[1]) . ")";
506
  }
507
  break;
508
  }
529
  return true;
530
  }
531
  return false;
532
+ }
533
+ if ($rawPath[0] == "list") {
534
  // handle a list of strings
535
  if (count($rawPath[2]) == 0) return false;
536
  foreach ($rawPath[2] as $path) {
549
 
550
  // return a value to halt execution
551
  protected function compileChild($child, $out) {
552
+ $this->sourcePos = isset($child[-1]) ? $child[-1] : -1;
553
+ $this->sourceParser = isset($child[-2]) ? $child[-2] : $this->parser;
554
+
555
  switch ($child[0]) {
556
  case "import":
557
  list(,$rawPath) = $child;
581
  list(,$name, $value) = $child;
582
  if ($name[0] == "var") {
583
  $isDefault = !empty($child[3]);
584
+
585
+ if ($isDefault) {
586
+ $existingValue = $this->get($name[1], true);
587
+ $shouldSet = $existingValue === true || $existingValue == self::$null;
588
+ }
589
+
590
+ if (!$isDefault || $shouldSet) {
591
  $this->set($name[1], $this->reduce($value));
592
  }
593
  break;
594
  }
595
 
596
+ // if the value reduces to null from something else then
597
+ // the property should be discarded
598
+ if ($value[0] != "null") {
599
+ $value = $this->reduce($value);
600
+ if ($value[0] == "null") {
601
+ break;
602
+ }
603
+ }
604
+
605
+ $compiledValue = $this->compileValue($value);
606
  $out->lines[] = $this->formatter->property(
607
+ $this->compileValue($name),
608
+ $compiledValue);
609
  break;
610
  case "comment":
611
  $out->lines[] = $child[1];
625
  break;
626
  case "if":
627
  list(, $if) = $child;
628
+ if ($this->isTruthy($this->reduce($if->cond, true))) {
629
  return $this->compileChildren($if->children, $out);
630
  } else {
631
  foreach ($if->cases as $case) {
632
  if ($case->type == "else" ||
633
+ $case->type == "elseif" && $this->isTruthy($this->reduce($case->cond)))
634
  {
635
  return $this->compileChildren($case->children, $out);
636
  }
641
  return $this->reduce($child[1], true);
642
  case "each":
643
  list(,$each) = $child;
644
+ $list = $this->coerceList($this->reduce($each->list));
645
  foreach ($list[2] as $item) {
646
  $this->pushEnv();
647
  $this->set($each->var, $item);
652
  break;
653
  case "while":
654
  list(,$while) = $child;
655
+ while ($this->isTruthy($this->reduce($while->cond, true))) {
656
  $ret = $this->compileChildren($while->children, $out);
657
  if ($ret) return $ret;
658
  }
698
  case "include": // including a mixin
699
  list(,$name, $argValues, $content) = $child;
700
  $mixin = $this->get(self::$namespaces["mixin"] . $name, false);
701
+ if (!$mixin) {
702
+ $this->throwError("Undefined mixin $name");
703
+ }
704
 
705
  $callingScope = $this->env;
706
 
707
  // push scope, apply args
708
  $this->pushEnv();
709
+ if ($this->env->depth > 0) {
710
+ $this->env->depth--;
711
+ }
712
 
713
  if (!is_null($content)) {
714
  $content->scope = $callingScope;
729
  case "mixin_content":
730
  $content = $this->get(self::$namespaces["special"] . "content");
731
  if (is_null($content)) {
732
+ $this->throwError("Expected @content inside of mixin");
733
  }
734
 
 
 
735
  foreach ($content->children as $child) {
736
+ $this->storeEnv = ($child[0] == 'include' || $child[0] == 'block')
737
+ ? null
738
+ : $content->scope;
739
+
740
  $this->compileChild($child, $out);
741
  }
742
 
749
  fwrite(STDERR, "Line $line DEBUG: $value\n");
750
  break;
751
  default:
752
+ $this->throwError("unknown child type: $child[0]");
753
  }
754
  }
755
 
756
  protected function expToString($exp) {
757
  list(, $op, $left, $right, $inParens, $whiteLeft, $whiteRight) = $exp;
758
+ $content = array($this->reduce($left));
759
  if ($whiteLeft) $content[] = " ";
760
  $content[] = $op;
761
  if ($whiteRight) $content[] = " ";
762
+ $content[] = $this->reduce($right);
763
  return array("string", "", $content);
764
  }
765
 
766
+ protected function isTruthy($value) {
767
+ return $value != self::$false && $value != self::$null;
768
+ }
769
+
770
  // should $value cause its operand to eval
771
  protected function shouldEval($value) {
772
  switch ($value[0]) {
824
  $left[0] == "number" && $right[0] == "number")
825
  {
826
  if ($opName == "mod" && $right[2] != "") {
827
+ $this->throwError("Cannot modulo by a number with units: $right[1]$right[2].");
828
  }
829
 
830
  $unitChange = true;
958
  }
959
  }
960
 
961
+ public function normalizeValue($value) {
962
+ $value = $this->coerceForExpression($this->reduce($value));
963
+ list($type) = $value;
964
+
965
+ switch ($type) {
966
+ case "list":
967
+ $value = $this->extractInterpolation($value);
968
+ if ($value[0] != "list") {
969
+ return array("keyword", $this->compileValue($value));
970
+ }
971
+ foreach ($value[2] as $key => $item) {
972
+ $value[2][$key] = $this->normalizeValue($item);
973
+ }
974
+ return $value;
975
+ case "number":
976
+ return $this->normalizeNumber($value);
977
+ default:
978
+ return $value;
979
+ }
980
+ }
981
+
982
  // just does physical lengths for now
983
  protected function normalizeNumber($number) {
984
  list(, $value, $unit) = $number;
1070
  break;
1071
  case '/':
1072
  if ($rval == 0) {
1073
+ $this->throwError("color: Can't divide by zero");
1074
  }
1075
  $out[] = $lval / $rval;
1076
  break;
1077
+ case "==":
1078
+ return $this->op_eq($left, $right);
1079
+ case "!=":
1080
+ return $this->op_neq($left, $right);
1081
  default:
1082
+ $this->throwError("color: unknown op $op");
1083
  }
1084
  }
1085
 
1135
  return $thing ? self::$true : self::$false;
1136
  }
1137
 
1138
+ /**
1139
+ * Compiles a primitive value into a CSS property value.
1140
+ *
1141
+ * Values in scssphp are typed by being wrapped in arrays, their format is
1142
+ * typically:
1143
+ *
1144
+ * array(type, contents [, additional_contents]*)
1145
+ *
1146
+ * The input is expected to be reduced. This function will not work on
1147
+ * things like expressions and variables.
1148
+ *
1149
+ * @param array $value
1150
+ */
1151
  protected function compileValue($value) {
1152
  $value = $this->reduce($value);
1153
 
1190
  if ($value[0] != "list") return $this->compileValue($value);
1191
 
1192
  list(, $delim, $items) = $value;
1193
+
1194
+ $filtered = array();
1195
+ foreach ($items as $item) {
1196
+ if ($item[0] == "null") continue;
1197
+ $filtered[] = $this->compileValue($item);
1198
  }
1199
+
1200
+ return implode("$delim ", $filtered);
1201
  case "interpolated": # node created by extractInterpolation
1202
  list(, $interpolate, $left, $right) = $value;
1203
  list(,, $whiteLeft, $whiteRight) = $interpolate;
1215
 
1216
  // strip quotes if it's a string
1217
  $reduced = $this->reduce($exp);
1218
+ switch ($reduced[0]) {
1219
+ case "string":
1220
+ $reduced = array("keyword",
1221
+ $this->compileStringContent($reduced));
1222
+ break;
1223
+ case "null":
1224
+ $reduced = array("keyword", "");
1225
  }
1226
 
1227
  return $this->compileValue($reduced);
1228
+ case "null":
1229
+ return "null";
1230
  default:
1231
+ $this->throwError("unknown value type: $type");
1232
  }
1233
  }
1234
 
1259
  }
1260
 
1261
  // find the final set of selectors
1262
+ protected function multiplySelectors($env) {
1263
+ $envs = array();
1264
+ while (null !== $env) {
1265
+ if (!empty($env->selectors)) {
1266
+ $envs[] = $env;
1267
+ }
1268
+ $env = $env->parent;
1269
+ };
 
1270
 
1271
+ $selectors = array();
1272
+ $parentSelectors = array(array());
1273
+ while ($env = array_pop($envs)) {
1274
  $selectors = array();
1275
+ foreach ($env->selectors as $selector) {
1276
+ foreach ($parentSelectors as $parent) {
1277
+ $selectors[] = $this->joinSelectors($parent, $selector);
1278
  }
1279
  }
1280
+ $parentSelectors = $selectors;
1281
  }
1282
 
1283
+ return $selectors;
1284
  }
1285
 
1286
  // looks for & to replace, or append parent before child
1352
  }
1353
 
1354
  protected function applyArguments($argDef, $argValues) {
1355
+ $hasVariable = false;
1356
+ $args = array();
1357
+ foreach ($argDef as $i => $arg) {
1358
+ list($name, $default, $isVariable) = $argDef[$i];
1359
+ $args[$name] = array($i, $name, $default, $isVariable);
1360
+ $hasVariable |= $isVariable;
1361
+ }
1362
 
1363
  $keywordArgs = array();
1364
+ $deferredKeywordArgs = array();
1365
  $remaining = array();
 
1366
  // assign the keyword args
1367
+ foreach ((array) $argValues as $arg) {
1368
  if (!empty($arg[0])) {
1369
+ if (!isset($args[$arg[0][1]])) {
1370
+ if ($hasVariable) {
1371
+ $deferredKeywordArgs[$arg[0][1]] = $arg[1];
1372
+ } else {
1373
+ $this->throwError("Mixin or function doesn't have an argument named $%s.", $arg[0][1]);
1374
+ }
1375
+ } elseif ($args[$arg[0][1]][0] < count($remaining)) {
1376
+ $this->throwError("The argument $%s was passed both by position and by name.", $arg[0][1]);
1377
+ } else {
1378
+ $keywordArgs[$arg[0][1]] = $arg[1];
1379
+ }
1380
+ } elseif (count($keywordArgs)) {
1381
+ $this->throwError('Positional arguments must come before keyword arguments.');
1382
+ } elseif ($arg[2] == true) {
1383
+ $val = $this->reduce($arg[1], true);
1384
+ if ($val[0] == "list") {
1385
+ foreach ($val[2] as $name => $item) {
1386
+ if (!is_numeric($name)) {
1387
+ $keywordArgs[$name] = $item;
1388
+ } else {
1389
+ $remaining[] = $item;
1390
+ }
1391
+ }
1392
+ } else {
1393
+ $remaining[] = $val;
1394
+ }
1395
  } else {
1396
  $remaining[] = $arg[1];
1397
  }
1398
  }
1399
 
1400
+ foreach ($args as $arg) {
1401
+ list($i, $name, $default, $isVariable) = $arg;
1402
+ if ($isVariable) {
1403
+ $val = array("list", ",", array());
1404
+ for ($count = count($remaining); $i < $count; $i++) {
1405
+ $val[2][] = $remaining[$i];
1406
+ }
1407
+ foreach ($deferredKeywordArgs as $itemName => $item) {
1408
+ $val[2][$itemName] = $item;
1409
+ }
1410
+ } elseif (isset($remaining[$i])) {
1411
  $val = $remaining[$i];
1412
  } elseif (isset($keywordArgs[$name])) {
1413
  $val = $keywordArgs[$name];
1414
  } elseif (!empty($default)) {
1415
  $val = $default;
1416
  } else {
1417
+ $this->throwError("Missing argument $$name");
1418
  }
1419
 
1420
  $this->set($name, $this->reduce($val, true), true);
1422
  }
1423
 
1424
  protected function pushEnv($block=null) {
1425
+ $env = new stdClass;
1426
  $env->parent = $this->env;
1427
  $env->store = array();
1428
  $env->block = $block;
1442
 
1443
  protected function set($name, $value, $shadow=false) {
1444
  $name = $this->normalizeName($name);
1445
+
1446
  if ($shadow) {
1447
  $this->setRaw($name, $value);
1448
  } else {
1475
 
1476
  if (isset($env->store[$name])) {
1477
  return $env->store[$name];
1478
+ } elseif (isset($env->parent)) {
1479
  return $this->get($name, $defaultValue, $env->parent);
1480
  }
1481
 
1519
  $tree = $this->importCache[$realPath];
1520
  } else {
1521
  $code = file_get_contents($path);
1522
+ $parser = new scss_parser($path, false);
1523
  $tree = $parser->parse($code);
1524
  $this->parsedFiles[] = $path;
1525
 
1585
  $val = $this->reduce($val, true);
1586
  }
1587
  $returnValue = call_user_func($f, $sorted, $this);
1588
+ } elseif (isset($this->userFunctions[$name])) {
1589
  // see if we can find a user function
1590
  $fn = $this->userFunctions[$name];
1591
 
1669
  $name = $value[1];
1670
  if (isset(self::$cssColors[$name])) {
1671
  list($r, $g, $b) = explode(',', self::$cssColors[$name]);
1672
+ return array('color', (int) $r, (int) $g, (int) $b);
1673
  }
1674
  return null;
1675
  }
1687
  return null;
1688
  }
1689
 
1690
+ protected function assertList($value) {
1691
+ if ($value[0] != "list")
1692
+ $this->throwError("expecting list");
1693
+ return $value;
1694
+ }
1695
+
1696
  protected function assertColor($value) {
1697
  if ($color = $this->coerceColor($value)) return $color;
1698
+ $this->throwError("expecting color");
1699
  }
1700
 
1701
  protected function assertNumber($value) {
1702
  if ($value[0] != "number")
1703
+ $this->throwError("expecting number");
1704
  return $value[1];
1705
  }
1706
 
1724
  return $c;
1725
  }
1726
 
1727
+ function toHSL($red, $green, $blue) {
1728
+ $r = $red / 255;
1729
+ $g = $green / 255;
1730
+ $b = $blue / 255;
1731
 
1732
  $min = min($r, $g, $b);
1733
  $max = max($r, $g, $b);
1734
+ $d = $max - $min;
1735
+ $l = ($min + $max) / 2;
1736
 
 
1737
  if ($min == $max) {
1738
+ $s = $h = 0;
1739
  } else {
1740
+ if ($l < 0.5)
1741
+ $s = $d / (2 * $l);
1742
  else
1743
+ $s = $d / (2 - 2 * $l);
 
 
 
 
1744
 
1745
+ if ($r == $max)
1746
+ $h = 60 * ($g - $b) / $d;
1747
+ elseif ($g == $max)
1748
+ $h = 60 * ($b - $r) / $d + 120;
1749
+ elseif ($b == $max)
1750
+ $h = 60 * ($r - $g) / $d + 240;
1751
  }
1752
 
1753
+ return array('hsl', fmod($h, 360), $s * 100, $l * 100);
 
 
 
 
1754
  }
1755
 
1756
+ function hueToRGB($m1, $m2, $h) {
1757
+ if ($h < 0)
1758
+ $h += 1;
1759
+ elseif ($h > 1)
1760
+ $h -= 1;
1761
 
1762
+ if ($h * 6 < 1)
1763
+ return $m1 + ($m2 - $m1) * $h * 6;
 
1764
 
1765
+ if ($h * 2 < 1)
1766
+ return $m2;
1767
 
1768
+ if ($h * 3 < 2)
1769
+ return $m1 + ($m2 - $m1) * (2/3 - $h) * 6;
 
 
1770
 
1771
+ return $m1;
1772
+ }
1773
 
1774
+ // H from 0 to 360, S and L from 0 to 100
1775
+ function toRGB($hue, $saturation, $lightness) {
1776
+ if ($hue < 0) {
1777
+ $hue += 360;
1778
+ }
1779
 
1780
+ $h = $hue / 360;
1781
+ $s = min(100, max(0, $saturation)) / 100;
1782
+ $l = min(100, max(0, $lightness)) / 100;
 
 
 
1783
 
1784
+ $m2 = $l <= 0.5 ? $l * ($s + 1) : $l + $s - $l * $s;
1785
+ $m1 = $l * 2 - $m2;
1786
 
1787
+ $r = $this->hueToRGB($m1, $m2, $h + 1/3) * 255;
1788
+ $g = $this->hueToRGB($m1, $m2, $h) * 255;
1789
+ $b = $this->hueToRGB($m1, $m2, $h - 1/3) * 255;
 
1790
 
1791
+ $out = array('color', $r, $g, $b);
1792
  return $out;
1793
  }
1794
 
1801
  return $t;
1802
  }
1803
 
1804
+ protected static $lib_index = array("list", "value");
1805
+ protected function lib_index($args) {
1806
+ list($list, $value) = $args;
1807
+ $list = $this->assertList($list);
1808
+
1809
+ $values = array();
1810
+ foreach ($list[2] as $item) {
1811
+ $values[] = $this->normalizeValue($item);
1812
+ }
1813
+ $key = array_search($this->normalizeValue($value), $values);
1814
+
1815
+ return false === $key ? false : $key + 1;
1816
+ }
1817
+
1818
  protected static $lib_rgb = array("red", "green", "blue");
1819
  protected function lib_rgb($args) {
1820
  list($r,$g,$b) = $args;
1953
  }
1954
 
1955
  // this might be the IE function, so return value unchanged
1956
+ return null;
1957
  }
1958
 
1959
  protected static $lib_opacity = array("color");
1960
  protected function lib_opacity($args) {
1961
+ $value = $args[0];
1962
+ if ($value[0] === 'number') return null;
1963
  return $this->lib_alpha($args);
1964
  }
1965
 
1976
  $weight = $this->coercePercent($weight);
1977
  }
1978
 
1979
+ $firstAlpha = isset($first[4]) ? $first[4] : 1;
1980
+ $secondAlpha = isset($second[4]) ? $second[4] : 1;
1981
 
1982
  $w = $weight * 2 - 1;
1983
+ $a = $firstAlpha - $secondAlpha;
1984
 
1985
  $w1 = (($w * $a == -1 ? $w : ($w + $a)/(1 + $w * $a)) + 1) / 2.0;
1986
  $w2 = 1.0 - $w1;
1991
  $w1 * $first[3] + $w2 * $second[3],
1992
  );
1993
 
1994
+ if ($firstAlpha != 1.0 || $secondAlpha != 1.0) {
1995
+ $new[] = $firstAlpha * $weight + $secondAlpha * ($weight - 1);
1996
  }
1997
 
1998
  return $this->fixColor($new);
2034
  return array("number", $hsl[3], "%");
2035
  }
2036
 
 
2037
  protected function adjustHsl($color, $idx, $amount) {
2038
  $hsl = $this->toHSL($color[1], $color[2], $color[3]);
2039
  $hsl[$idx] += $amount;
2065
 
2066
  protected static $lib_saturate = array("color", "amount");
2067
  protected function lib_saturate($args) {
2068
+ $value = $args[0];
2069
+ if ($value[0] === 'number') return null;
2070
+ $color = $this->assertColor($value);
2071
  $amount = 100*$this->coercePercent($args[1]);
2072
  return $this->adjustHsl($color, 2, $amount);
2073
  }
2081
 
2082
  protected static $lib_grayscale = array("color");
2083
  protected function lib_grayscale($args) {
2084
+ $value = $args[0];
2085
+ if ($value[0] === 'number') return null;
2086
+ return $this->adjustHsl($this->assertColor($value), 2, -100);
2087
  }
2088
 
2089
  protected static $lib_complement = array("color");
2093
 
2094
  protected static $lib_invert = array("color");
2095
  protected function lib_invert($args) {
2096
+ $value = $args[0];
2097
+ if ($value[0] === 'number') return null;
2098
+ $color = $this->assertColor($value);
2099
  $color[1] = 255 - $color[1];
2100
  $color[2] = 255 - $color[2];
2101
  $color[3] = 255 - $color[3];
2102
  return $color;
2103
  }
2104
 
 
2105
  // increases opacity by amount
2106
  protected static $lib_opacify = array("color", "amount");
2107
  protected function lib_opacify($args) {
2214
  $numbers = array();
2215
  foreach ($args as $key => $item) {
2216
  if ('number' != $item[0]) {
2217
+ $this->throwError("%s is not a number", $item[0]);
2218
  }
2219
  $number = $this->normalizeNumber($item);
2220
 
2221
  if (null === $unit) {
2222
  $unit = $number[2];
2223
  } elseif ($unit !== $number[2]) {
2224
+ $this->throwError('Incompatible units: "%s" and "%s".', $originalUnit, $item[2]);
2225
  }
2226
 
2227
  $originalUnit = $item[2];
2274
  return array("list", $sep, array_merge($list1[2], array($value)));
2275
  }
2276
 
2277
+ protected function lib_zip($args) {
2278
+ foreach ($args as $arg) {
2279
+ $this->assertList($arg);
2280
+ }
2281
+
2282
+ $lists = array();
2283
+ $firstList = array_shift($args);
2284
+ foreach ($firstList[2] as $key => $item) {
2285
+ $list = array("list", "", array($item));
2286
+ foreach ($args as $arg) {
2287
+ if (isset($arg[2][$key])) {
2288
+ $list[2][] = $arg[2][$key];
2289
+ } else {
2290
+ break 2;
2291
+ }
2292
+ }
2293
+ $lists[] = $list;
2294
+ }
2295
+
2296
+ return array("list", ",", $lists);
2297
+ }
2298
 
2299
  protected static $lib_type_of = array("value");
2300
  protected function lib_type_of($args) {
2330
  return $value[0] == "number" && empty($value[2]);
2331
  }
2332
 
 
2333
  protected static $lib_comparable = array("number-1", "number-2");
2334
  protected function lib_comparable($args) {
2335
+ list($number1, $number2) = $args;
2336
+ if (!isset($number1[0]) || $number1[0] != "number" || !isset($number2[0]) || $number2[0] != "number") {
2337
+ $this->throwError('Invalid argument(s) for "comparable"');
2338
+ }
2339
+
2340
+ $number1 = $this->normalizeNumber($number1);
2341
+ $number2 = $this->normalizeNumber($number2);
2342
+
2343
+ return $number1[2] == $number2[2] || $number1[2] == "" || $number2[2] == "";
2344
+ }
2345
+
2346
+ protected function throwError($msg = null) {
2347
+ if (func_num_args() > 1) {
2348
+ $msg = call_user_func_array("sprintf", func_get_args());
2349
+ }
2350
+
2351
+ if ($this->sourcePos >= 0 && isset($this->sourceParser)) {
2352
+ $this->sourceParser->throwParseError($msg, $this->sourcePos);
2353
+ }
2354
+
2355
+ throw new Exception($msg);
2356
  }
2357
 
2358
  static protected $cssColors = array(
2506
  );
2507
  }
2508
 
2509
+ /**
2510
+ * SCSS parser
2511
+ *
2512
+ * @author Leaf Corcoran <leafot@gmail.com>
2513
+ */
2514
  class scss_parser {
2515
  static protected $precedence = array(
2516
  "or" => 0,
2542
  static protected $commentMultiLeft = "/*";
2543
  static protected $commentMultiRight = "*/";
2544
 
2545
+ function __construct($sourceName = null, $rootParser = true) {
2546
  $this->sourceName = $sourceName;
2547
+ $this->rootParser = $rootParser;
2548
 
2549
  if (empty(self::$operatorStr)) {
2550
  self::$operatorStr = $this->makeOperatorStr(self::$operators);
2586
  return $this->env;
2587
  }
2588
 
2589
+ /**
2590
+ * Parse a single chunk off the head of the buffer and append it to the
2591
+ * current parse environment.
2592
+ *
2593
+ * Returns false when the buffer is empty, or when there is an error.
2594
+ *
2595
+ * This function is called repeatedly until the entire document is
2596
+ * parsed.
2597
+ *
2598
+ * This parser is most similar to a recursive descent parser. Single
2599
+ * functions represent discrete grammatical rules for the language, and
2600
+ * they are able to capture the text that represents those rules.
2601
+ *
2602
+ * Consider the function scssc::keyword(). (All parse functions are
2603
+ * structured the same.)
2604
+ *
2605
+ * The function takes a single reference argument. When calling the
2606
+ * function it will attempt to match a keyword on the head of the buffer.
2607
+ * If it is successful, it will place the keyword in the referenced
2608
+ * argument, advance the position in the buffer, and return true. If it
2609
+ * fails then it won't advance the buffer and it will return false.
2610
+ *
2611
+ * All of these parse functions are powered by scssc::match(), which behaves
2612
+ * the same way, but takes a literal regular expression. Sometimes it is
2613
+ * more convenient to use match instead of creating a new function.
2614
+ *
2615
+ * Because of the format of the functions, to parse an entire string of
2616
+ * grammatical rules, you can chain them together using &&.
2617
+ *
2618
+ * But, if some of the rules in the chain succeed before one fails, then
2619
+ * the buffer position will be left at an invalid state. In order to
2620
+ * avoid this, scssc::seek() is used to remember and set buffer positions.
2621
+ *
2622
+ * Before parsing a chain, use $s = $this->seek() to remember the current
2623
+ * position into $s. Then if a chain fails, use $this->seek($s) to
2624
+ * go back where we started.
2625
+ *
2626
+ * @return boolean
2627
+ */
2628
  protected function parseChunk() {
2629
  $s = $this->seek();
2630
 
2666
  $include = $this->pushSpecialBlock("include");
2667
  $include->child = $child;
2668
  } else {
2669
+ $this->append($child, $s);
2670
  }
2671
 
2672
  return true;
2678
  $this->valueList($importPath) &&
2679
  $this->end())
2680
  {
2681
+ $this->append(array("import", $importPath), $s);
2682
  return true;
2683
  } else {
2684
  $this->seek($s);
2688
  $this->selectors($selector) &&
2689
  $this->end())
2690
  {
2691
+ $this->append(array("extend", $selector), $s);
2692
  return true;
2693
  } else {
2694
  $this->seek($s);
2695
  }
2696
 
2697
  if ($this->literal("@function") &&
2698
+ $this->keyword($fnName) &&
2699
  $this->argumentDef($args) &&
2700
  $this->literal("{"))
2701
  {
2702
  $func = $this->pushSpecialBlock("function");
2703
+ $func->name = $fnName;
2704
  $func->args = $args;
2705
  return true;
2706
  } else {
2708
  }
2709
 
2710
  if ($this->literal("@return") && $this->valueList($retVal) && $this->end()) {
2711
+ $this->append(array("return", $retVal), $s);
2712
  return true;
2713
  } else {
2714
  $this->seek($s);
2770
  if (($this->literal("@debug") || $this->literal("@warn")) &&
2771
  $this->valueList($value) &&
2772
  $this->end()) {
2773
+ $this->append(array("debug", $value, $s), $s);
2774
  return true;
2775
  } else {
2776
  $this->seek($s);
2777
  }
2778
 
2779
  if ($this->literal("@content") && $this->end()) {
2780
+ $this->append(array("mixin_content"), $s);
2781
  return true;
2782
  } else {
2783
  $this->seek($s);
2807
  if ($this->literal("@charset") &&
2808
  $this->valueList($charset) && $this->end())
2809
  {
2810
+ $this->append(array("charset", $charset), $s);
2811
  return true;
2812
  } else {
2813
  $this->seek($s);
2836
  $this->end())
2837
  {
2838
  $name = array("string", "", array($name));
2839
+ $this->append(array("assign", $name, $value), $s);
2840
  return true;
2841
  } else {
2842
  $this->seek($s);
2847
  $this->literal(":") &&
2848
  $this->valueList($value) && $this->end())
2849
  {
 
2850
  // check for !default
2851
+ $defaultVar = $value[0] == "list" && $this->stripDefault($value);
2852
+ $this->append(array("assign", $name, $value, $defaultVar), $s);
 
 
 
 
 
 
 
2853
  return true;
2854
  } else {
2855
  $this->seek($s);
2876
  if ($this->propertyName($name) && $this->literal(":")) {
2877
  $foundSomething = false;
2878
  if ($this->valueList($value)) {
2879
+ $this->append(array("assign", $name, $value), $s);
2880
  $foundSomething = true;
2881
  }
2882
 
2904
  $include = $block->child;
2905
  unset($block->child);
2906
  $include[3] = $block;
2907
+ $this->append($include, $s);
2908
+ } elseif (empty($block->dontAppend)) {
2909
  $type = isset($block->type) ? $block->type : "block";
2910
+ $this->append(array($type, $block), $s);
2911
  }
2912
  return true;
2913
  }
2922
  return false;
2923
  }
2924
 
2925
+ protected function stripDefault(&$value) {
2926
+ $def = end($value[2]);
2927
+ if ($def[0] == "keyword" && $def[1] == "!default") {
2928
+ array_pop($value[2]);
2929
+ $value = $this->flattenList($value);
2930
+ return true;
2931
+ }
2932
+
2933
+ if ($def[0] == "list") {
2934
+ return $this->stripDefault($value[2][count($value[2]) - 1]);
2935
+ }
2936
+
2937
+ return false;
2938
+ }
2939
+
2940
  protected function literal($what, $eatWhitespace = null) {
2941
  if (is_null($eatWhitespace)) $eatWhitespace = $this->eatWhiteDefault;
2942
 
 
 
 
2943
  // shortcut on single letter
2944
+ if (!isset($what[1]) && isset($this->buffer[$this->count])) {
2945
+ if ($this->buffer[$this->count] == $what) {
2946
+ if (!$eatWhitespace) {
2947
+ $this->count++;
2948
+ return true;
2949
+ }
2950
+ // goes below...
2951
+ } else {
2952
+ return false;
2953
  }
 
2954
  }
2955
 
2956
  return $this->match($this->preg_quote($what), $m, $eatWhitespace);
2959
  // tree builders
2960
 
2961
  protected function pushBlock($selectors) {
2962
+ $b = new stdClass;
2963
  $b->parent = $this->env; // not sure if we need this yet
2964
 
2965
  $b->selectors = $selectors;
2986
  return $old;
2987
  }
2988
 
2989
+ protected function append($statement, $pos=null) {
2990
+ if ($pos !== null) {
2991
+ $statement[-1] = $pos;
2992
+ if (!$this->rootParser) $statement[-2] = $this;
2993
+ }
2994
  $this->env->children[] = $statement;
2995
  }
2996
 
3013
  $expressions = null;
3014
  $parts = array();
3015
 
3016
+ if (($this->literal("only") && ($only = true) || $this->literal("not") && ($not = true) || true) && $this->mixedKeyword($mediaType)) {
3017
  $prop = array("mediaType");
3018
+ if (isset($only)) $prop[] = array("keyword", "only");
3019
+ if (isset($not)) $prop[] = array("keyword", "not");
3020
+ $media = array("list", "", array());
3021
+ foreach ((array)$mediaType as $type) {
3022
+ if (is_array($type)) {
3023
+ $media[2][] = $type;
3024
+ } else {
3025
+ $media[2][] = array("keyword", $type);
3026
+ }
3027
+ }
3028
+ $prop[] = $media;
3029
  $parts[] = $prop;
 
 
3030
  }
3031
 
3032
+ if (empty($parts) || $this->literal("and")) {
 
 
 
3033
  $this->genericList($expressions, "mediaExpression", "and", false);
3034
  if (is_array($expressions)) $parts = array_merge($parts, $expressions[2]);
3035
  }
3042
  $s = $this->seek();
3043
  $value = null;
3044
  if ($this->literal("(") &&
3045
+ $this->expression($feature) &&
3046
  ($this->literal(":") && $this->expression($value) || true) &&
3047
  $this->literal(")"))
3048
  {
3073
  }
3074
 
3075
  if ($this->genericList($value, "expression")) {
3076
+ $out = array($keyword, $value, false);
3077
+ $s = $this->seek();
3078
+ if ($this->literal("...")) {
3079
+ $out[2] = true;
3080
+ } else {
3081
+ $this->seek($s);
3082
+ }
3083
  return true;
3084
  }
3085
 
3088
 
3089
 
3090
  protected function valueList(&$out) {
3091
+ return $this->genericList($out, "spaceList", ",");
3092
  }
3093
 
3094
+ protected function spaceList(&$out) {
3095
+ return $this->genericList($out, "expression");
3096
  }
3097
 
3098
  protected function genericList(&$out, $parseItem, $delim="", $flatten=true) {
3216
  if ($this->progid($out)) return true;
3217
 
3218
  if ($this->keyword($keyword)) {
3219
+ if ($keyword == "null") {
3220
+ $out = array("null");
3221
+ } else {
3222
+ $out = array("keyword", $keyword);
3223
+ }
3224
  return true;
3225
  }
3226
 
3272
  if ($this->keyword($name, false) &&
3273
  $this->literal("("))
3274
  {
3275
+ if ($name == "alpha" && $this->argumentList($args)) {
3276
+ $func = array("function", $name, array("string", "", $args));
3277
+ return true;
3278
+ }
3279
+
3280
+ if ($name != "expression" && !preg_match("/^(-[a-z]+-)?calc$/", $name)) {
3281
  $ss = $this->seek();
3282
  if ($this->argValues($args) && $this->literal(")")) {
3283
  $func = array("fncall", $name, $args);
3303
  return false;
3304
  }
3305
 
3306
+ protected function argumentList(&$out) {
3307
+ $s = $this->seek();
3308
+ $this->literal("(");
3309
+
3310
+ $args = array();
3311
+ while ($this->keyword($var)) {
3312
+ $ss = $this->seek();
3313
+
3314
+ if ($this->literal("=") && $this->expression($exp)) {
3315
+ $args[] = array("string", "", array($var."="));
3316
+ $arg = $exp;
3317
+ } else {
3318
+ break;
3319
+ }
3320
+
3321
+ $args[] = $arg;
3322
+
3323
+ if (!$this->literal(",")) break;
3324
+
3325
+ $args[] = array("string", "", array(", "));
3326
+ }
3327
+
3328
+ if (!$this->literal(")")) {
3329
+ $this->seek($s);
3330
+ return false;
3331
+ }
3332
+
3333
+ $out = $args;
3334
+ return true;
3335
+ }
3336
+
3337
  protected function argumentDef(&$out) {
3338
  $s = $this->seek();
3339
  $this->literal("(");
3340
 
3341
  $args = array();
3342
  while ($this->variable($var)) {
3343
+ $arg = array($var[1], null, false);
3344
 
3345
  $ss = $this->seek();
3346
+ if ($this->literal(":") && $this->genericList($defaultVal, "expression")) {
3347
  $arg[1] = $defaultVal;
3348
  } else {
3349
  $this->seek($ss);
3350
  }
3351
 
3352
+ $ss = $this->seek();
3353
+ if ($this->literal("...")) {
3354
+ $sss = $this->seek();
3355
+ if (!$this->literal(")")) {
3356
+ $this->throwParseError("... has to be after the final argument");
3357
+ }
3358
+ $arg[2] = true;
3359
+ $this->seek($sss);
3360
+ } else {
3361
+ $this->seek($ss);
3362
+ }
3363
+
3364
  $args[] = $arg;
3365
  if (!$this->literal(",")) break;
3366
  }
3420
  }
3421
 
3422
  $content = array();
 
 
 
 
 
3423
  $oldWhite = $this->eatWhiteDefault;
3424
  $this->eatWhiteDefault = false;
3425
 
3426
+ while ($this->matchString($m, $delim)) {
3427
  $content[] = $m[1];
3428
  if ($m[2] == "#{") {
3429
  $this->count -= strlen($m[2]);
3481
 
3482
  if (count($parts) == 0) return false;
3483
 
3484
+ if ($this->eatWhiteDefault) {
3485
+ $this->whitespace();
3486
+ }
3487
+
3488
  $out = $parts;
3489
  return true;
3490
  }
3504
 
3505
  $content = array();
3506
  while ($this->match($patt, $m, false)) {
3507
+ if (isset($m[1]) && $m[1] !== '') {
3508
  $content[] = $m[1];
3509
  if ($nestingOpen) {
3510
  $nestingLevel += substr_count($m[1], $nestingOpen);
3638
  return true;
3639
  }
3640
 
3641
+ // whitespace separated list of selectorSingle
3642
  protected function selector(&$out) {
3643
  $selector = array();
3644
 
3648
  } elseif ($this->selectorSingle($part)) {
3649
  $selector[] = $part;
3650
  $this->whitespace();
3651
+ } elseif ($this->match('\/[^\/]+\/', $m)) {
3652
+ $selector[] = array($m[0]);
3653
  } else {
3654
  break;
3655
  }
3665
  }
3666
 
3667
  // the parts that make up
3668
+ // div[yes=no]#something.hello.world:nth-child(-2n+1)%placeholder
3669
  protected function selectorSingle(&$out) {
3670
  $oldWhite = $this->eatWhiteDefault;
3671
  $this->eatWhiteDefault = false;
3716
  continue;
3717
  }
3718
 
3719
+ if ($this->literal('%', false) && $this->placeholder($placeholder)) {
3720
+ $parts[] = '%';
3721
+ $parts[] = $placeholder;
3722
+ continue;
3723
+ }
3724
+
3725
  if ($this->literal("#", false)) {
3726
  $parts[] = "#";
3727
  continue;
3832
  return false;
3833
  }
3834
 
3835
+ protected function placeholder(&$placeholder) {
3836
+ if ($this->match('([\w\-_]+)', $m)) {
3837
+ $placeholder = $m[1];
3838
+ return true;
3839
+ }
3840
+ return false;
3841
+ }
3842
+
3843
  // consume an end of statement delimiter
3844
  protected function end() {
3845
  if ($this->literal(';')) {
3846
  return true;
3847
+ } elseif ($this->count == strlen($this->buffer) || $this->buffer[$this->count] == '}') {
3848
  // if there is end of file or a closing block next then we don't need a ;
3849
  return true;
3850
  }
3866
  return true;
3867
  }
3868
 
3869
+ public function throwParseError($msg = "parse error", $count = null) {
3870
  $count = is_null($count) ? $this->count : $count;
3871
 
3872
  $line = $this->getLineNo($count);
3878
  }
3879
 
3880
  if ($this->peek("(.*?)(\n|$)", $m, $count)) {
3881
+ throw new Exception("$msg: failed at `$m[1]` $loc");
3882
  } else {
3883
+ throw new Exception("$msg: $loc");
3884
  }
3885
  }
3886
 
3888
  return 1 + substr_count(substr($this->buffer, 0, $pos), "\n");
3889
  }
3890
 
3891
+ /**
3892
+ * Match string looking for either ending delim, escape, or string interpolation
3893
+ *
3894
+ * {@internal This is a workaround for preg_match's 250K string match limit. }}
3895
+ *
3896
+ * @param array $m Matches (passed by reference)
3897
+ * @param string $delim Delimeter
3898
+ *
3899
+ * @return boolean True if match; false otherwise
3900
+ */
3901
+ protected function matchString(&$m, $delim) {
3902
+ $token = null;
3903
+
3904
+ $end = strpos($this->buffer, "\n", $this->count);
3905
+ if ($end === false) {
3906
+ $end = strlen($this->buffer);
3907
+ }
3908
+
3909
+ // look for either ending delim, escape, or string interpolation
3910
+ foreach (array('#{', '\\', $delim) as $lookahead) {
3911
+ $pos = strpos($this->buffer, $lookahead, $this->count);
3912
+ if ($pos !== false && $pos < $end) {
3913
+ $end = $pos;
3914
+ $token = $lookahead;
3915
+ }
3916
+ }
3917
+
3918
+ if (!isset($token)) {
3919
+ return false;
3920
+ }
3921
+
3922
+ $match = substr($this->buffer, $this->count, $end - $this->count);
3923
+ $m = array(
3924
+ $match . $token,
3925
+ $match,
3926
+ $token
3927
+ );
3928
+ $this->count = $end + strlen($token);
3929
+
3930
+ return true;
3931
+ }
3932
+
3933
  // try to match something on head of buffer
3934
  protected function match($regex, &$out, $eatWhitespace = null) {
3935
  if (is_null($eatWhitespace)) $eatWhitespace = $this->eatWhiteDefault;
3994
  }
3995
  }
3996
 
3997
+ /**
3998
+ * SCSS base formatter
3999
+ *
4000
+ * @author Leaf Corcoran <leafot@gmail.com>
4001
+ */
4002
  class scss_formatter {
4003
  public $indentChar = " ";
4004
 
4020
  return $name . $this->assignSeparator . $value . ";";
4021
  }
4022
 
4023
+ protected function block($block) {
4024
  if (empty($block->lines) && empty($block->children)) return;
4025
 
4026
  $inner = $pre = $this->indentStr();
4051
  echo $pre . $this->close . $this->break;
4052
  }
4053
  }
 
4054
 
4055
+ public function format($block) {
4056
+ ob_start();
4057
+ $this->block($block);
4058
+ $out = ob_get_clean();
4059
+
4060
+ return $out;
4061
+ }
4062
+ }
4063
 
4064
+ /**
4065
+ * SCSS nested formatter
4066
+ *
4067
+ * @author Leaf Corcoran <leafot@gmail.com>
4068
+ */
4069
  class scss_formatter_nested extends scss_formatter {
4070
  public $close = " }";
4071
 
4082
  }
4083
  $children[] = $child;
4084
  }
4085
+
4086
+ $count = count($children);
4087
+ for ($i = 0; $i < $count; $i++) {
4088
+ $depth = $children[$i]->depth;
4089
+ $j = $i + 1;
4090
+ if (isset($children[$j]) && $depth < $children[$j]->depth) {
4091
+ $childDepth = $children[$j]->depth;
4092
+ for (; $j < $count; $j++) {
4093
+ if ($depth < $children[$j]->depth && $childDepth >= $children[$j]->depth) {
4094
+ $children[$j]->depth = $depth + 1;
4095
+ }
4096
+ }
4097
+ }
4098
+ }
4099
+
4100
  $block->children = $children;
4101
 
4102
  // make relative to parent
4106
  }
4107
  }
4108
 
4109
+ protected function block($block) {
4110
  if ($block->type == "root") {
4111
  $this->adjustAllChildren($block);
4112
  }
4152
  }
4153
  }
4154
 
4155
+ /**
4156
+ * SCSS compressed formatter
4157
+ *
4158
+ * @author Leaf Corcoran <leafot@gmail.com>
4159
+ */
4160
  class scss_formatter_compressed extends scss_formatter {
4161
  public $open = "{";
4162
  public $tagSeparator = ",";
4168
  }
4169
  }
4170
 
4171
+ /**
4172
+ * SCSS server
4173
+ *
4174
+ * @author Leaf Corcoran <leafot@gmail.com>
4175
+ */
4176
  class scss_server {
4177
+ /**
4178
+ * Join path components
4179
+ *
4180
+ * @param string $left Path component, left of the directory separator
4181
+ * @param string $right Path component, right of the directory separator
4182
+ *
4183
+ * @return string
4184
+ */
4185
  protected function join($left, $right) {
4186
+ return rtrim($left, '/\\') . DIRECTORY_SEPARATOR . ltrim($right, '/\\');
4187
  }
4188
 
4189
+ /**
4190
+ * Get name of requested .scss file
4191
+ *
4192
+ * @return string|null
4193
+ */
4194
  protected function inputName() {
4195
+ switch (true) {
4196
+ case isset($_GET['p']):
4197
+ return $_GET['p'];
4198
+ case isset($_SERVER['PATH_INFO']):
4199
+ return $_SERVER['PATH_INFO'];
4200
+ case isset($_SERVER['DOCUMENT_URI']):
4201
+ return substr($_SERVER['DOCUMENT_URI'], strlen($_SERVER['SCRIPT_NAME']));
4202
  }
4203
  }
4204
 
4205
+ /**
4206
+ * Get path to requested .scss file
4207
+ *
4208
+ * @return string
4209
+ */
4210
  protected function findInput() {
4211
+ if ($input = $this->inputName()
4212
+ && strpos($input, '..') === false
4213
+ && substr($input, -5) === '.scss'
4214
+ ) {
4215
  $name = $this->join($this->dir, $input);
4216
+
4217
+ if (is_file($name) && is_readable($name)) {
4218
+ return $name;
4219
+ }
4220
  }
4221
+
4222
  return false;
4223
  }
4224
 
4225
+ /**
4226
+ * Get path to cached .css file
4227
+ *
4228
+ * @return string
4229
+ */
4230
  protected function cacheName($fname) {
4231
+ return $this->join($this->cacheDir, md5($fname) . '.css');
4232
  }
4233
 
4234
+ /**
4235
+ * Get path to cached imports
4236
+ *
4237
+ * @return string
4238
+ */
4239
  protected function importsCacheName($out) {
4240
+ return $out . '.imports';
4241
  }
4242
 
4243
+ /**
4244
+ * Determine whether .scss file needs to be re-compiled.
4245
+ *
4246
+ * @param string $in Input path
4247
+ * @param string $out Output path
4248
+ *
4249
+ * @return boolean True if compile required.
4250
+ */
4251
  protected function needsCompile($in, $out) {
4252
  if (!is_file($out)) return true;
4253
 
4265
  return false;
4266
  }
4267
 
4268
+ /**
4269
+ * Compile .scss file
4270
+ *
4271
+ * @param string $in Input path (.scss)
4272
+ * @param string $out Output path (.css)
4273
+ *
4274
+ * @return string
4275
+ */
4276
  protected function compile($in, $out) {
4277
  $start = microtime(true);
4278
  $css = $this->scss->compile(file_get_contents($in), $in);
4279
  $elapsed = round((microtime(true) - $start), 4);
4280
 
4281
  $v = scssc::$VERSION;
4282
+ $t = date('r');
4283
  $css = "/* compiled by scssphp $v on $t (${elapsed}s) */\n\n" . $css;
4284
 
4285
  file_put_contents($out, $css);
4288
  return $css;
4289
  }
4290
 
4291
+ /**
4292
+ * Compile requested scss and serve css. Outputs HTTP response.
4293
+ */
4294
  public function serve() {
4295
  if ($input = $this->findInput()) {
4296
  $output = $this->cacheName($input);
4297
+ header('Content-type: text/css');
4298
 
4299
  if ($this->needsCompile($input, $output)) {
4300
  try {
4301
  echo $this->compile($input, $output);
4302
+ } catch (Exception $e) {
4303
  header('HTTP/1.1 500 Internal Server Error');
4304
+ echo 'Parse error: ' . $e->getMessage() . "\n";
4305
  }
4306
  } else {
4307
  header('X-SCSS-Cache: true');
4312
  }
4313
 
4314
  header('HTTP/1.0 404 Not Found');
4315
+ header('Content-type: text');
4316
  $v = scssc::$VERSION;
4317
  echo "/* INPUT NOT FOUND scss $v */\n";
4318
  }
4319
 
4320
+ /**
4321
+ * Constructor
4322
+ *
4323
+ * @param string $dir Root directory to .scss files
4324
+ * @param string $cacheDir Cache directory
4325
+ * @param \scssc|null $scss SCSS compiler instance
4326
+ */
4327
  public function __construct($dir, $cacheDir=null, $scss=null) {
4328
  $this->dir = $dir;
4329
 
4330
  if (is_null($cacheDir)) {
4331
+ $cacheDir = $this->join($dir, 'scss_cache');
4332
  }
4333
 
4334
  $this->cacheDir = $cacheDir;
4341
  $this->scss = $scss;
4342
  }
4343
 
4344
+ /**
4345
+ * Helper method to serve compiled scss
4346
+ *
4347
+ * @param string $path Root path
4348
+ */
4349
  static public function serveFrom($path) {
4350
  $server = new self($path);
4351
  $server->serve();
4352
  }
4353
  }
 
 
modules/custom-post-types/comics.php CHANGED
@@ -1,9 +1,9 @@
1
  <?php
2
-
3
  class Jetpack_Comic {
4
  const POST_TYPE = 'jetpack-comic';
5
 
6
- function init() {
7
  static $instance = false;
8
 
9
  if ( ! $instance )
@@ -78,13 +78,13 @@ class Jetpack_Comic {
78
  <?php if ( ! $post_type || 'post' == $post_type ) { ?>
79
  $( '<option>' )
80
  .val( 'post2comic' )
81
- .text( <?php echo json_encode( __( 'Convert to Comic' ) ); ?> )
82
  .appendTo( "select[name='action'], select[name='action2']" );
83
  <?php } ?>
84
  <?php if ( ! $post_type || self::POST_TYPE == $post_type ) { ?>
85
  $( '<option>' )
86
  .val( 'comic2post' )
87
- .text( <?php echo json_encode( __( 'Convert to Post' ) ); ?> )
88
  .appendTo( "select[name='action'], select[name='action2']" );
89
  <?php } ?>
90
 
@@ -108,7 +108,7 @@ class Jetpack_Comic {
108
 
109
  if ( 'post2comic' == $action || 'comic2post' == $action ) {
110
  if ( ! current_user_can( 'publish_posts' ) )
111
- wp_die( __( 'You are not allowed to make this change.' ) );
112
 
113
  $post_ids = array_map( 'intval', $_REQUEST['post'] );
114
 
@@ -142,7 +142,7 @@ class Jetpack_Comic {
142
  $pagenum = $wp_list_table->get_pagenum();
143
  $sendback = add_query_arg( array( 'paged' => $pagenum, 'post_type_changed' => $modified_count ), $sendback );
144
 
145
- wp_redirect( $sendback );
146
  exit();
147
  }
148
  }
@@ -155,7 +155,7 @@ class Jetpack_Comic {
155
 
156
  if ( 'edit.php' == $pagenow && ! empty( $_GET['post_type_changed'] ) ) {
157
  ?><div id="message" class="updated below-h2 jetpack-comic-post-type-conversion" style="display: none;"><p><?php
158
- printf( _n( 'Post converted.', '%s posts converted', $_GET['post_type_changed'] ), number_format_i18n( $_GET['post_type_changed'] ) );
159
  ?></p></div><?php
160
  }
161
  }
@@ -171,7 +171,7 @@ class Jetpack_Comic {
171
  'dragging' => __( 'Drop images to upload', 'jetpack' ),
172
  'uploading' => __( 'Uploading...', 'jetpack' ),
173
  'processing' => __( 'Processing...', 'jetpack' ),
174
- 'unsupported' => __( "Sorry, your browser isn't supported. Upgrade at browsehappy.com." ),
175
  'invalidUpload' => __( 'Only images can be uploaded here.', 'jetpack' ),
176
  'error' => __( "Your upload didn't complete; try again later or cross your fingers and try again right now.", 'jetpack' ),
177
  )
@@ -279,7 +279,7 @@ class Jetpack_Comic {
279
  8 => sprintf( __( 'Comic submitted. <a target="_blank" href="%s">Preview comic</a>', 'jetpack'), esc_url( add_query_arg( 'preview', 'true', get_permalink( $post->ID ) ) ) ),
280
  9 => sprintf( __( 'Comic scheduled for: <strong>%1$s</strong>. <a target="_blank" href="%2$s">Preview comic</a>', 'jetpack' ),
281
  // translators: Publish box date format, see http://php.net/date
282
- date_i18n( __( 'M j, Y @ G:i' ), strtotime( $post->post_date ) ), esc_url( get_permalink($post->ID) ) ),
283
  10 => sprintf( __( 'Comic draft updated. <a target="_blank" href="%s">Preview comic</a>', 'jetpack' ), esc_url( add_query_arg( 'preview', 'true', get_permalink( $post->ID ) ) ) ),
284
  );
285
 
@@ -302,7 +302,7 @@ class Jetpack_Comic {
302
  }
303
 
304
  private function _site_supports_comics() {
305
- return ( site_vertical() == 'comics' || current_theme_supports( self::POST_TYPE ) );
306
  }
307
 
308
  /**
@@ -341,7 +341,7 @@ class Jetpack_Comic {
341
  header( 'Content-Type: application/json' );
342
 
343
  if ( ! wp_verify_nonce( $_REQUEST['nonce'], 'jetpack_comic_upload_nonce' ) )
344
- die( json_encode( array( 'error' => __( 'Invalid or expired nonce.' ) ) ) );
345
 
346
  $_POST['action'] = 'wp_handle_upload';
347
 
@@ -457,7 +457,7 @@ Your webcomic's new site is ready to go. Get started by <a href=\"BLOG_URLwp-adm
457
  Looking for more help with setting up your site? Check out the WordPress.com <a href=\"http://learn.wordpress.com/\">beginner's tutorial</a> and the <a href=\"http://en.support.wordpress.com/comics/\">guide to comics on WordPress.com</a>. Dive right in by <a href=\"BLOG_URLwp-admin/customize.php#title\">publishing your first strip!</a>
458
 
459
  Lots of laughs,
460
- The WordPress.com Team" );
461
  }
462
 
463
  return $welcome_email;
1
  <?php
2
+
3
  class Jetpack_Comic {
4
  const POST_TYPE = 'jetpack-comic';
5
 
6
+ static function init() {
7
  static $instance = false;
8
 
9
  if ( ! $instance )
78
  <?php if ( ! $post_type || 'post' == $post_type ) { ?>
79
  $( '<option>' )
80
  .val( 'post2comic' )
81
+ .text( <?php echo json_encode( __( 'Convert to Comic', 'jetpack' ) ); ?> )
82
  .appendTo( "select[name='action'], select[name='action2']" );
83
  <?php } ?>
84
  <?php if ( ! $post_type || self::POST_TYPE == $post_type ) { ?>
85
  $( '<option>' )
86
  .val( 'comic2post' )
87
+ .text( <?php echo json_encode( __( 'Convert to Post', 'jetpack' ) ); ?> )
88
  .appendTo( "select[name='action'], select[name='action2']" );
89
  <?php } ?>
90
 
108
 
109
  if ( 'post2comic' == $action || 'comic2post' == $action ) {
110
  if ( ! current_user_can( 'publish_posts' ) )
111
+ wp_die( __( 'You are not allowed to make this change.', 'jetpack' ) );
112
 
113
  $post_ids = array_map( 'intval', $_REQUEST['post'] );
114
 
142
  $pagenum = $wp_list_table->get_pagenum();
143
  $sendback = add_query_arg( array( 'paged' => $pagenum, 'post_type_changed' => $modified_count ), $sendback );
144
 
145
+ wp_safe_redirect( $sendback );
146
  exit();
147
  }
148
  }
155
 
156
  if ( 'edit.php' == $pagenow && ! empty( $_GET['post_type_changed'] ) ) {
157
  ?><div id="message" class="updated below-h2 jetpack-comic-post-type-conversion" style="display: none;"><p><?php
158
+ printf( _n( 'Post converted.', '%s posts converted', $_GET['post_type_changed'], 'jetpack' ), number_format_i18n( $_GET['post_type_changed'] ) );
159
  ?></p></div><?php
160
  }
161
  }
171
  'dragging' => __( 'Drop images to upload', 'jetpack' ),
172
  'uploading' => __( 'Uploading...', 'jetpack' ),
173
  'processing' => __( 'Processing...', 'jetpack' ),
174
+ 'unsupported' => __( "Sorry, your browser isn't supported. Upgrade at browsehappy.com.", 'jetpack' ),
175
  'invalidUpload' => __( 'Only images can be uploaded here.', 'jetpack' ),
176
  'error' => __( "Your upload didn't complete; try again later or cross your fingers and try again right now.", 'jetpack' ),
177
  )
279
  8 => sprintf( __( 'Comic submitted. <a target="_blank" href="%s">Preview comic</a>', 'jetpack'), esc_url( add_query_arg( 'preview', 'true', get_permalink( $post->ID ) ) ) ),
280
  9 => sprintf( __( 'Comic scheduled for: <strong>%1$s</strong>. <a target="_blank" href="%2$s">Preview comic</a>', 'jetpack' ),
281
  // translators: Publish box date format, see http://php.net/date
282
+ date_i18n( __( 'M j, Y @ G:i', 'jetpack' ), strtotime( $post->post_date ) ), esc_url( get_permalink($post->ID) ) ),
283
  10 => sprintf( __( 'Comic draft updated. <a target="_blank" href="%s">Preview comic</a>', 'jetpack' ), esc_url( add_query_arg( 'preview', 'true', get_permalink( $post->ID ) ) ) ),
284
  );
285
 
302
  }
303
 
304
  private function _site_supports_comics() {
305
+ return ( ( function_exists( 'site_vertical' ) && 'comics' == site_vertical() ) || current_theme_supports( self::POST_TYPE ) );
306
  }
307
 
308
  /**
341
  header( 'Content-Type: application/json' );
342
 
343
  if ( ! wp_verify_nonce( $_REQUEST['nonce'], 'jetpack_comic_upload_nonce' ) )
344
+ die( json_encode( array( 'error' => __( 'Invalid or expired nonce.', 'jetpack' ) ) ) );
345
 
346
  $_POST['action'] = 'wp_handle_upload';
347
 
457
  Looking for more help with setting up your site? Check out the WordPress.com <a href=\"http://learn.wordpress.com/\">beginner's tutorial</a> and the <a href=\"http://en.support.wordpress.com/comics/\">guide to comics on WordPress.com</a>. Dive right in by <a href=\"BLOG_URLwp-admin/customize.php#title\">publishing your first strip!</a>
458
 
459
  Lots of laughs,
460
+ The WordPress.com Team", 'jetpack' );
461
  }
462
 
463
  return $welcome_email;
modules/custom-post-types/testimonial.php CHANGED
@@ -14,7 +14,7 @@ class Jetpack_Testimonial {
14
 
15
  var $version = '0.1';
16
 
17
- function init() {
18
  static $instance = false;
19
 
20
  if ( ! $instance )
@@ -128,7 +128,7 @@ class Jetpack_Testimonial {
128
  8 => sprintf( __( 'Testimonial submitted. <a target="_blank" href="%s">Preview testimonial</a>', 'jetpack'), esc_url( add_query_arg( 'preview', 'true', get_permalink( $post->ID ) ) ) ),
129
  9 => sprintf( __( 'Testimonial scheduled for: <strong>%1$s</strong>. <a target="_blank" href="%2$s">Preview testimonial</a>', 'jetpack' ),
130
  // translators: Publish box date format, see http://php.net/date
131
- date_i18n( __( 'M j, Y @ G:i' ), strtotime( $post->post_date ) ), esc_url( get_permalink($post->ID) ) ),
132
  10 => sprintf( __( 'Testimonial draft updated. <a target="_blank" href="%s">Preview testimonial</a>', 'jetpack' ), esc_url( add_query_arg( 'preview', 'true', get_permalink( $post->ID ) ) ) ),
133
  );
134
 
@@ -283,4 +283,4 @@ function jetpack_testimonial_custom_control_classes() {
283
  }
284
  }
285
 
286
- add_action( 'init', array( 'Jetpack_Testimonial', 'init' ) );
14
 
15
  var $version = '0.1';
16
 
17
+ static function init() {
18
  static $instance = false;
19
 
20
  if ( ! $instance )
128
  8 => sprintf( __( 'Testimonial submitted. <a target="_blank" href="%s">Preview testimonial</a>', 'jetpack'), esc_url( add_query_arg( 'preview', 'true', get_permalink( $post->ID ) ) ) ),
129
  9 => sprintf( __( 'Testimonial scheduled for: <strong>%1$s</strong>. <a target="_blank" href="%2$s">Preview testimonial</a>', 'jetpack' ),
130
  // translators: Publish box date format, see http://php.net/date
131
+ date_i18n( __( 'M j, Y @ G:i', 'jetpack' ), strtotime( $post->post_date ) ), esc_url( get_permalink($post->ID) ) ),
132
  10 => sprintf( __( 'Testimonial draft updated. <a target="_blank" href="%s">Preview testimonial</a>', 'jetpack' ), esc_url( add_query_arg( 'preview', 'true', get_permalink( $post->ID ) ) ) ),
133
  );
134
 
283
  }
284
  }
285
 
286
+ add_action( 'init', array( 'Jetpack_Testimonial', 'init' ) );
modules/debug.php ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Deprecated. No longer needed.
4
+ *
5
+ * @package Jetpack
6
+ */
modules/enhanced-distribution.php CHANGED
@@ -5,6 +5,7 @@
5
  * Sort Order: 100
6
  * First Introduced: 1.2
7
  * Requires Connection: Yes
 
8
  */
9
 
10
  Jetpack_Sync::sync_posts( __FILE__ );
5
  * Sort Order: 100
6
  * First Introduced: 1.2
7
  * Requires Connection: Yes
8
+ * Auto Activate: Public
9
  */
10
 
11
  Jetpack_Sync::sync_posts( __FILE__ );
modules/gravatar-hovercards.php CHANGED
@@ -5,6 +5,7 @@
5
  * Sort Order: 8
6
  * First Introduced: 1.1
7
  * Requires Connection: No
 
8
  */
9
 
10
  define( 'GROFILES__CACHE_BUSTER', gmdate( 'YM' ) . 'aa' ); // Break CDN cache, increment when gravatar.com/js/gprofiles.js changes
5
  * Sort Order: 8
6
  * First Introduced: 1.1
7
  * Requires Connection: No
8
+ * Auto Activate: Yes
9
  */
10
 
11
  define( 'GROFILES__CACHE_BUSTER', gmdate( 'YM' ) . 'aa' ); // Break CDN cache, increment when gravatar.com/js/gprofiles.js changes
modules/holiday-snow.php CHANGED
@@ -6,6 +6,7 @@
6
  * Not a module that is activated/deactivated
7
  * First Introduced: 2.0.3 ??
8
  * Requires Connection: No
 
9
  */
10
 
11
  class Jetpack_Holiday_Snow_Settings {
6
  * Not a module that is activated/deactivated
7
  * First Introduced: 2.0.3 ??
8
  * Requires Connection: No
9
+ * Auto Activate: Yes
10
  */
11
 
12
  class Jetpack_Holiday_Snow_Settings {
modules/infinite-scroll.php CHANGED
@@ -5,6 +5,7 @@
5
  * Sort Order: 14
6
  * First Introduced: 2.0
7
  * Requires Connection: No
 
8
  */
9
 
10
  /**
5
  * Sort Order: 14
6
  * First Introduced: 2.0
7
  * Requires Connection: No
8
+ * Auto Activate: No
9
  */
10
 
11
  /**
modules/json-api.php CHANGED
@@ -5,6 +5,7 @@
5
  * Sort Order: 100
6
  * First Introduced: 1.9
7
  * Requires Connection: Yes
 
8
  */
9
 
10
  function jetpack_json_api_toggle() {
5
  * Sort Order: 100
6
  * First Introduced: 1.9
7
  * Requires Connection: Yes
8
+ * Auto Activate: Public
9
  */
10
 
11
  function jetpack_json_api_toggle() {
modules/latex.php CHANGED
@@ -5,6 +5,7 @@
5
  * Sort Order: 12
6
  * First Introduced: 1.1
7
  * Requires Connection: Yes
 
8
  */
9
 
10
  /**
5
  * Sort Order: 12
6
  * First Introduced: 1.1
7
  * Requires Connection: Yes
8
+ * Auto Activate: Yes
9
  */
10
 
11
  /**
modules/likes.php CHANGED
@@ -5,6 +5,7 @@
5
  * First Introduced: 2.2
6
  * Sort Order: 4
7
  * Requires Connection: Yes
 
8
  */
9
  class Jetpack_Likes {
10
  var $version = '20130620a';
@@ -520,11 +521,11 @@ class Jetpack_Likes {
520
  .fixed .column-likes .post-com-count { background-image: none; }
521
  .fixed .column-likes .comment-count { background-color: #888; }
522
  .fixed .column-likes .comment-count:hover { background-color: #D54E21; }
523
- .admin-color-mp6 .fixed .column-likes .post-com-count::after { border: none !important; }
524
- .admin-color-mp6 .fixed .column-likes .comment-count { background-color: #bbb; }
525
- .admin-color-mp6 .fixed .column-likes .comment-count:hover { background-color: #2ea2cc; }
526
- .admin-color-mp6 .fixed .column-likes .vers img { display: none; }
527
- .admin-color-mp6 .fixed .column-likes .vers:before {font:20px/1 dashicons;content: '\f155';-webkit-font-smoothing:antialiased;}
528
  </style> <?php
529
  }
530
 
@@ -533,10 +534,14 @@ class Jetpack_Likes {
533
  */
534
  function enqueue_admin_scripts() {
535
  if ( empty( $_GET['post_type'] ) || 'post' == $_GET['post_type'] || 'page' == $_GET['post_type'] ) {
536
- if ( $this->in_jetpack )
537
  wp_enqueue_script( 'likes-post-count', plugins_url( 'modules/likes/post-count.js', dirname( __FILE__ ) ), array( 'jquery' ), JETPACK__VERSION );
538
- else
 
 
539
  wp_enqueue_script( 'likes-post-count', plugins_url( 'likes/post-count.js', dirname( __FILE__ ) ), array( 'jquery' ), JETPACK__VERSION );
 
 
540
  }
541
  }
542
 
@@ -586,10 +591,6 @@ class Jetpack_Likes {
586
  if ( ! $this->is_likes_visible() )
587
  return $content;
588
 
589
- $protocol = 'http';
590
- if ( is_ssl() )
591
- $protocol = 'https';
592
-
593
  if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
594
  $blog_id = get_current_blog_id();
595
  $bloginfo = get_blog_details( (int) $blog_id );
@@ -610,7 +611,7 @@ class Jetpack_Likes {
610
  */
611
  $uniqid = uniqid();
612
 
613
- $src = sprintf( '%1$s://widgets.wp.com/likes/#blog_id=%2$d&amp;post_id=%3$d&amp;origin=%1$s://%4$s&amp;obj_id=%2$d-%3$d-%5$s', $protocol, $blog_id, $post->ID, $domain, $uniqid );
614
  $name = sprintf( 'like-post-frame-%1$d-%2$d-%3$s', $blog_id, $post->ID, $uniqid );
615
  $wrapper = sprintf( 'like-post-wrapper-%1$d-%2$d-%3$s', $blog_id, $post->ID, $uniqid );
616
 
5
  * First Introduced: 2.2
6
  * Sort Order: 4
7
  * Requires Connection: Yes
8
+ * Auto Activate: No
9
  */
10
  class Jetpack_Likes {
11
  var $version = '20130620a';
521
  .fixed .column-likes .post-com-count { background-image: none; }
522
  .fixed .column-likes .comment-count { background-color: #888; }
523
  .fixed .column-likes .comment-count:hover { background-color: #D54E21; }
524
+ .mp6 .fixed .column-likes .post-com-count::after { border: none !important; }
525
+ .mp6 .fixed .column-likes .comment-count { background-color: #bbb; }
526
+ .mp6 .fixed .column-likes .comment-count:hover { background-color: #2ea2cc; }
527
+ .mp6 .fixed .column-likes .vers img { display: none; }
528
+ .mp6 .fixed .column-likes .vers:before {font:20px/1 dashicons;content: '\f155';-webkit-font-smoothing:antialiased;}
529
  </style> <?php
530
  }
531
 
534
  */
535
  function enqueue_admin_scripts() {
536
  if ( empty( $_GET['post_type'] ) || 'post' == $_GET['post_type'] || 'page' == $_GET['post_type'] ) {
537
+ if ( $this->in_jetpack ) {
538
  wp_enqueue_script( 'likes-post-count', plugins_url( 'modules/likes/post-count.js', dirname( __FILE__ ) ), array( 'jquery' ), JETPACK__VERSION );
539
+ wp_enqueue_script( 'likes-post-count-jetpack', plugins_url( 'modules/likes/post-count-jetpack.js', dirname( __FILE__ ) ), array( 'likes-post-count' ), JETPACK__VERSION );
540
+ } else {
541
+ wp_enqueue_script( 'jquery.wpcom-proxy-request', "/wp-content/js/jquery/jquery.wpcom-proxy-request.js", array('jquery'), NULL, true );
542
  wp_enqueue_script( 'likes-post-count', plugins_url( 'likes/post-count.js', dirname( __FILE__ ) ), array( 'jquery' ), JETPACK__VERSION );
543
+ wp_enqueue_script( 'likes-post-count-wpcom', plugins_url( 'likes/post-count-wpcom.js', dirname( __FILE__ ) ), array( 'likes-post-count', 'jquery.wpcom-proxy-request' ), JETPACK__VERSION );
544
+ }
545
  }
546
  }
547
 
591
  if ( ! $this->is_likes_visible() )
592
  return $content;
593
 
 
 
 
 
594
  if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
595
  $blog_id = get_current_blog_id();
596
  $bloginfo = get_blog_details( (int) $blog_id );
611
  */
612
  $uniqid = uniqid();
613
 
614
+ $src = sprintf( '//widgets.wp.com/likes/#blog_id=%1$d&amp;post_id=%2$d&amp;origin=%3$s&amp;obj_id=%1$d-%2$d-%4$s', $blog_id, $post->ID, $domain, $uniqid );
615
  $name = sprintf( 'like-post-frame-%1$d-%2$d-%3$s', $blog_id, $post->ID, $uniqid );
616
  $wrapper = sprintf( 'like-post-wrapper-%1$d-%2$d-%3$s', $blog_id, $post->ID, $uniqid );
617
 
modules/likes/post-count-jetpack.js ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ var wpPostLikeCount = wpPostLikeCount || {};
2
+
3
+ (function($) {
4
+
5
+ wpPostLikeCount = jQuery.extend( wpPostLikeCount, {
6
+ request: function( options ) {
7
+ return $.ajax( {
8
+ type: 'GET',
9
+ url: wpPostLikeCount.jsonAPIbase + options.path,
10
+ dataType : "jsonp",
11
+ data: options.data,
12
+ success: function( response ) { options.success( response ); },
13
+ error: function( response ) { options.error( response ); }
14
+ } );
15
+ }
16
+ } );
17
+
18
+ })(jQuery);
modules/likes/post-count.js CHANGED
@@ -1,8 +1,8 @@
1
- var wpPostLikeCount;
2
 
3
  (function($) {
4
 
5
- wpPostLikeCount = {
6
 
7
  jsonAPIbase: 'https://public-api.wordpress.com/rest/v1',
8
  APIqueue: [],
@@ -47,23 +47,11 @@ var wpPostLikeCount;
47
  }
48
 
49
  wpPostLikeCount.request( batchRequest );
50
- },
51
-
52
- request: function( options ) {
53
- return $.ajax( {
54
- type: 'GET',
55
- url: wpPostLikeCount.jsonAPIbase + options.path,
56
- dataType : "jsonp",
57
- data: options.data,
58
- success: function( response ) { options.success( response ) },
59
- error: function( response ) { options.error( response ) }
60
- } )
61
  }
62
-
63
- };
64
 
65
  })(jQuery);
66
 
67
  jQuery(document).ready(function($) {
68
  wpPostLikeCount.wpPostLikeCount();
69
- });
1
+ var wpPostLikeCount = wpPostLikeCount || {};
2
 
3
  (function($) {
4
 
5
+ wpPostLikeCount = jQuery.extend( wpPostLikeCount, {
6
 
7
  jsonAPIbase: 'https://public-api.wordpress.com/rest/v1',
8
  APIqueue: [],
47
  }
48
 
49
  wpPostLikeCount.request( batchRequest );
 
 
 
 
 
 
 
 
 
 
 
50
  }
51
+ } );
 
52
 
53
  })(jQuery);
54
 
55
  jQuery(document).ready(function($) {
56
  wpPostLikeCount.wpPostLikeCount();
57
+ });
modules/likes/style.css CHANGED
@@ -1,7 +1,7 @@
1
  #wpadminbar li#wp-admin-bar-admin-bar-likes-widget {
2
  width: 61px;
 
3
  }
4
-
5
  #wpadminbar iframe.admin-bar-likes-widget {
6
  width: 61px;
7
  height: 28px;
1
  #wpadminbar li#wp-admin-bar-admin-bar-likes-widget {
2
  width: 61px;
3
+ overflow: hidden;
4
  }
 
5
  #wpadminbar iframe.admin-bar-likes-widget {
6
  width: 61px;
7
  height: 28px;
modules/minileven.php CHANGED
@@ -6,6 +6,7 @@
6
  * Sort Order: 11
7
  * First Introduced: 1.8
8
  * Requires Connection: No
 
9
  */
10
 
11
  function jetpack_load_minileven() {
6
  * Sort Order: 11
7
  * First Introduced: 1.8
8
  * Requires Connection: No
9
+ * Auto Activate: No
10
  */
11
 
12
  function jetpack_load_minileven() {
modules/minileven/theme/pub/minileven/functions.php CHANGED
@@ -40,6 +40,11 @@ function minileven_setup() {
40
  */
41
  require( get_template_directory() . '/inc/tweaks.php' );
42
 
 
 
 
 
 
43
  /* Make Minileven available for translation.
44
  * Translations can be added to the /languages/ directory.
45
  * If you're building a theme based on Minileven, use a find and replace
@@ -176,11 +181,6 @@ function minileven_get_background() {
176
  return false;
177
  }
178
 
179
- /**
180
- * Implement the Custom Header functions
181
- */
182
- require( get_template_directory() . '/inc/custom-header.php' );
183
-
184
  /**
185
  * If the user has set a static front page, show all posts on the front page, instead of a static page.
186
  */
40
  */
41
  require( get_template_directory() . '/inc/tweaks.php' );
42
 
43
+ /**
44
+ * Implement the Custom Header functions
45
+ */
46
+ require( get_template_directory() . '/inc/custom-header.php' );
47
+
48
  /* Make Minileven available for translation.
49
  * Translations can be added to the /languages/ directory.
50
  * If you're building a theme based on Minileven, use a find and replace
181
  return false;
182
  }
183
 
 
 
 
 
 
184
  /**
185
  * If the user has set a static front page, show all posts on the front page, instead of a static page.
186
  */
modules/minileven/theme/pub/minileven/style.css CHANGED
@@ -1,8 +1,8 @@
1
  /*
2
  Theme Name: Minileven
3
- Theme URI: http://automattic.com
4
  Author: Automattic
5
- Author URI: http://automattic.com
6
  Description: The Minileven theme is a clean, lightweight mobile experience for your blog based on Twenty Eleven.
7
  Version: 2.0-wpcom
8
  License: GNU General Public License
@@ -1483,8 +1483,11 @@ p.comment-form-comment {
1483
  display: block;
1484
  }
1485
  #wpl-mustlogin {
1486
- width: 240px !important;
1487
- margin-left: -60px !important;
 
 
 
1488
  }
1489
 
1490
  /* WP.com comment form */
1
  /*
2
  Theme Name: Minileven
3
+ Theme URI: http://theme.wordpress.com
4
  Author: Automattic
5
+ Author URI: http://theme.wordpress.com
6
  Description: The Minileven theme is a clean, lightweight mobile experience for your blog based on Twenty Eleven.
7
  Version: 2.0-wpcom
8
  License: GNU General Public License
1483
  display: block;
1484
  }
1485
  #wpl-mustlogin {
1486
+ width: 240px !important;
1487
+ margin-left: -60px !important;
1488
+ }
1489
+ img.latex {
1490
+ display: inline;
1491
  }
1492
 
1493
  /* WP.com comment form */
modules/mobile-push.php CHANGED
@@ -5,6 +5,7 @@
5
  * Sort Order: 100
6
  * First Introduced: 1.9
7
  * Requires Connection: Yes
 
8
  */
9
 
10
  Jetpack_Sync::sync_comments( __FILE__, array(
5
  * Sort Order: 100
6
  * First Introduced: 1.9
7
  * Requires Connection: Yes
8
+ * Auto Activate: Yes
9
  */
10
 
11
  Jetpack_Sync::sync_comments( __FILE__, array(
modules/module-extras.php CHANGED
@@ -4,57 +4,16 @@
4
  * For example, if a module shouldn't be activatable unless certain conditions are met, the code belongs in this file.
5
  */
6
 
7
- /**
8
- * INFINITE SCROLL
9
- */
10
-
11
- /**
12
- * Load theme's infinite scroll annotation file, if present in the IS plugin.
13
- * The `setup_theme` action is used because the annotation files should be using `after_setup_theme` to register support for IS.
14
- *
15
- * As released in Jetpack 2.0, a child theme's parent wasn't checked for in the plugin's bundled support, hence the convoluted way the parent is checked for now.
16
- *
17
- * @uses is_admin, wp_get_theme, get_theme, get_current_theme, apply_filters
18
- * @action setup_theme
19
- * @return null
20
- */
21
- function jetpack_load_infinite_scroll_annotation() {
22
- if ( is_admin() && isset( $_GET['page'] ) && 'jetpack' == $_GET['page'] ) {
23
- $theme = function_exists( 'wp_get_theme' ) ? wp_get_theme() : get_theme( get_current_theme() );
24
-
25
- if ( ! is_a( $theme, 'WP_Theme' ) && ! is_array( $theme ) )
26
- return;
27
-
28
- $customization_file = apply_filters( 'infinite_scroll_customization_file', dirname( __FILE__ ) . "/infinite-scroll/themes/{$theme['Stylesheet']}.php", $theme['Stylesheet'] );
29
-
30
- if ( is_readable( $customization_file ) ) {
31
- require_once( $customization_file );
32
- }
33
- elseif ( ! empty( $theme['Template'] ) ) {
34
- $customization_file = dirname( __FILE__ ) . "/infinite-scroll/themes/{$theme['Template']}.php";
35
-
36
- if ( is_readable( $customization_file ) )
37
- require_once( $customization_file );
38
- }
39
- }
40
- }
41
- add_action( 'setup_theme', 'jetpack_load_infinite_scroll_annotation' );
42
-
43
- /**
44
- * Prevent IS from being activated if theme doesn't support it
45
- *
46
- * @param bool $can_activate
47
- * @filter jetpack_can_activate_infinite-scroll
48
- * @return bool
49
- */
50
- function jetpack_can_activate_infinite_scroll( $can_activate ) {
51
- return (bool) current_theme_supports( 'infinite-scroll' );
52
- }
53
- add_filter( 'jetpack_can_activate_infinite-scroll', 'jetpack_can_activate_infinite_scroll' );
54
-
55
  // Happy Holidays!
56
  require_once( dirname( __FILE__ ) . '/holiday-snow.php' );
57
 
58
- require_once( dirname( __FILE__ ) . '/featured-content/featured-content.php' );
 
59
 
60
- require_once( dirname( __FILE__ ) . '/social-links.php' );
 
 
 
 
 
 
4
  * For example, if a module shouldn't be activatable unless certain conditions are met, the code belongs in this file.
5
  */
6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
  // Happy Holidays!
8
  require_once( dirname( __FILE__ ) . '/holiday-snow.php' );
9
 
10
+ // Include extra tools that aren't modules, in a filterable way
11
+ $jetpack_tools_to_include = apply_filters( 'jetpack-tools-to-include', array( 'theme-tools.php' ) );
12
 
13
+ if ( ! empty( $jetpack_tools_to_include ) ) {
14
+ foreach ( $jetpack_tools_to_include as $tool ) {
15
+ if ( file_exists( JETPACK__PLUGIN_DIR . '/modules/' . $tool ) ) {
16
+ require_once( JETPACK__PLUGIN_DIR . '/modules/' . $tool );
17
+ }
18
+ }
19
+ }
modules/module-info.php CHANGED
@@ -777,30 +777,9 @@ function jetpack_likes_more_link() {
777
  add_action( 'jetpack_learn_more_button_likes', 'jetpack_likes_more_link' );
778
  // Likes: STOP
779
 
780
- // Debug: START
781
- function jetpack_debug_more_info() { ?>
782
-
783
- <h4><?php esc_html_e( 'Debug' , 'jetpack' ); ?></h4>
784
-
785
- <p><?php esc_html_e( "A debugging platform for the Jetpack plugin. Find out why Jetpack isn't working for you and submit a help request direct from your Dashboard.", 'jetpack' ); ?></p>
786
- <?php if ( Jetpack::is_module_active( 'debug' ) ) : ?>
787
- <p><a href="<?php echo admin_url( 'admin.php?page=jetpack-debugger' ); ?>"><?php esc_html_e( "Click here to start debugging.", 'jetpack' ); ?></a></p>
788
-
789
- <?php endif; ?>
790
- <?php
791
- }
792
-
793
- function jetpack_debug_more_link() {
794
- echo '<a class="button-secondary more-info-link" href="http://jetpack.me/support/debug/">' . __( 'Learn More', 'jetpack' ) . '</a>';
795
- }
796
-
797
- add_action( 'jetpack_module_more_info_debug', 'jetpack_debug_more_info' );
798
- add_action( 'jetpack_module_more_info_connected_debug', 'jetpack_debug_more_info' );
799
- add_action( 'jetpack_learn_more_button_debug', 'jetpack_debug_more_link' );
800
- // Debug: STOP
801
-
802
  // Omnisearch: START
803
- function jetpack_omnisearch_more_info() { ?>
 
804
 
805
  <h4><?php esc_html_e( 'Omnisearch' , 'jetpack' ); ?></h4>
806
 
@@ -812,7 +791,7 @@ function jetpack_omnisearch_more_info() { ?>
812
  <?php echo Jetpack_Omnisearch::get_omnisearch_form(); ?>
813
  <?php endif; ?>
814
 
815
- <?php
816
  }
817
 
818
  function jetpack_omnisearch_more_link() {
@@ -822,3 +801,41 @@ function jetpack_omnisearch_more_link() {
822
  add_action( 'jetpack_module_more_info_omnisearch', 'jetpack_omnisearch_more_info' );
823
  add_action( 'jetpack_learn_more_button_omnisearch', 'jetpack_omnisearch_more_link' );
824
  // Omnisearch: STOP
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
777
  add_action( 'jetpack_learn_more_button_likes', 'jetpack_likes_more_link' );
778
  // Likes: STOP
779
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
780
  // Omnisearch: START
781
+ function jetpack_omnisearch_more_info() {
782
+ ?>
783
 
784
  <h4><?php esc_html_e( 'Omnisearch' , 'jetpack' ); ?></h4>
785
 
791
  <?php echo Jetpack_Omnisearch::get_omnisearch_form(); ?>
792
  <?php endif; ?>
793
 
794
+ <?php
795
  }
796
 
797
  function jetpack_omnisearch_more_link() {
801
  add_action( 'jetpack_module_more_info_omnisearch', 'jetpack_omnisearch_more_info' );
802
  add_action( 'jetpack_learn_more_button_omnisearch', 'jetpack_omnisearch_more_link' );
803
  // Omnisearch: STOP
804
+
805
+ // Widget Visibility: START
806
+ function jetpack_widget_visibility_more_info() { ?>
807
+ <h4><?php esc_html_e( 'Widget Visibility', 'jetpack' ); ?></h4>
808
+
809
+ <p><?php esc_html_e( 'Control which pages your widgets appear on with Widget Visibility.', 'jetpack' ); ?></p>
810
+ <p><?php esc_html_e( 'To control visibility, expand the widget and click the Visibility button next to the Save button, and then, choose a set of visibility options.', 'jetpack' ); ?></p>
811
+ <p><?php esc_html_e( 'For example, if you wanted the Archives widget to only appear on category archives and error pages, choose "Show" from the first dropdown and then add two rules: "Page is 404 Error Page" and "Category is All Category Pages."', 'jetpack' ); ?></p>
812
+ <p><?php esc_html_e( 'You can also hide widgets based on the current page. For example, if you don\'t want the Archives widget to appear on search results pages, choose "Hide" and "Page is Search results."', 'jetpack' ); ?></p>
813
+ <?php
814
+ }
815
+
816
+ function jetpack_widget_visibility_more_link() {
817
+ echo '<a class="button-secondary more-info-link" href="http://jetpack.me/support/widget-visibility/">' . __( 'Learn More', 'jetpack' ) . '</a>';
818
+ }
819
+
820
+ add_action( 'jetpack_module_more_info_widget-visibility', 'jetpack_widget_visibility_more_info' );
821
+ add_action( 'jetpack_learn_more_button_widget-visibility', 'jetpack_widget_visibility_more_link' );
822
+ // Widget Visibility: STOP
823
+
824
+
825
+ // WordPress.com Connect: START
826
+ function jetpack_wpcc_more_info() { ?>
827
+ <h4><?php esc_html_e( 'WordPress.com Connect' , 'jetpack' ); ?></h4>
828
+
829
+ <p><?php esc_html_e( 'With WordPress.com Connect, your users will be able to log into your WordPress admin with the same credentials they use to log into WordPress.com. It\'s safe and secure.' , 'jetpack' ); ?></p>
830
+ <p><?php esc_html_e( 'Once enabled, a "Connect with WordPress.com" option will be added to your existing log-in form.' , 'jetpack' ); ?></p>
831
+
832
+ <?php
833
+ }
834
+
835
+ function jetpack_wpcc_more_link() {
836
+ echo '<a class="button-secondary more-info-link" href="http://jetpack.me/support/wpcc/">' . __( 'Learn More', 'jetpack' ) . '</a>';
837
+ }
838
+
839
+ add_action( 'jetpack_module_more_info_wpcc', 'jetpack_wpcc_more_info' );
840
+ add_action( 'jetpack_learn_more_button_wpcc', 'jetpack_wpcc_more_link' );
841
+ // WordPress.com Connect: STOP
modules/notes.php CHANGED
@@ -5,6 +5,7 @@
5
  * Sort Order: 1
6
  * First Introduced: 1.9
7
  * Requires Connection: Yes
 
8
  */
9
 
10
  if ( !defined( 'JETPACK_NOTES__CACHE_BUSTER' ) ) define( 'JETPACK_NOTES__CACHE_BUSTER', JETPACK__VERSION . '-' . gmdate( 'oW' ) );
5
  * Sort Order: 1
6
  * First Introduced: 1.9
7
  * Requires Connection: Yes
8
+ * Auto Activate: Yes
9
  */
10
 
11
  if ( !defined( 'JETPACK_NOTES__CACHE_BUSTER' ) ) define( 'JETPACK_NOTES__CACHE_BUSTER', JETPACK__VERSION . '-' . gmdate( 'oW' ) );
modules/omnisearch.php CHANGED
@@ -6,6 +6,7 @@
6
  * Sort Order: 8
7
  * First Introduced: 2.3
8
  * Requires Connection: No
 
9
  */
10
 
11
  // Only do Jetpack Omnisearch if there isn't already a Core WP_Omnisearch Class.
6
  * Sort Order: 8
7
  * First Introduced: 2.3
8
  * Requires Connection: No
9
+ * Auto Activate: Yes
10
  */
11
 
12
  // Only do Jetpack Omnisearch if there isn't already a Core WP_Omnisearch Class.
modules/omnisearch/omnisearch-core.php CHANGED
@@ -27,6 +27,11 @@ class Jetpack_Omnisearch {
27
  require_once( dirname(__FILE__) . '/omnisearch-comments.php' );
28
  new Jetpack_Omnisearch_Comments;
29
 
 
 
 
 
 
30
  if ( current_user_can( 'install_plugins' ) ) {
31
  require_once( dirname(__FILE__) . '/omnisearch-plugins.php' );
32
  new Jetpack_Omnisearch_Plugins;
27
  require_once( dirname(__FILE__) . '/omnisearch-comments.php' );
28
  new Jetpack_Omnisearch_Comments;
29
 
30
+ if ( current_user_can( 'upload_files' ) ) {
31
+ require_once( dirname(__FILE__) . '/omnisearch-media.php' );
32
+ new Jetpack_Omnisearch_Media;
33
+ }
34
+
35
  if ( current_user_can( 'install_plugins' ) ) {
36
  require_once( dirname(__FILE__) . '/omnisearch-plugins.php' );
37
  new Jetpack_Omnisearch_Plugins;
modules/omnisearch/omnisearch-media.php ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if( ! class_exists( 'WP_Media_List_Table' ) )
4
+ require_once( ABSPATH . 'wp-admin/includes/class-wp-media-list-table.php' );
5
+
6
+ class Jetpack_Omnisearch_Media extends WP_Media_List_Table {
7
+ static $instance;
8
+
9
+ function __construct() {
10
+ self::$instance = $this;
11
+ add_filter( 'omnisearch_results', array( $this, 'search'), 10, 2 );
12
+ }
13
+
14
+ function search( $results, $search_term ) {
15
+ $search_url = esc_url( add_query_arg( 's', $search_term, admin_url( 'upload.php' ) ) );
16
+ $search_link = sprintf( ' <a href="%s" class="add-new-h2">%s</a>', $search_url, esc_html__('Search Media', 'jetpack') );
17
+ $html = '<h2>' . esc_html__('Media', 'jetpack') . $search_link . '</h2>';
18
+ parent::__construct();
19
+
20
+ ob_start();
21
+ $this->prepare_items();
22
+ $columns = $this->get_columns();
23
+ unset( $columns['cb'] );
24
+ $this->_column_headers = array( $columns, array(), array() );
25
+ $this->display();
26
+ $html .= ob_get_clean();
27
+
28
+ $label = __( 'Media', 'jetpack' );
29
+ $results[ $label ] = $html;
30
+ return $results;
31
+ }
32
+
33
+ function get_sortable_columns() {
34
+ return array();
35
+ }
36
+
37
+ function get_bulk_actions() {
38
+ return array();
39
+ }
40
+
41
+ function pagination( $which ) {}
42
+
43
+ function extra_tablenav( $which ) {}
44
+ }
45
+
46
+
modules/omnisearch/omnisearch.css CHANGED
@@ -19,7 +19,7 @@ input.omnisearch {
19
  width: 100%;
20
  }
21
 
22
- .admin-color-mp6 input.omnisearch {
23
  line-height: 1.35;
24
  }
25
 
@@ -40,7 +40,7 @@ button.omnisearch-submit {
40
  bottom: 0;
41
  }
42
 
43
- .admin-color-mp6 button.omnisearch-submit {
44
  padding: 0.3em 0.5em 0.1em;
45
  }
46
 
@@ -113,10 +113,22 @@ button.omnisearch-submit span {
113
  width: 15%;
114
  }
115
 
116
- .comments .column-author {
117
  width: 20%;
118
  }
119
 
 
 
 
 
 
 
 
 
 
 
 
 
120
  .tablenav {
121
  height: 0;
122
  }
@@ -124,3 +136,4 @@ button.omnisearch-submit span {
124
  .omnisearch-results .tablenav.top {
125
  margin: 5px 0;
126
  }
 
19
  width: 100%;
20
  }
21
 
22
+ .mp6 input.omnisearch {
23
  line-height: 1.35;
24
  }
25
 
40
  bottom: 0;
41
  }
42
 
43
+ .mp6 button.omnisearch-submit {
44
  padding: 0.3em 0.5em 0.1em;
45
  }
46
 
113
  width: 15%;
114
  }
115
 
116
+ .wp-list-table.comments .column-author {
117
  width: 20%;
118
  }
119
 
120
+ .wp-list-table.media th {
121
+ white-space: nowrap;
122
+ }
123
+
124
+ .wp-list-table.media .column-parent {
125
+ width: 15%;
126
+ }
127
+
128
+ .wp-list-table.media .column-comments span.vers {
129
+ display: block;
130
+ }
131
+
132
  .tablenav {
133
  height: 0;
134
  }
136
  .omnisearch-results .tablenav.top {
137
  margin: 5px 0;
138
  }
139
+
modules/omnisearch/rtl/omnisearch-rtl.css CHANGED
@@ -1,4 +1,4 @@
1
- /* This file was automatically generated on Jun 19 2013 20:38:31 */
2
 
3
 
4
  h2.page-title small {
@@ -21,7 +21,7 @@ input.omnisearch {
21
  width: 100%;
22
  }
23
 
24
- .admin-color-mp6 input.omnisearch {
25
  line-height: 1.35;
26
  }
27
 
@@ -42,7 +42,7 @@ button.omnisearch-submit {
42
  bottom: 0;
43
  }
44
 
45
- .admin-color-mp6 button.omnisearch-submit {
46
  padding: 0.3em 0.5em 0.1em;
47
  }
48
 
@@ -115,10 +115,22 @@ button.omnisearch-submit span {
115
  width: 15%;
116
  }
117
 
118
- .comments .column-author {
119
  width: 20%;
120
  }
121
 
 
 
 
 
 
 
 
 
 
 
 
 
122
  .tablenav {
123
  height: 0;
124
  }
@@ -126,3 +138,4 @@ button.omnisearch-submit span {
126
  .omnisearch-results .tablenav.top {
127
  margin: 5px 0;
128
  }
 
1
+ /* This file was automatically generated on Aug 15 2013 16:01:51 */
2
 
3
 
4
  h2.page-title small {
21
  width: 100%;
22
  }
23
 
24
+ .mp6 input.omnisearch {
25
  line-height: 1.35;
26
  }
27
 
42
  bottom: 0;
43
  }
44
 
45
+ .mp6 button.omnisearch-submit {
46
  padding: 0.3em 0.5em 0.1em;
47
  }
48
 
115
  width: 15%;
116
  }
117
 
118
+ .wp-list-table.comments .column-author {
119
  width: 20%;
120
  }
121
 
122
+ .wp-list-table.media th {
123
+ white-space: nowrap;
124
+ }
125
+
126
+ .wp-list-table.media .column-parent {
127
+ width: 15%;
128
+ }
129
+
130
+ .wp-list-table.media .column-comments span.vers {
131
+ display: block;
132
+ }
133
+
134
  .tablenav {
135
  height: 0;
136
  }
138
  .omnisearch-results .tablenav.top {
139
  margin: 5px 0;
140
  }
141
+
modules/photon.php CHANGED
@@ -5,6 +5,7 @@
5
  * Sort Order: 15
6
  * First Introduced: 2.0
7
  * Requires Connection: Yes
 
8
  */
9
 
10
  Jetpack_Photon::instance();
5
  * Sort Order: 15
6
  * First Introduced: 2.0
7
  * Requires Connection: Yes
8
+ * Auto Activate: No
9
  */
10
 
11
  Jetpack_Photon::instance();
modules/post-by-email.php CHANGED
@@ -6,6 +6,7 @@
6
  * First Introduced: 2.0
7
  * Sort Order: 4
8
  * Requires Connection: Yes
 
9
  */
10
 
11
  add_action( 'jetpack_modules_loaded', array( 'Jetpack_Post_By_Email', 'init' ) );
6
  * First Introduced: 2.0
7
  * Sort Order: 4
8
  * Requires Connection: Yes
9
+ * Auto Activate: Yes
10
  */
11
 
12
  add_action( 'jetpack_modules_loaded', array( 'Jetpack_Post_By_Email', 'init' ) );
modules/publicize.php CHANGED
@@ -5,6 +5,7 @@
5
  * Sort Order: 1
6
  * First Introduced: 2.0
7
  * Requires Connection: Yes
 
8
  */
9
 
10
  class Jetpack_Publicize {
5
  * Sort Order: 1
6
  * First Introduced: 2.0
7
  * Requires Connection: Yes
8
+ * Auto Activate: Yes
9
  */
10
 
11
  class Jetpack_Publicize {
modules/publicize/assets/publicize.js CHANGED
@@ -70,7 +70,7 @@ jQuery( function( $ ) {
70
 
71
  $.post( ajaxurl, 'action=publicize_'+ service + '_options_save&connection=' + connection + '&selected_id=' + id + '&token=' + token + '&type=' + type + '&_wpnonce=' + nonce + '&global=' + global_conn + '&global_nonce=' + global_nonce, function( response ) {
72
  tb_remove();
73
- window.location = 'options-general.php?page=sharing';
74
  } );
75
 
76
  } );
70
 
71
  $.post( ajaxurl, 'action=publicize_'+ service + '_options_save&connection=' + connection + '&selected_id=' + id + '&token=' + token + '&type=' + type + '&_wpnonce=' + nonce + '&global=' + global_conn + '&global_nonce=' + global_nonce, function( response ) {
72
  tb_remove();
73
+ top.location = 'options-general.php?page=sharing';
74
  } );
75
 
76
  } );
modules/publicize/assets/rtl/publicize-rtl.css CHANGED
@@ -1,4 +1,4 @@
1
- /* This file was automatically generated on Jun 24 2013 19:39:49 */
2
 
3
  div#publicize-services-block {
4
  display: inline-block;
@@ -23,6 +23,7 @@ span#facebook { background: url( ../facebook-logo.png ) 50% 19px no-repeat; back
23
  span#twitter { background: url( ../twitter-logo.png ) 50% 19px no-repeat; background-size: 125px 47px; }
24
  span#linkedin { background: url( ../linkedin-logo.png ) 50% 19px no-repeat; background-size: 125px 47px; }
25
  span#tumblr { background: url( ../tumblr-logo.png ) 50% 19px no-repeat; background-size: 125px 47px; }
 
26
 
27
  a.publicize-profile-link, a.publicize-profile-link:visited {
28
  text-decoration: none;
1
+ /* This file was automatically generated on Aug 12 2013 17:03:27 */
2
 
3
  div#publicize-services-block {
4
  display: inline-block;
23
  span#twitter { background: url( ../twitter-logo.png ) 50% 19px no-repeat; background-size: 125px 47px; }
24
  span#linkedin { background: url( ../linkedin-logo.png ) 50% 19px no-repeat; background-size: 125px 47px; }
25
  span#tumblr { background: url( ../tumblr-logo.png ) 50% 19px no-repeat; background-size: 125px 47px; }
26
+ span#path { background: url( ../path-logo.png ) 50% 19px no-repeat; background-size: 85px 32px; }
27
 
28
  a.publicize-profile-link, a.publicize-profile-link:visited {
29
  text-decoration: none;
modules/publicize/ui.php CHANGED
@@ -99,7 +99,7 @@ class Publicize_UI {
99
  $doc_link = "http://en.support.wordpress.com/publicize/";
100
  ?>
101
 
102
- <p>&rarr; <a href="<?php echo esc_url( $doc_link ); ?>"><?php esc_html_e( 'More information on using Publicize.', 'jetpack' ); ?></a></p>
103
 
104
  <div id="publicize-services-block">
105
  <?php
@@ -108,7 +108,7 @@ class Publicize_UI {
108
  ?>
109
  <div class="publicize-service-entry">
110
  <div id="<?php echo esc_attr( $name ); ?>" class="publicize-service-left">
111
- <a href="<?php echo esc_url( $connect_url ); ?>"><span class="pub-logos" id="<?php echo esc_attr( $name ); ?>">&nbsp;</span></a>
112
  </div>
113
 
114
  <div class="publicize-service-right">
@@ -141,7 +141,7 @@ class Publicize_UI {
141
  <li>
142
  <?php
143
  if ( !empty( $profile_link ) ) : ?>
144
- <a class="publicize-profile-link" href="<?php echo esc_url( $profile_link ); ?>">
145
  <?php echo esc_html( $connection_display ); ?>
146
  </a><?php
147
  else :
@@ -153,11 +153,11 @@ class Publicize_UI {
153
  <small>(<?php esc_html_e( 'Shared', 'jetpack' ); ?>)</small>
154
 
155
  <?php if ( current_user_can( $this->publicize->GLOBAL_CAP ) ) : ?>
156
- <a class="pub-disconnect-button" title="<?php esc_html_e( 'Disconnect', 'jetpack' ); ?>" href="<?php echo esc_url( $disconnect_url ); ?>">×</a>
157
  <?php endif; ?>
158
 
159
  <?php else : ?>
160
- <a class="pub-disconnect-button" title="<?php esc_html_e( 'Disconnect', 'jetpack' ); ?>" href="<?php echo esc_url( $disconnect_url ); ?>">×</a>
161
  <?php endif; ?>
162
  </li>
163
 
@@ -166,7 +166,7 @@ class Publicize_UI {
166
  ?>
167
  </ul>
168
  <?php endif; ?>
169
- <a id="<?php echo esc_attr( $name ); ?>" class="publicize-add-connection" href="<?php echo esc_url( $connect_url); ?>"><?php echo esc_html( sprintf( __( 'Add new %s connection.', 'jetpack' ), $this->publicize->get_service_label( $name ) ) ); ?></a>
170
  </div>
171
  </div>
172
  <?php endforeach; ?>
@@ -464,6 +464,10 @@ jQuery( function($) {
464
  $checked = $skip != 1 || $done;
465
  $checked = apply_filters( 'publicize_checkbox_default', $checked, $post->ID, $name, $connection );
466
 
 
 
 
 
467
  // This post has been handled, so disable everything
468
  if ( $all_done )
469
  $disabled = ' disabled="disabled"';
99
  $doc_link = "http://en.support.wordpress.com/publicize/";
100
  ?>
101
 
102
+ <p>&rarr; <a href="<?php echo esc_url( $doc_link ); ?>" target="_blank"><?php esc_html_e( 'More information on using Publicize.', 'jetpack' ); ?></a></p>
103
 
104
  <div id="publicize-services-block">
105
  <?php
108
  ?>
109
  <div class="publicize-service-entry">
110
  <div id="<?php echo esc_attr( $name ); ?>" class="publicize-service-left">
111
+ <a href="<?php echo esc_url( $connect_url ); ?>" target="_top"><span class="pub-logos" id="<?php echo esc_attr( $name ); ?>">&nbsp;</span></a>
112
  </div>
113
 
114
  <div class="publicize-service-right">
141
  <li>
142
  <?php
143
  if ( !empty( $profile_link ) ) : ?>
144
+ <a class="publicize-profile-link" href="<?php echo esc_url( $profile_link ); ?>" target="_top">
145
  <?php echo esc_html( $connection_display ); ?>
146
  </a><?php
147
  else :
153
  <small>(<?php esc_html_e( 'Shared', 'jetpack' ); ?>)</small>
154
 
155
  <?php if ( current_user_can( $this->publicize->GLOBAL_CAP ) ) : ?>
156
+ <a class="pub-disconnect-button" title="<?php esc_html_e( 'Disconnect', 'jetpack' ); ?>" href="<?php echo esc_url( $disconnect_url ); ?>" target="_top">×</a>
157
  <?php endif; ?>
158
 
159
  <?php else : ?>
160
+ <a class="pub-disconnect-button" title="<?php esc_html_e( 'Disconnect', 'jetpack' ); ?>" href="<?php echo esc_url( $disconnect_url ); ?>" target="_top">×</a>
161
  <?php endif; ?>
162
  </li>
163
 
166
  ?>
167
  </ul>
168
  <?php endif; ?>
169
+ <a id="<?php echo esc_attr( $name ); ?>" class="publicize-add-connection" href="<?php echo esc_url( $connect_url); ?>" target="_top"><?php echo esc_html( sprintf( __( 'Add new %s connection.', 'jetpack' ), $this->publicize->get_service_label( $name ) ) ); ?></a>
170
  </div>
171
  </div>
172
  <?php endforeach; ?>
464
  $checked = $skip != 1 || $done;
465
  $checked = apply_filters( 'publicize_checkbox_default', $checked, $post->ID, $name, $connection );
466
 
467
+ // Force the checkbox to be checked if the post was DONE, regardless of what the filter does
468
+ if ( $done )
469
+ $checked = true;
470
+
471
  // This post has been handled, so disable everything
472
  if ( $all_done )
473
  $disabled = ' disabled="disabled"';
modules/random-redirect.php ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Plugin Name: Random Redirect
4
+ Plugin URI: http://wordpress.org/extend/plugins/random-redirect/
5
+ Description: Allows you to create a link to yourblog.example.com/?random which will redirect someone to a random post on your blog, in a StumbleUpon-like fashion.
6
+ Version: 1.2-wpcom
7
+ Author: Matt Mullenweg
8
+ Author URI: http://photomatt.net/
9
+ */
10
+
11
+ function matt_random_redirect() {
12
+ // Acceptables URL formats: /[...]/?random=[post type], /?random, /&random, /&random=1
13
+ if ( ! isset( $_GET['random'] ) && ! in_array( strtolower( $_SERVER['REQUEST_URI'] ), array( '/&random', '/&random=1' ) ) )
14
+ return;
15
+
16
+ // Ignore requests that include more than just the random parameter.
17
+ if ( ! empty( $_POST ) || ( isset( $_GET['random'] ) && count( $_GET ) > 1 ) )
18
+ return;
19
+
20
+ // Persistent AppEngine abuse. ORDER BY RAND is expensive.
21
+ if ( strstr( $_SERVER['HTTP_USER_AGENT'], 'AppEngine-Google' ) )
22
+ wp_die( 'Please <a href="http://en.support.wordpress.com/contact/">contact support</a>' );
23
+
24
+ // Use the post type of the current page as the context for the random lookup.
25
+ $post_type = get_post_type();
26
+
27
+ // /?random should always show a random post, even if the home page is a static page.
28
+ if ( '/' == $_SERVER['DOCUMENT_URI'] )
29
+ $post_type = 'post';
30
+ else
31
+ $post_type = get_post_type();
32
+
33
+ if ( ! $post_type )
34
+ $post_type = 'post';
35
+
36
+ global $wpdb;
37
+ $random_id = $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_type = %s AND post_password = '' AND post_status = 'publish' ORDER BY RAND() LIMIT 1", $post_type ) );
38
+ $permalink = get_permalink( $random_id );
39
+ wp_safe_redirect( $permalink );
40
+ exit;
41
+ }
42
+
43
+ add_action( 'template_redirect', 'matt_random_redirect' );
modules/sharedaddy.php CHANGED
@@ -6,6 +6,7 @@
6
  * First Introduced: 1.1
7
  * Major Changes In: 1.2
8
  * Requires Connection: No
 
9
  */
10
 
11
  if ( !function_exists( 'sharing_init' ) )
6
  * First Introduced: 1.1
7
  * Major Changes In: 1.2
8
  * Requires Connection: No
9
+ * Auto Activate: Yes
10
  */
11
 
12
  if ( !function_exists( 'sharing_init' ) )
modules/sharedaddy/images/facebook.png CHANGED
Binary file
modules/sharedaddy/images/facebook@2x.png CHANGED
Binary file
modules/sharedaddy/images/icon-facebook-2x.png CHANGED
Binary file
modules/sharedaddy/images/icon-facebook.png CHANGED
Binary file
modules/sharedaddy/sharing-service.php CHANGED
@@ -620,7 +620,7 @@ function get_base_recaptcha_lang_code() {
620
  'tr' => 'tr'
621
  );
622
 
623
- $blog_lang_code = function_exists( 'get_blog_lang_code' ) ? get_blog_lang_code() : get_bloginfo( 'language' );
624
  if( isset( $base_recaptcha_lang_code_mapping[ $blog_lang_code ] ) )
625
  return $base_recaptcha_lang_code_mapping[ $blog_lang_code ];
626
 
620
  'tr' => 'tr'
621
  );
622
 
623
+ $blog_lang_code = function_exists( 'get_blog_lang_code' ) ? get_blog_lang_code() : get_bloginfo( 'language' );
624
  if( isset( $base_recaptcha_lang_code_mapping[ $blog_lang_code ] ) )
625
  return $base_recaptcha_lang_code_mapping[ $blog_lang_code ];
626
 
modules/sharedaddy/sharing.php CHANGED
@@ -166,6 +166,7 @@ class Sharing_Admin {
166
 
167
  <?php if ( current_user_can( 'manage_options' ) ) : ?>
168
 
 
169
  <h3><?php _e( 'Sharing Buttons', 'jetpack' ) ?></h3>
170
  <p><?php _e( 'Add sharing buttons to your blog and allow your visitors to share posts with their friends.', 'jetpack' ) ?></p>
171
 
@@ -402,7 +403,7 @@ class Sharing_Admin {
402
  <input type="hidden" name="_wpnonce" value="<?php echo wp_create_nonce( 'sharing-new_service' );?>" />
403
  </form>
404
  </div>
405
-
406
 
407
  <?php endif; ?>
408
 
166
 
167
  <?php if ( current_user_can( 'manage_options' ) ) : ?>
168
 
169
+ <div class="share_manage_options">
170
  <h3><?php _e( 'Sharing Buttons', 'jetpack' ) ?></h3>
171
  <p><?php _e( 'Add sharing buttons to your blog and allow your visitors to share posts with their friends.', 'jetpack' ) ?></p>
172
 
403
  <input type="hidden" name="_wpnonce" value="<?php echo wp_create_nonce( 'sharing-new_service' );?>" />
404
  </form>
405
  </div>
406
+ </div>
407
 
408
  <?php endif; ?>
409
 
modules/shortcodes.php CHANGED
@@ -7,6 +7,7 @@
7
  * First Introduced: 1.1
8
  * Major Changes In: 1.2
9
  * Requires Connection: No
 
10
  */
11
 
12
  /**
7
  * First Introduced: 1.1
8
  * Major Changes In: 1.2
9
  * Requires Connection: No
10
+ * Auto Activate: Yes
11
  */
12
 
13
  /**
modules/shortcodes/css/rtl/slideshow-shortcode-rtl.css CHANGED
@@ -1,4 +1,4 @@
1
- /* This file was automatically generated on Mar 25 2013 08:14:36 */
2
 
3
  .slideshow-window {
4
  background-color: #222;
@@ -8,6 +8,7 @@
8
  -webkit-border-radius: 11px;
9
  -khtml-border-radius: 11px;
10
  margin-bottom: 20px;
 
11
  }
12
 
13
  .slideshow-window, .slideshow-window * {
1
+ /* This file was automatically generated on Aug 22 2013 17:45:44 */
2
 
3
  .slideshow-window {
4
  background-color: #222;
8
  -webkit-border-radius: 11px;
9
  -khtml-border-radius: 11px;
10
  margin-bottom: 20px;
11
+ height: 410px;
12
  }
13
 
14
  .slideshow-window, .slideshow-window * {
modules/shortcodes/css/slideshow-shortcode.css CHANGED
@@ -6,6 +6,7 @@
6
  -webkit-border-radius: 11px;
7
  -khtml-border-radius: 11px;
8
  margin-bottom: 20px;
 
9
  }
10
 
11
  .slideshow-window, .slideshow-window * {
6
  -webkit-border-radius: 11px;
7
  -khtml-border-radius: 11px;
8
  margin-bottom: 20px;
9
+ height: 410px;
10
  }
11
 
12
  .slideshow-window, .slideshow-window * {
modules/shortcodes/css/style.css ADDED
@@ -0,0 +1,140 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * 1. Fullscreen styles
3
+ */
4
+ html.presentation-wrapper-fullscreen-parent,
5
+ body.presentation-wrapper-fullscreen-parent {
6
+ overflow: hidden !important;
7
+ }
8
+
9
+ .presentation-wrapper-fullscreen-parent #wpadminbar {
10
+ display: none;
11
+ }
12
+
13
+ .presentation-wrapper-fullscreen,
14
+ .presentation-wrapper-fullscreen-parent {
15
+ min-width: 100% !important;
16
+ min-height: 100% !important;
17
+ position: absolute !important;
18
+ top: 0 !important;
19
+ right: 0 !important;
20
+ bottom: 0 !important;
21
+ left: 0 !important;
22
+ margin: 0 !important;
23
+ padding: 0 !important;
24
+ z-index: 10000 !important;
25
+ }
26
+
27
+ .presentation-wrapper-fullscreen {
28
+ background-color: #808080;
29
+ border: none !important;
30
+ }
31
+
32
+ .presentation-wrapper-fullscreen .nav-arrow-left,
33
+ .presentation-wrapper-fullscreen .nav-arrow-right {
34
+ z-index: 20001;
35
+ }
36
+
37
+ .presentation-wrapper-fullscreen .nav-fullscreen-button {
38
+ z-index: 20002;
39
+ }
40
+
41
+
42
+ /**
43
+ * 2. General presentation styles
44
+ */
45
+ .presentation-wrapper {
46
+ margin: 20px auto;
47
+ border: 1px solid #e5e5e5;
48
+ }
49
+
50
+ .presentation {
51
+ position: relative;
52
+ margin: 0;
53
+ overflow: hidden;
54
+ outline: none;
55
+ }
56
+
57
+ /**
58
+ * jmpress requires that step sizes are explicitly defined
59
+ * as it inserts sizeless divs before the steps. These
60
+ * dimensions are set by the js code on initialization
61
+ */
62
+ .presentation,
63
+ .presentation .step {
64
+ background-repeat: no-repeat;
65
+ background-position: center;
66
+ background-size: 100% 100%;
67
+ }
68
+
69
+ /**
70
+ * Opacity transition durations are set by the js code
71
+ * so they match the presentation animation durations
72
+ */
73
+ .presentation .step.fade:not(.active) {
74
+ opacity: 0;
75
+ }
76
+
77
+ .presentation .slide-content {
78
+ padding: 30px;
79
+ }
80
+
81
+
82
+ /**
83
+ * 3. Styles for the navigation arrows
84
+ */
85
+ .presentation .nav-arrow-left,
86
+ .presentation .nav-arrow-right,
87
+ .presentation .nav-fullscreen-button {
88
+ position: absolute;
89
+ width: 34px;
90
+ background-repeat: no-repeat;
91
+ z-index: 2;
92
+ opacity: 0;
93
+
94
+ -webkit-transition : opacity .25s;
95
+ -moz-transition : opacity .25s;
96
+ -ms-transition : opacity .25s;
97
+ -o-transition : opacity .25s;
98
+ transition : opacity .25s;
99
+ }
100
+
101
+ .presentation .nav-arrow-left,
102
+ .presentation .nav-arrow-right {
103
+ height: 100%;
104
+ background-image: url(../images/slide-nav.png);
105
+ background-size: 450% 61px;
106
+ }
107
+
108
+ .presentation .nav-arrow-left {
109
+ left: 0;
110
+ background-position: 4px 50%;
111
+ }
112
+
113
+ .presentation .nav-arrow-right {
114
+ right: 0;
115
+ background-position: -120px 50%;
116
+ }
117
+
118
+ .presentation .nav-fullscreen-button {
119
+ width: 32px;
120
+ height: 32px;
121
+ margin: 4px;
122
+ bottom: 0;
123
+ right: 0;
124
+ z-index: 3;
125
+ background-image: url(../images/expand.png);
126
+ background-size: 100% 100%;
127
+ }
128
+
129
+ .presentation:hover .nav-arrow-left,
130
+ .presentation:hover .nav-arrow-right {
131
+ opacity: 1;
132
+ }
133
+
134
+ .presentation:hover .nav-fullscreen-button {
135
+ opacity: 0.8;
136
+ }
137
+
138
+ .presentation-wrapper-fullscreen .nav-fullscreen-button {
139
+ background-image: url(../images/collapse.png);
140
+ }
modules/shortcodes/images/collapse.png ADDED
Binary file
modules/shortcodes/images/expand.png ADDED
Binary file
modules/shortcodes/images/slide-nav.png ADDED
Binary file
modules/shortcodes/js/jmpress.js ADDED
@@ -0,0 +1,2721 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*!
2
+ * jmpress.js v0.4.5
3
+ * http://jmpressjs.github.com/jmpress.js
4
+ *
5
+ * A jQuery plugin to build a website on the infinite canvas.
6
+ *
7
+ * Copyright 2013 Kyle Robinson Young @shama & Tobias Koppers @sokra
8
+ * Licensed MIT
9
+ * http://www.opensource.org/licenses/mit-license.php
10
+ *
11
+ * Based on the foundation laid by Bartek Szopka @bartaz
12
+ *//*!
13
+ * jmpress.js v0.4.5
14
+ * http://jmpressjs.github.com/jmpress.js
15
+ *
16
+ * A jQuery plugin to build a website on the infinite canvas.
17
+ *
18
+ * Copyright 2013 Kyle Robinson Young @shama & Tobias Koppers @sokra
19
+ * Licensed MIT
20
+ * http://www.opensource.org/licenses/mit-license.php
21
+ *
22
+ * Based on the foundation laid by Bartek Szopka @bartaz
23
+ *//*
24
+ * core.js
25
+ * The core of jmpress.js
26
+ */
27
+ (function( $, document, window, undefined ) {
28
+
29
+ 'use strict';
30
+
31
+ /**
32
+ * Set supported prefixes
33
+ *
34
+ * @access protected
35
+ * @return Function to get prefixed property
36
+ */
37
+ var pfx = (function () {
38
+ var style = document.createElement('dummy').style,
39
+ prefixes = 'Webkit Moz O ms Khtml'.split(' '),
40
+ memory = {};
41
+ return function ( prop ) {
42
+ if ( typeof memory[ prop ] === "undefined" ) {
43
+ var ucProp = prop.charAt(0).toUpperCase() + prop.substr(1),
44
+ props = (prop + ' ' + prefixes.join(ucProp + ' ') + ucProp).split(' ');
45
+ memory[ prop ] = null;
46
+ for ( var i in props ) {
47
+ if ( style[ props[i] ] !== undefined ) {
48
+ memory[ prop ] = props[i];
49
+ break;
50
+ }
51
+ }
52
+ }
53
+ return memory[ prop ];
54
+ };
55
+ }());
56
+
57
+ /**
58
+ * map ex. "WebkitTransform" to "-webkit-transform"
59
+ */
60
+ function mapProperty( name ) {
61
+ if(!name) {
62
+ return;
63
+ }
64
+ var index = 1 + name.substr(1).search(/[A-Z]/);
65
+ var prefix = name.substr(0, index).toLowerCase();
66
+ var postfix = name.substr(index).toLowerCase();
67
+ return "-" + prefix + "-" + postfix;
68
+ }
69
+ function addComma( attribute ) {
70
+ if(!attribute) {
71
+ return "";
72
+ }
73
+ return attribute + ",";
74
+ }
75
+ /**
76
+ * Return an jquery object only if it's not empty
77
+ */
78
+ function ifNotEmpty(el) {
79
+ if(el.length > 0) {
80
+ return el;
81
+ }
82
+ return null;
83
+ }
84
+
85
+ /**
86
+ * Default Settings
87
+ */
88
+ var defaults = {
89
+ /* CLASSES */
90
+ stepSelector: '.step'
91
+ ,containerClass: ''
92
+ ,canvasClass: ''
93
+ ,areaClass: ''
94
+ ,notSupportedClass: 'not-supported'
95
+
96
+ /* CONFIG */
97
+ ,fullscreen: true
98
+
99
+ /* ANIMATION */
100
+ ,animation: {
101
+ transformOrigin: 'top left'
102
+ ,transitionProperty: addComma(mapProperty(pfx('transform'))) + addComma(mapProperty(pfx('perspective'))) + 'opacity'
103
+ ,transitionDuration: '1s'
104
+ ,transitionDelay: '500ms'
105
+ ,transitionTimingFunction: 'ease-in-out'
106
+ ,transformStyle: "preserve-3d"
107
+ }
108
+ ,transitionDuration: 1500
109
+ };
110
+ var callbacks = {
111
+ 'beforeChange': 1
112
+ ,'beforeInitStep': 1
113
+ ,'initStep': 1
114
+ ,'beforeInit': 1
115
+ ,'afterInit': 1
116
+ ,'beforeDeinit': 1
117
+ ,'afterDeinit': 1
118
+ ,'applyStep': 1
119
+ ,'unapplyStep': 1
120
+ ,'setInactive': 1
121
+ ,'beforeActive': 1
122
+ ,'setActive': 1
123
+ ,'selectInitialStep': 1
124
+ ,'selectPrev': 1
125
+ ,'selectNext': 1
126
+ ,'selectHome': 1
127
+ ,'selectEnd': 1
128
+ ,'idle': 1
129
+ ,'applyTarget': 1
130
+ };
131
+ for(var callbackName in callbacks) {
132
+ defaults[callbackName] = [];
133
+ }
134
+
135
+
136
+ /**
137
+ * Initialize jmpress
138
+ */
139
+ function init( args ) {
140
+ args = $.extend(true, {}, args || {});
141
+
142
+ // accept functions and arrays of functions as callbacks
143
+ var callbackArgs = {};
144
+ var callbackName = null;
145
+ for (callbackName in callbacks) {
146
+ callbackArgs[callbackName] = $.isFunction( args[callbackName] ) ?
147
+ [ args[callbackName] ] :
148
+ args[callbackName];
149
+ args[callbackName] = [];
150
+ }
151
+
152
+ // MERGE SETTINGS
153
+ var settings = $.extend(true, {}, defaults, args);
154
+
155
+ for (callbackName in callbacks) {
156
+ if (callbackArgs[callbackName]) {
157
+ Array.prototype.push.apply(settings[callbackName], callbackArgs[callbackName]);
158
+ }
159
+ }
160
+
161
+ /*** MEMBER VARS ***/
162
+
163
+ var jmpress = $( this )
164
+ ,container = null
165
+ ,area = null
166
+ ,oldStyle = {
167
+ container: ""
168
+ ,area: ""
169
+ }
170
+ ,canvas = null
171
+ ,current = null
172
+ ,active = false
173
+ ,activeSubstep = null
174
+ ,activeDelegated = false;
175
+
176
+
177
+ /*** MEMBER FUNCTIONS ***/
178
+ // functions have to be called with this
179
+
180
+ /**
181
+ * Init a single step
182
+ *
183
+ * @param element the element of the step
184
+ * @param idx number of step
185
+ */
186
+ function doStepInit( element, idx ) {
187
+ var data = dataset( element );
188
+ var step = {
189
+ oldStyle: $(element).attr("style") || ""
190
+ };
191
+
192
+ var callbackData = {
193
+ data: data
194
+ ,stepData: step
195
+ };
196
+ callCallback.call(this, 'beforeInitStep', $(element), callbackData);
197
+ step.delegate = data.delegate;
198
+ callCallback.call(this, 'initStep', $(element), callbackData);
199
+
200
+ $(element).data('stepData', step);
201
+
202
+ if ( !$(element).attr('id') ) {
203
+ $(element).attr('id', 'step-' + (idx + 1));
204
+ }
205
+
206
+ callCallback.call(this, 'applyStep', $(element), callbackData);
207
+ }
208
+ /**
209
+ * Deinit a single step
210
+ *
211
+ * @param element the element of the step
212
+ */
213
+ function doStepDeinit( element ) {
214
+ var stepData = $(element).data('stepData');
215
+
216
+ $(element).attr("style", stepData.oldStyle);
217
+
218
+ callCallback.call(this, 'unapplyStep', $(element), {
219
+ stepData: stepData
220
+ });
221
+ }
222
+ /**
223
+ * Reapplies stepData to the element
224
+ *
225
+ * @param element
226
+ */
227
+ function doStepReapply( element ) {
228
+ callCallback.call(this, 'unapplyStep', $(element), {
229
+ stepData: element.data("stepData")
230
+ });
231
+
232
+ callCallback.call(this, 'applyStep', $(element), {
233
+ stepData: element.data("stepData")
234
+ });
235
+ }
236
+ /**
237
+ * Completly deinit jmpress
238
+ *
239
+ */
240
+ function deinit() {
241
+ if ( active ) {
242
+ callCallback.call(this, 'setInactive', active, {
243
+ stepData: $(active).data('stepData')
244
+ ,reason: "deinit"
245
+ } );
246
+ }
247
+ if (current.jmpressClass) {
248
+ $(jmpress).removeClass(current.jmpressClass);
249
+ }
250
+
251
+ callCallback.call(this, 'beforeDeinit', $(this), {});
252
+
253
+ $(settings.stepSelector, jmpress).each(function( idx ) {
254
+ doStepDeinit.call(jmpress, this );
255
+ });
256
+
257
+ container.attr("style", oldStyle.container);
258
+ if(settings.fullscreen) {
259
+ $("html").attr("style", "");
260
+ }
261
+ area.attr("style", oldStyle.area);
262
+ $(canvas).children().each(function() {
263
+ jmpress.append( $( this ) );
264
+ });
265
+ if( settings.fullscreen ) {
266
+ canvas.remove();
267
+ } else {
268
+ canvas.remove();
269
+ area.remove();
270
+ }
271
+
272
+ callCallback.call(this, 'afterDeinit', $(this), {});
273
+
274
+ $(jmpress).data("jmpressmethods", false);
275
+ }
276
+ /**
277
+ * Call a callback
278
+ *
279
+ * @param callbackName String callback which should be called
280
+ * @param element some arguments to the callback
281
+ * @param eventData
282
+ */
283
+ function callCallback( callbackName, element, eventData ) {
284
+ eventData.settings = settings;
285
+ eventData.current = current;
286
+ eventData.container = container;
287
+ eventData.parents = element ? getStepParents(element) : null;
288
+ eventData.current = current;
289
+ eventData.jmpress = this;
290
+ var result = {};
291
+ $.each( settings[callbackName], function(idx, callback) {
292
+ result.value = callback.call( jmpress, element, eventData ) || result.value;
293
+ });
294
+ return result.value;
295
+ }
296
+ /**
297
+ *
298
+ */
299
+ function getStepParents( el ) {
300
+ return $(el).parentsUntil(jmpress).not(jmpress).filter(settings.stepSelector);
301
+ }
302
+ /**
303
+ * Reselect the active step
304
+ *
305
+ * @param String type reason of reselecting step
306
+ */
307
+ function reselect( type ) {
308
+ return select( { step: active, substep: activeSubstep }, type);
309
+ }
310
+ /**
311
+ * Select a given step
312
+ *
313
+ * @param el element to select
314
+ * @param type reason of changing step
315
+ * @return Object element selected
316
+ */
317
+ function select( el, type ) {
318
+ var substep;
319
+ if ( $.isPlainObject( el ) ) {
320
+ substep = el.substep;
321
+ el = el.step;
322
+ }
323
+ if ( typeof el === 'string') {
324
+ el = jmpress.find( el ).first();
325
+ }
326
+ if ( !el || !$(el).data('stepData') ) {
327
+ return false;
328
+ }
329
+
330
+ scrollFix.call(this);
331
+
332
+ var step = $(el).data('stepData');
333
+
334
+ var cancelSelect = false;
335
+ callCallback.call(this, "beforeChange", el, {
336
+ stepData: step
337
+ ,reason: type
338
+ ,cancel: function() {
339
+ cancelSelect = true;
340
+ }
341
+ });
342
+ if (cancelSelect) {
343
+ return undefined;
344
+ }
345
+
346
+ var target = {};
347
+
348
+ var delegated = el;
349
+ if($(el).data("stepData").delegate) {
350
+ delegated = ifNotEmpty($(el).parentsUntil(jmpress).filter(settings.stepSelector).filter(step.delegate)) ||
351
+ ifNotEmpty($(el).near(step.delegate)) ||
352
+ ifNotEmpty($(el).near(step.delegate, true)) ||
353
+ ifNotEmpty($(step.delegate, jmpress));
354
+ if(delegated) {
355
+ step = delegated.data("stepData");
356
+ } else {
357
+ // Do not delegate if expression not found
358
+ delegated = el;
359
+ }
360
+ }
361
+ if ( activeDelegated ) {
362
+ callCallback.call(this, 'setInactive', activeDelegated, {
363
+ stepData: $(activeDelegated).data('stepData')
364
+ ,delegatedFrom: active
365
+ ,reason: type
366
+ ,target: target
367
+ ,nextStep: delegated
368
+ ,nextSubstep: substep
369
+ ,nextStepData: step
370
+ } );
371
+ }
372
+ var callbackData = {
373
+ stepData: step
374
+ ,delegatedFrom: el
375
+ ,reason: type
376
+ ,target: target
377
+ ,substep: substep
378
+ ,prevStep: activeDelegated
379
+ ,prevSubstep: activeSubstep
380
+ ,prevStepData: activeDelegated && $(activeDelegated).data('stepData')
381
+ };
382
+ callCallback.call(this, 'beforeActive', delegated, callbackData);
383
+ callCallback.call(this, 'setActive', delegated, callbackData);
384
+
385
+ // Set on step class on root element
386
+ if (current.jmpressClass) {
387
+ $(jmpress).removeClass(current.jmpressClass);
388
+ }
389
+ $(jmpress).addClass(current.jmpressClass = 'step-' + $(delegated).attr('id') );
390
+ if (current.jmpressDelegatedClass) {
391
+ $(jmpress).removeClass(current.jmpressDelegatedClass);
392
+ }
393
+ $(jmpress).addClass(current.jmpressDelegatedClass = 'delegating-step-' + $(el).attr('id') );
394
+
395
+ callCallback.call(this, "applyTarget", delegated, $.extend({
396
+ canvas: canvas
397
+ ,area: area
398
+ ,beforeActive: activeDelegated
399
+ }, callbackData));
400
+
401
+ active = el;
402
+ activeSubstep = callbackData.substep;
403
+ activeDelegated = delegated;
404
+
405
+ if(current.idleTimeout) {
406
+ clearTimeout(current.idleTimeout);
407
+ }
408
+ current.idleTimeout = setTimeout(function() {
409
+ callCallback.call(this, 'idle', delegated, callbackData);
410
+ }, Math.max(1, settings.transitionDuration - 100));
411
+
412
+ return delegated;
413
+ }
414
+ /**
415
+ * This should fix ANY kind of buggy scrolling
416
+ */
417
+ function scrollFix() {
418
+ (function fix() {
419
+ if ($(container)[0].tagName === "BODY") {
420
+ try {
421
+ window.scrollTo(0, 0);
422
+ } catch(e) {}
423
+ }
424
+ $(container).scrollTop(0);
425
+ $(container).scrollLeft(0);
426
+ function check() {
427
+ if ($(container).scrollTop() !== 0 ||
428
+ $(container).scrollLeft() !== 0) {
429
+ fix();
430
+ }
431
+ }
432
+ setTimeout(check, 1);
433
+ setTimeout(check, 10);
434
+ setTimeout(check, 100);
435
+ setTimeout(check, 200);
436
+ setTimeout(check, 400);
437
+ }());
438
+ }
439
+ /**
440
+ * Alias for select
441
+ */
442
+ function goTo( el ) {
443
+ return select.call(this, el, "jump" );
444
+ }
445
+ /**
446
+ * Goto Next Slide
447
+ *
448
+ * @return Object newly active slide
449
+ */
450
+ function next() {
451
+ return select.call(this, callCallback.call(this, 'selectNext', active, {
452
+ stepData: $(active).data('stepData')
453
+ ,substep: activeSubstep
454
+ }), "next" );
455
+ }
456
+ /**
457
+ * Goto Previous Slide
458
+ *
459
+ * @return Object newly active slide
460
+ */
461
+ function prev() {
462
+ return select.call(this, callCallback.call(this, 'selectPrev', active, {
463
+ stepData: $(active).data('stepData')
464
+ ,substep: activeSubstep
465
+ }), "prev" );
466
+ }
467
+ /**
468
+ * Goto First Slide
469
+ *
470
+ * @return Object newly active slide
471
+ */
472
+ function home() {
473
+ return select.call(this, callCallback.call(this, 'selectHome', active, {
474
+ stepData: $(active).data('stepData')
475
+ }), "home" );
476
+ }
477
+ /**
478
+ * Goto Last Slide
479
+ *
480
+ * @return Object newly active slide
481
+ */
482
+ function end() {
483
+ return select.call(this, callCallback.call(this, 'selectEnd', active, {
484
+ stepData: $(active).data('stepData')
485
+ }), "end" );
486
+ }
487
+ /**
488
+ * Manipulate the canvas
489
+ *
490
+ * @param props
491
+ * @return Object
492
+ */
493
+ function canvasMod( props ) {
494
+ css(canvas, props || {});
495
+ return $(canvas);
496
+ }
497
+ /**
498
+ * Return current step
499
+ *
500
+ * @return Object
501
+ */
502
+ function getActive() {
503
+ return activeDelegated && $(activeDelegated);
504
+ }
505
+ /**
506
+ * fire a callback
507
+ *
508
+ * @param callbackName
509
+ * @param element
510
+ * @param eventData
511
+ * @return void
512
+ */
513
+ function fire( callbackName, element, eventData ) {
514
+ if( !callbacks[callbackName] ) {
515
+ $.error( "callback " + callbackName + " is not registered." );
516
+ } else {
517
+ return callCallback.call(this, callbackName, element, eventData);
518
+ }
519
+ }
520
+
521
+ /**
522
+ * PUBLIC METHODS LIST
523
+ */
524
+ jmpress.data("jmpressmethods", {
525
+ select: select
526
+ ,reselect: reselect
527
+ ,scrollFix: scrollFix
528
+ ,goTo: goTo
529
+ ,next: next
530
+ ,prev: prev
531
+ ,home: home
532
+ ,end: end
533
+ ,canvas: canvasMod
534
+ ,container: function() { return container; }
535
+ ,settings: function() { return settings; }
536
+ ,active: getActive
537
+ ,current: function() { return current; }
538
+ ,fire: fire
539
+ ,init: function(step) {
540
+ doStepInit.call(this, $(step), current.nextIdNumber++);
541
+ }
542
+ ,deinit: function(step) {
543
+ if(step) {
544
+ doStepDeinit.call(this, $(step));
545
+ } else {
546
+ deinit.call(this);
547
+ }
548
+ }
549
+ ,reapply: doStepReapply
550
+ });
551
+
552
+ /**
553
+ * Check for support
554
+ * This will be removed in near future, when support is coming
555
+ *
556
+ * @access protected
557
+ * @return void
558
+ */
559
+ function checkSupport() {
560
+ var ua = navigator.userAgent.toLowerCase();
561
+ return (ua.search(/(iphone)|(ipod)|(android)/) === -1) || (ua.search(/(chrome)/) !== -1);
562
+ }
563
+
564
+ // BEGIN INIT
565
+
566
+ // CHECK FOR SUPPORT
567
+ if (checkSupport() === false) {
568
+ if (settings.notSupportedClass) {
569
+ jmpress.addClass(settings.notSupportedClass);
570
+ }
571
+ return;
572
+ } else {
573
+ if (settings.notSupportedClass) {
574
+ jmpress.removeClass(settings.notSupportedClass);
575
+ }
576
+ }
577
+
578
+ // grabbing all steps
579
+ var steps = $(settings.stepSelector, jmpress);
580
+
581
+ // GERNERAL INIT OF FRAME
582
+ container = jmpress;
583
+ area = $('<div />');
584
+ canvas = $('<div />');
585
+ $(jmpress).children().filter(steps).each(function() {
586
+ canvas.append( $( this ) );
587
+ });
588
+ if(settings.fullscreen) {
589
+ container = $('body');
590
+ $("html").css({
591
+ overflow: 'hidden'
592
+ });
593
+ area = jmpress;
594
+ }
595
+ oldStyle.area = area.attr("style") || "";
596
+ oldStyle.container = container.attr("style") || "";
597
+ if(settings.fullscreen) {
598
+ container.css({
599
+ height: '100%'
600
+ });
601
+ jmpress.append( canvas );
602
+ } else {
603
+ container.css({
604
+ position: "relative"
605
+ });
606
+ area.append( canvas );
607
+ jmpress.append( area );
608
+ }
609
+
610
+ $(container).addClass(settings.containerClass);
611
+ $(area).addClass(settings.areaClass);
612
+ $(canvas).addClass(settings.canvasClass);
613
+
614
+ document.documentElement.style.height = "100%";
615
+ container.css({
616
+ overflow: 'hidden'
617
+ });
618
+
619
+ var props = {
620
+ position: "absolute"
621
+ ,transitionDuration: '0s'
622
+ };
623
+ props = $.extend({}, settings.animation, props);
624
+ css(area, props);
625
+ css(area, {
626
+ top: '50%'
627
+ ,left: '50%'
628
+ ,perspective: '1000px'
629
+ });
630
+ css(canvas, props);
631
+
632
+ current = {};
633
+
634
+ callCallback.call(this, 'beforeInit', null, {});
635
+
636
+ // INITIALIZE EACH STEP
637
+ steps.each(function( idx ) {
638
+ doStepInit.call(jmpress, this, idx );
639
+ });
640
+ current.nextIdNumber = steps.length;
641
+
642
+ callCallback.call(this, 'afterInit', null, {});
643
+
644
+ // START
645
+ select.call(this, callCallback.call(this, 'selectInitialStep', "init", {}) );
646
+
647
+ if (settings.initClass) {
648
+ $(steps).removeClass(settings.initClass);
649
+ }
650
+ }
651
+ /**
652
+ * Return default settings
653
+ *
654
+ * @return Object
655
+ */
656
+ function getDefaults() {
657
+ return defaults;
658
+ }
659
+ /**
660
+ * Register a callback or a jmpress function
661
+ *
662
+ * @access public
663
+ * @param name String the name of the callback or function
664
+ * @param func Function? the function to be added
665
+ */
666
+ function register(name, func) {
667
+ if( $.isFunction(func) ) {
668
+ if( methods[name] ) {
669
+ $.error( "function " + name + " is already registered." );
670
+ } else {
671
+ methods[name] = func;
672
+ }
673
+ } else {
674
+ if( callbacks[name] ) {
675
+ $.error( "callback " + name + " is already registered." );
676
+ } else {
677
+ callbacks[name] = 1;
678
+ defaults[name] = [];
679
+ }
680
+ }
681
+ }
682
+ /**
683
+ * Set CSS on element w/ prefixes
684
+ *
685
+ * @return Object element which properties were set
686
+ *
687
+ * TODO: Consider bypassing pfx and blindly set as jQuery
688
+ * already checks for support
689
+ */
690
+ function css( el, props ) {
691
+ var key, pkey, cssObj = {};
692
+ for ( key in props ) {
693
+ if ( props.hasOwnProperty(key) ) {
694
+ pkey = pfx(key);
695
+ if ( pkey !== null ) {
696
+ cssObj[pkey] = props[key];
697
+ }
698
+ }
699
+ }
700
+ $(el).css(cssObj);
701
+ return el;
702
+ }
703
+ /**
704
+ * Return dataset for element
705
+ *
706
+ * @param el element
707
+ * @return Object
708
+ */
709
+ function dataset( el ) {
710
+ if ( $(el)[0].dataset ) {
711
+ return $.extend({}, $(el)[0].dataset);
712
+ }
713
+ function toCamelcase( str ) {
714
+ str = str.split( '-' );
715
+ for( var i = 1; i < str.length; i++ ) {
716
+ str[i] = str[i].substr(0, 1).toUpperCase() + str[i].substr(1);
717
+ }
718
+ return str.join( '' );
719
+ }
720
+ var returnDataset = {};
721
+ var attrs = $(el)[0].attributes;
722
+ $.each(attrs, function ( idx, attr ) {
723
+ if ( attr.nodeName.substr(0, 5) === "data-" ) {
724
+ returnDataset[ toCamelcase(attr.nodeName.substr(5)) ] = attr.nodeValue;
725
+ }
726
+ });
727
+ return returnDataset;
728
+ }
729
+ /**
730
+ * Returns true, if jmpress is initialized
731
+ *
732
+ * @return bool
733
+ */
734
+ function initialized() {
735
+ return !!$(this).data("jmpressmethods");
736
+ }
737
+
738
+
739
+ /**
740
+ * PUBLIC STATIC METHODS LIST
741
+ */
742
+ var methods = {
743
+ init: init
744
+ ,initialized: initialized
745
+ ,deinit: function() {}
746
+ ,css: css
747
+ ,pfx: pfx
748
+ ,defaults: getDefaults
749
+ ,register: register
750
+ ,dataset: dataset
751
+ };
752
+
753
+ /**
754
+ * $.jmpress()
755
+ */
756
+ $.fn.jmpress = function( method ) {
757
+ function f() {
758
+ var jmpressmethods = $(this).data("jmpressmethods");
759
+ if ( jmpressmethods && jmpressmethods[method] ) {
760
+ return jmpressmethods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
761
+ } else if ( methods[method] ) {
762
+ return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
763
+ } else if ( callbacks[method] && jmpressmethods ) {
764
+ var settings = jmpressmethods.settings();
765
+ var func = Array.prototype.slice.call( arguments, 1 )[0];
766
+ if ($.isFunction( func )) {
767
+ settings[method] = settings[method] || [];
768
+ settings[method].push(func);
769
+ }
770
+ } else if ( typeof method === 'object' || ! method ) {
771
+ return init.apply( this, arguments );
772
+ } else {
773
+ $.error( 'Method ' + method + ' does not exist on jQuery.jmpress' );
774
+ }
775
+ // to allow chaining
776
+ return this;
777
+ }
778
+ var args = arguments;
779
+ var result;
780
+ $(this).each(function(idx, element) {
781
+ result = f.apply(element, args);
782
+ });
783
+ return result;
784
+ };
785
+ $.extend({
786
+ jmpress: function( method ) {
787
+ if ( methods[method] ) {
788
+ return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
789
+ } else if ( callbacks[method] ) {
790
+ // plugin interface
791
+ var func = Array.prototype.slice.call( arguments, 1 )[0];
792
+ if ($.isFunction( func )) {
793
+ defaults[method].push(func);
794
+ } else {
795
+ $.error( 'Second parameter should be a function: $.jmpress( callbackName, callbackFunction )' );
796
+ }
797
+ } else {
798
+ $.error( 'Method ' + method + ' does not exist on jQuery.jmpress' );
799
+ }
800
+ }
801
+ });
802
+
803
+ }(jQuery, document, window));
804
+
805
+ /*
806
+ * near.js
807
+ * Find steps near each other
808
+ */
809
+ (function( $, document, window, undefined ) {
810
+
811
+ 'use strict';
812
+
813
+ // add near( selector, backwards = false) to jquery
814
+
815
+
816
+ function checkAndGo( elements, func, selector, backwards ) {
817
+ var next;
818
+ elements.each(function(idx, element) {
819
+ if(backwards) {
820
+ next = func(element, selector, backwards);
821
+ if (next) {
822
+ return false;
823
+ }
824
+ }
825
+ if( $(element).is(selector) ) {
826
+ next = element;
827
+ return false;
828
+ }
829
+ if(!backwards) {
830
+ next = func(element, selector, backwards);
831
+ if (next) {
832
+ return false;
833
+ }
834
+ }
835
+ });
836
+ return next;
837
+ }
838
+ function findNextInChildren(item, selector, backwards) {
839
+ var children = $(item).children();
840
+ if(backwards) {
841
+ children = $(children.get().reverse());
842
+ }
843
+ return checkAndGo( children, findNextInChildren, selector, backwards );
844
+ }
845
+ function findNextInSiblings(item, selector, backwards) {
846
+ return checkAndGo(
847
+ $(item)[backwards ? "prevAll" : "nextAll"](),
848
+ findNextInChildren, selector, backwards );
849
+ }
850
+ function findNextInParents(item, selector, backwards) {
851
+ var next;
852
+ var parents = $(item).parents();
853
+ parents = $(parents.get());
854
+ $.each(parents.get(), function(idx, element) {
855
+ if( backwards && $(element).is(selector) ) {
856
+ next = element;
857
+ return false;
858
+ }
859
+ next = findNextInSiblings(element, selector, backwards);
860
+ if(next) {
861
+ return false;
862
+ }
863
+ });
864
+ return next;
865
+ }
866
+
867
+ $.fn.near = function( selector, backwards ) {
868
+ var array = [];
869
+ $(this).each(function(idx, element) {
870
+ var near = (backwards ?
871
+ false :
872
+ findNextInChildren( element, selector, backwards )) ||
873
+ findNextInSiblings( element, selector, backwards ) ||
874
+ findNextInParents( element, selector, backwards );
875
+ if( near ) {
876
+ array.push(near);
877
+ }
878
+ });
879
+ return $(array);
880
+ };
881
+ }(jQuery, document, window));
882
+ /*
883
+ * transform.js
884
+ * The engine that powers the transforms or falls back to other methods
885
+ */
886
+ (function( $, document, window, undefined ) {
887
+
888
+ 'use strict';
889
+
890
+ /* FUNCTIONS */
891
+ function toCssNumber(number) {
892
+ return (Math.round(10000*number)/10000)+"";
893
+ }
894
+
895
+ /**
896
+ * 3D and 2D engines
897
+ */
898
+ var engines = {
899
+ 3: {
900
+ transform: function( el, data ) {
901
+ var transform = 'translate(-50%,-50%)';
902
+ $.each(data, function(idx, item) {
903
+ var coord = ["X", "Y", "Z"];
904
+ var i;
905
+ if(item[0] === "translate") { // ["translate", x, y, z]
906
+ transform += " translate3d(" + toCssNumber(item[1] || 0) + "px," + toCssNumber(item[2] || 0) + "px," + toCssNumber(item[3] || 0) + "px)";
907
+ } else if(item[0] === "rotate") {
908
+ var order = item[4] ? [1, 2, 3] : [3, 2, 1];
909
+ for(i = 0; i < 3; i++) {
910
+ transform += " rotate" + coord[order[i]-1] + "(" + toCssNumber(item[order[i]] || 0) + "deg)";
911
+ }
912
+ } else if(item[0] === "scale") {
913
+ for(i = 0; i < 3; i++) {
914
+ transform += " scale" + coord[i] + "(" + toCssNumber(item[i+1] || 1) + ")";
915
+ }
916
+ }
917
+ });
918
+ $.jmpress("css", el, $.extend({}, { transform: transform }));
919
+ }
920
+ }
921
+ ,2: {
922
+ transform: function( el, data ) {
923
+ var transform = 'translate(-50%,-50%)';
924
+ $.each(data, function(idx, item) {
925
+ var coord = ["X", "Y"];
926
+ if(item[0] === "translate") { // ["translate", x, y, z]
927
+ transform += " translate(" + toCssNumber(item[1] || 0) + "px," + toCssNumber(item[2] || 0) + "px)";
928
+ } else if(item[0] === "rotate") {
929
+ transform += " rotate(" + toCssNumber(item[3] || 0) + "deg)";
930
+ } else if(item[0] === "scale") {
931
+ for(var i = 0; i < 2; i++) {
932
+ transform += " scale" + coord[i] + "(" + toCssNumber(item[i+1] || 1) + ")";
933
+ }
934
+ }
935
+ });
936
+ $.jmpress("css", el, $.extend({}, { transform: transform }));
937
+ }
938
+ }
939
+ ,1: {
940
+ // CHECK IF SUPPORT IS REALLY NEEDED?
941
+ // this not even work without scaling...
942
+ // it may better to display the normal view
943
+ transform: function( el, data ) {
944
+ var anitarget = { top: 0, left: 0 };
945
+ $.each(data, function(idx, item) {
946
+ var coord = ["X", "Y"];
947
+ if(item[0] === "translate") { // ["translate", x, y, z]
948
+ anitarget.left = Math.round(item[1] || 0) + "px";
949
+ anitarget.top = Math.round(item[2] || 0) + "px";
950
+ }
951
+ });
952
+ el.animate(anitarget, 1000); // TODO: Use animation duration
953
+ }
954
+ }
955
+ };
956
+
957
+ /**
958
+ * Engine to power cross-browser translate, scale and rotate.
959
+ */
960
+ var engine = (function() {
961
+ if ($.jmpress("pfx", "perspective")) {
962
+ return engines[3];
963
+ } else if ($.jmpress("pfx", "transform")) {
964
+ return engines[2];
965
+ } else {
966
+ // CHECK IF SUPPORT IS REALLY NEEDED?
967
+ return engines[1];
968
+ }
969
+ }());
970
+
971
+ $.jmpress("defaults").reasonableAnimation = {};
972
+ $.jmpress("initStep", function( step, eventData ) {
973
+ var data = eventData.data;
974
+ var stepData = eventData.stepData;
975
+ var pf = parseFloat;
976
+ $.extend(stepData, {
977
+ x: pf(data.x) || 0
978
+ ,y: pf(data.y) || 0
979
+ ,z: pf(data.z) || 0
980
+ ,r: pf(data.r) || 0
981
+ ,phi: pf(data.phi) || 0
982
+ ,rotate: pf(data.rotate) || 0
983
+ ,rotateX: pf(data.rotateX) || 0
984
+ ,rotateY: pf(data.rotateY) || 0
985
+ ,rotateZ: pf(data.rotateZ) || 0
986
+ ,revertRotate: false
987
+ ,scale: pf(data.scale) || 1
988
+ ,scaleX: pf(data.scaleX) || false
989
+ ,scaleY: pf(data.scaleY) || false
990
+ ,scaleZ: pf(data.scaleZ) || 1
991
+ });
992
+ });
993
+ $.jmpress("afterInit", function( nil, eventData ) {
994
+ var stepSelector = eventData.settings.stepSelector,
995
+ current = eventData.current;
996
+ current.perspectiveScale = 1;
997
+ current.maxNestedDepth = 0;
998
+ var nestedSteps = $(eventData.jmpress).find(stepSelector).children(stepSelector);
999
+ while(nestedSteps.length) {
1000
+ current.maxNestedDepth++;
1001
+ nestedSteps = nestedSteps.children(stepSelector);
1002
+ }
1003
+ });
1004
+ $.jmpress("applyStep", function( step, eventData ) {
1005
+ $.jmpress("css", $(step), {
1006
+ position: "absolute"
1007
+ ,transformStyle: "preserve-3d"
1008
+ });
1009
+ if ( eventData.parents.length > 0 ) {
1010
+ $.jmpress("css", $(step), {
1011
+ top: "50%"
1012
+ ,left: "50%"
1013
+ });
1014
+ }
1015
+ var sd = eventData.stepData;
1016
+ var transform = [
1017
+ ["translate",
1018
+ sd.x || (sd.r * Math.sin(sd.phi*Math.PI/180)),
1019
+ sd.y || (-sd.r * Math.cos(sd.phi*Math.PI/180)),
1020
+ sd.z],
1021
+ ["rotate",
1022
+ sd.rotateX,
1023
+ sd.rotateY,
1024
+ sd.rotateZ || sd.rotate,
1025
+ true],
1026
+ ["scale",
1027
+ sd.scaleX || sd.scale,
1028
+ sd.scaleY || sd.scale,
1029
+ sd.scaleZ || sd.scale]
1030
+ ];
1031
+ engine.transform( step, transform );
1032
+ });
1033
+ $.jmpress("setActive", function( element, eventData ) {
1034
+ var target = eventData.target;
1035
+ var step = eventData.stepData;
1036
+ var tf = target.transform = [];
1037
+ target.perspectiveScale = 1;
1038
+
1039
+ for(var i = eventData.current.maxNestedDepth; i > (eventData.parents.length || 0); i--) {
1040
+ tf.push(["scale"], ["rotate"], ["translate"]);
1041
+ }
1042
+
1043
+ tf.push(["scale",
1044
+ 1 / (step.scaleX || step.scale),
1045
+ 1 / (step.scaleY || step.scale),
1046
+ 1 / (step.scaleZ)]);
1047
+ tf.push(["rotate",
1048
+ -step.rotateX,
1049
+ -step.rotateY,
1050
+ -(step.rotateZ || step.rotate)]);
1051
+ tf.push(["translate",
1052
+ -(step.x || (step.r * Math.sin(step.phi*Math.PI/180))),
1053
+ -(step.y || (-step.r * Math.cos(step.phi*Math.PI/180))),
1054
+ -step.z]);
1055
+ target.perspectiveScale *= (step.scaleX || step.scale);
1056
+
1057
+ $.each(eventData.parents, function(idx, element) {
1058
+ var step = $(element).data("stepData");
1059
+ tf.push(["scale",
1060
+ 1 / (step.scaleX || step.scale),
1061
+ 1 / (step.scaleY || step.scale),
1062
+ 1 / (step.scaleZ)]);
1063
+ tf.push(["rotate",
1064
+ -step.rotateX,
1065
+ -step.rotateY,
1066
+ -(step.rotateZ || step.rotate)]);
1067
+ tf.push(["translate",
1068
+ -(step.x || (step.r * Math.sin(step.phi*Math.PI/180))),
1069
+ -(step.y || (-step.r * Math.cos(step.phi*Math.PI/180))),
1070
+ -step.z]);
1071
+ target.perspectiveScale *= (step.scaleX || step.scale);
1072
+ });
1073
+
1074
+ $.each(tf, function(idx, item) {
1075
+ if(item[0] !== "rotate") {
1076
+ return;
1077
+ }
1078
+ function lowRotate(name) {
1079
+ if(eventData.current["rotate"+name+"-"+idx] === undefined) {
1080
+ eventData.current["rotate"+name+"-"+idx] = item[name] || 0;
1081
+ }
1082
+ var cur = eventData.current["rotate"+name+"-"+idx], tar = item[name] || 0,
1083
+ curmod = cur % 360, tarmod = tar % 360;
1084
+ if(curmod < 0) {
1085
+ curmod += 360;
1086
+ }
1087
+ if(tarmod < 0) {
1088
+ tarmod += 360;
1089
+ }
1090
+ var diff = tarmod - curmod;
1091
+ if(diff < -180) {
1092
+ diff += 360;
1093
+ } else if(diff > 180) {
1094
+ diff -= 360;
1095
+ }
1096
+ eventData.current["rotate"+name+"-"+idx] = item[name] = cur + diff;
1097
+ }
1098
+ lowRotate(1);
1099
+ lowRotate(2);
1100
+ lowRotate(3);
1101
+ });
1102
+ });
1103
+ $.jmpress("applyTarget", function( active, eventData ) {
1104
+
1105
+ var target = eventData.target,
1106
+ props, step = eventData.stepData,
1107
+ settings = eventData.settings,
1108
+ zoomin = target.perspectiveScale * 1.3 < eventData.current.perspectiveScale,
1109
+ zoomout = target.perspectiveScale > eventData.current.perspectiveScale * 1.3;
1110
+
1111
+ // extract first scale from transform
1112
+ var lastScale = -1;
1113
+ $.each(target.transform, function(idx, item) {
1114
+ if(item.length <= 1) {
1115
+ return;
1116
+ }
1117
+ if(item[0] === "rotate" &&
1118
+ item[1] % 360 === 0 &&
1119
+ item[2] % 360 === 0 &&
1120
+ item[3] % 360 === 0) {
1121
+ return;
1122
+ }
1123
+ if(item[0] === "scale") {
1124
+ lastScale = idx;
1125
+ } else {
1126
+ return false;
1127
+ }
1128
+ });
1129
+
1130
+ if(lastScale !== eventData.current.oldLastScale) {
1131
+ zoomin = zoomout = false;
1132
+ eventData.current.oldLastScale = lastScale;
1133
+ }
1134
+
1135
+ var extracted = [];
1136
+ if(lastScale !== -1) {
1137
+ while(lastScale >= 0) {
1138
+ if(target.transform[lastScale][0] === "scale") {
1139
+ extracted.push(target.transform[lastScale]);
1140
+ target.transform[lastScale] = ["scale"];
1141
+ }
1142
+ lastScale--;
1143
+ }
1144
+ }
1145
+
1146
+ var animation = settings.animation;
1147
+ if(settings.reasonableAnimation[eventData.reason]) {
1148
+ animation = $.extend({},
1149
+ animation,
1150
+ settings.reasonableAnimation[eventData.reason]);
1151
+ }
1152
+
1153
+ props = {
1154
+ // to keep the perspective look similar for different scales
1155
+ // we need to 'scale' the perspective, too
1156
+ perspective: Math.round(target.perspectiveScale * 1000) + "px"
1157
+ };
1158
+ props = $.extend({}, animation, props);
1159
+ if (!zoomin) {
1160
+ props.transitionDelay = '0s';
1161
+ }
1162
+ if (!eventData.beforeActive) {
1163
+ props.transitionDuration = '0s';
1164
+ props.transitionDelay = '0s';
1165
+ }
1166
+ $.jmpress("css", eventData.area, props);
1167
+ engine.transform(eventData.area, extracted);
1168
+
1169
+ props = $.extend({}, animation);
1170
+ if (!zoomout) {
1171
+ props.transitionDelay = '0s';
1172
+ }
1173
+ if (!eventData.beforeActive) {
1174
+ props.transitionDuration = '0s';
1175
+ props.transitionDelay = '0s';
1176
+ }
1177
+
1178
+ eventData.current.perspectiveScale = target.perspectiveScale;
1179
+
1180
+ $.jmpress("css", eventData.canvas, props);
1181
+ engine.transform(eventData.canvas, target.transform);
1182
+ });
1183
+
1184
+ }(jQuery, document, window));
1185
+ /*
1186
+ * active.js
1187
+ * Set the active classes on steps
1188
+ */
1189
+ (function( $, document, window, undefined ) {
1190
+
1191
+ 'use strict';
1192
+ var $jmpress = $.jmpress;
1193
+
1194
+ /* DEFINES */
1195
+ var activeClass = 'activeClass',
1196
+ nestedActiveClass = 'nestedActiveClass';
1197
+
1198
+ /* DEFAULTS */
1199
+ var defaults = $jmpress( 'defaults' );
1200
+ defaults[nestedActiveClass] = "nested-active";
1201
+ defaults[activeClass] = "active";
1202
+
1203
+ /* HOOKS */
1204
+ $jmpress( 'setInactive', function( step, eventData ) {
1205
+ var settings = eventData.settings,
1206
+ activeClassSetting = settings[activeClass],
1207
+ nestedActiveClassSettings = settings[nestedActiveClass];
1208
+ if(activeClassSetting) {
1209
+ $(step).removeClass( activeClassSetting );
1210
+ }
1211
+ if(nestedActiveClassSettings) {
1212
+ $.each(eventData.parents, function(idx, element) {
1213
+ $(element).removeClass(nestedActiveClassSettings);
1214
+ });
1215
+ }
1216
+ });
1217
+ $jmpress( 'setActive', function( step, eventData ) {
1218
+ var settings = eventData.settings,
1219
+ activeClassSetting = settings[activeClass],
1220
+ nestedActiveClassSettings = settings[nestedActiveClass];
1221
+ if(activeClassSetting) {
1222
+ $(step).addClass( activeClassSetting );
1223
+ }
1224
+ if(nestedActiveClassSettings) {
1225
+ $.each(eventData.parents, function(idx, element) {
1226
+ $(element).addClass(nestedActiveClassSettings);
1227
+ });
1228
+ }
1229
+ });
1230
+
1231
+ }(jQuery, document, window));
1232
+ /*
1233
+ * circular.js
1234
+ * Repeat from start after end
1235
+ */
1236
+ (function( $, document, window, undefined ) {
1237
+
1238
+ 'use strict';
1239
+ var $jmpress = $.jmpress;
1240
+
1241
+ /* FUNCTIONS */
1242
+ function firstSlide( step, eventData ) {
1243
+ return $(this).find(eventData.settings.stepSelector).first();
1244
+ }
1245
+ function prevOrNext( jmpress, step, eventData, prev) {
1246
+ if (!step) {
1247
+ return false;
1248
+ }
1249
+ var stepSelector = eventData.settings.stepSelector;
1250
+ step = $(step);
1251
+ do {
1252
+ var item = step.near( stepSelector, prev );
1253
+ if (item.length === 0 || item.closest(jmpress).length === 0) {
1254
+ item = $(jmpress).find(stepSelector)[prev?"last":"first"]();
1255
+ }
1256
+ if (!item.length) {
1257
+ return false;
1258
+ }
1259
+ step = item;
1260
+ } while( step.data("stepData").exclude );
1261
+ return step;
1262
+ }
1263
+
1264
+ /* HOOKS */
1265
+ $jmpress( 'initStep', function( step, eventData ) {
1266
+ eventData.stepData.exclude = eventData.data.exclude && ["false", "no"].indexOf(eventData.data.exclude) === -1;
1267
+ });
1268
+ $jmpress( 'selectInitialStep', firstSlide);
1269
+ $jmpress( 'selectHome', firstSlide);
1270
+ $jmpress( 'selectEnd', function( step, eventData ) {
1271
+ return $(this).find(eventData.settings.stepSelector).last();
1272
+ });
1273
+ $jmpress( 'selectPrev', function( step, eventData ) {
1274
+ return prevOrNext(this, step, eventData, true);
1275
+ });
1276
+ $jmpress( 'selectNext', function( step, eventData ) {
1277
+ return prevOrNext(this, step, eventData);
1278
+ });
1279
+ }(jQuery, document, window));
1280
+ /*
1281
+ * start.js
1282
+ * Set the first step to start on
1283
+ */
1284
+ (function( $, document, window, undefined ) {
1285
+
1286
+ 'use strict';
1287
+
1288
+ /* HOOKS */
1289
+ $.jmpress( 'selectInitialStep', function( nil, eventData ) {
1290
+ return eventData.settings.start;
1291
+ });
1292
+
1293
+ }(jQuery, document, window));
1294
+ /*
1295
+ * ways.js
1296
+ * Control the flow of the steps
1297
+ */
1298
+ (function( $, document, window, undefined ) {
1299
+
1300
+ 'use strict';
1301
+ var $jmpress = $.jmpress;
1302
+
1303
+ /* FUNCTIONS */
1304
+ function routeFunc( jmpress, route, type ) {
1305
+ for(var i = 0; i < route.length - 1; i++) {
1306
+ var from = route[i];
1307
+ var to = route[i+1];
1308
+ if($(jmpress).jmpress("initialized")) {
1309
+ $(from, jmpress).data("stepData")[type] = to;
1310
+ } else {
1311
+ $(from, jmpress).attr('data-' + type, to);
1312
+ }
1313
+ }
1314
+ }
1315
+ function selectPrevOrNext( step, eventData, attr, prev ) {
1316
+ var stepData = eventData.stepData;
1317
+ if(stepData[attr]) {
1318
+ var near = $(step).near(stepData[attr], prev);
1319
+ if(near && near.length) {
1320
+ return near;
1321
+ }
1322
+ near = $(stepData[attr], this)[prev?"last":"first"]();
1323
+ if(near && near.length) {
1324
+ return near;
1325
+ }
1326
+ }
1327
+ }
1328
+
1329
+ /* EXPORTED FUNCTIONS */
1330
+ $jmpress( 'register', 'route', function( route, unidirectional, reversedRoute ) {
1331
+ if( typeof route === "string" ) {
1332
+ route = [route, route];
1333
+ }
1334
+ routeFunc(this, route, reversedRoute ? "prev" : "next");
1335
+ if (!unidirectional) {
1336
+ routeFunc(this, route.reverse(), reversedRoute ? "next" : "prev");
1337
+ }
1338
+ });
1339
+
1340
+ /* HOOKS */
1341
+ $jmpress( 'initStep', function( step, eventData ) {
1342
+ for(var attr in {next:1,prev:1}) {
1343
+ eventData.stepData[attr] = eventData.data[attr];
1344
+ }
1345
+ });
1346
+ $jmpress( 'selectNext', function( step, eventData ) {
1347
+ return selectPrevOrNext.call(this, step, eventData, "next");
1348
+ });
1349
+ $jmpress( 'selectPrev', function( step, eventData ) {
1350
+ return selectPrevOrNext.call(this, step, eventData, "prev", true);
1351
+ });
1352
+
1353
+ }(jQuery, document, window));
1354
+ /*
1355
+ * ajax.js
1356
+ * Load steps via ajax
1357
+ */
1358
+ (function( $, document, window, undefined ) {
1359
+
1360
+ 'use strict';
1361
+ var $jmpress = $.jmpress;
1362
+
1363
+ /* DEFINES */
1364
+ var afterStepLoaded = 'ajax:afterStepLoaded',
1365
+ loadStep = 'ajax:loadStep';
1366
+
1367
+ /* REGISTER EVENTS */
1368
+ $jmpress('register', loadStep);
1369
+ $jmpress('register', afterStepLoaded);
1370
+
1371
+ /* DEFAULTS */
1372
+ $jmpress('defaults').ajaxLoadedClass = "loaded";
1373
+
1374
+ /* HOOKS */
1375
+ $jmpress('initStep', function( step, eventData ) {
1376
+ eventData.stepData.src = $(step).attr('href') || eventData.data.src || false;
1377
+ eventData.stepData.srcLoaded = false;
1378
+ });
1379
+ $jmpress(loadStep, function( step, eventData ) {
1380
+ var stepData = eventData.stepData,
1381
+ href = stepData && stepData.src,
1382
+ settings = eventData.settings;
1383
+ if ( href ) {
1384
+ $(step).addClass( settings.ajaxLoadedClass );
1385
+ stepData.srcLoaded = true;
1386
+ $(step).load(href, function(response, status, xhr) {
1387
+ $(eventData.jmpress).jmpress('fire', afterStepLoaded, step, $.extend({}, eventData, {
1388
+ response: response
1389
+ ,status: status
1390
+ ,xhr: xhr
1391
+ }));
1392
+ });
1393
+ }
1394
+ });
1395
+ $jmpress('idle', function( step, eventData ) {
1396
+ if (!step) {
1397
+ return;
1398
+ }
1399
+ var settings = eventData.settings,
1400
+ jmpress = $(this),
1401
+ stepData = eventData.stepData;
1402
+ var siblings = $(step)
1403
+ .add( $(step).near( settings.stepSelector ) )
1404
+ .add( $(step).near( settings.stepSelector, true) )
1405
+ .add( jmpress.jmpress('fire', 'selectPrev', step, {
1406
+ stepData: $(step).data('stepData')
1407
+ }))
1408
+ .add( jmpress.jmpress('fire', 'selectNext', step, {
1409
+ stepData: $(step).data('stepData')
1410
+ }));
1411
+ siblings.each(function() {
1412
+ var step = this,
1413
+ stepData = $(step).data("stepData");
1414
+ if(!stepData.src || stepData.srcLoaded) {
1415
+ return;
1416
+ }
1417
+ jmpress.jmpress('fire', loadStep, step, {
1418
+ stepData: $(step).data('stepData')
1419
+ });
1420
+ });
1421
+ });
1422
+ $jmpress("setActive", function(step, eventData) {
1423
+ var stepData = $(step).data("stepData");
1424
+ if(!stepData.src || stepData.srcLoaded) {
1425
+ return;
1426
+ }
1427
+ $(this).jmpress('fire', loadStep, step, {
1428
+ stepData: $(step).data('stepData')
1429
+ });
1430
+ });
1431
+
1432
+ }(jQuery, document, window));
1433
+ /*
1434
+ * hash.js
1435
+ * Detect and set the URL hash
1436
+ */
1437
+ (function( $, document, window, undefined ) {
1438
+
1439
+ 'use strict';
1440
+ var $jmpress = $.jmpress,
1441
+ hashLink = "a[href^=#]";
1442
+
1443
+ /* FUNCTIONS */
1444
+ function randomString() {
1445
+ return "" + Math.round(Math.random() * 100000, 0);
1446
+ }
1447
+ /**
1448
+ * getElementFromUrl
1449
+ *
1450
+ * @return String or undefined
1451
+ */
1452
+ function getElementFromUrl(settings) {
1453
+ // get id from url # by removing `#` or `#/` from the beginning,
1454
+ // so both "fallback" `#slide-id` and "enhanced" `#/slide-id` will work
1455
+ // TODO SECURITY check user input to be valid!
1456
+ try {
1457
+ var el = $( '#' + window.location.hash.replace(/^#\/?/,"") );
1458
+ return el.length > 0 && el.is(settings.stepSelector) ? el : undefined;
1459
+ } catch(e) {}
1460
+ }
1461
+ function setHash(stepid) {
1462
+ var shouldBeHash = "#/" + stepid;
1463
+ if(window.history && window.history.pushState) {
1464
+ // shouldBeHash = "#" + stepid;
1465
+ // consider this for future versions
1466
+ // it has currently issues, when startup with a link with hash (webkit)
1467
+ if(window.location.hash !== shouldBeHash) {
1468
+ window.history.pushState({}, '', shouldBeHash);
1469
+ }
1470
+ } else {
1471
+ if(window.location.hash !== shouldBeHash) {
1472
+ window.location.hash = shouldBeHash;
1473
+ }
1474
+ }
1475
+ }
1476
+
1477
+ /* DEFAULTS */
1478
+ $jmpress('defaults').hash = {
1479
+ use: true
1480
+ ,update: true
1481
+ ,bindChange: true
1482
+ // NOTICE: {use: true, update: false, bindChange: true}
1483
+ // will cause a error after clicking on a link to the current step
1484
+ };
1485
+
1486
+ /* HOOKS */
1487
+ $jmpress('selectInitialStep', function( step, eventData ) {
1488
+ var settings = eventData.settings,
1489
+ hashSettings = settings.hash,
1490
+ current = eventData.current,
1491
+ jmpress = $(this);
1492
+ eventData.current.hashNamespace = ".jmpress-"+randomString();
1493
+ // HASH CHANGE EVENT
1494
+ if ( hashSettings.use ) {
1495
+ if ( hashSettings.bindChange ) {
1496
+ $(window).bind('hashchange'+current.hashNamespace, function(event) {
1497
+ var urlItem = getElementFromUrl(settings);
1498
+ if ( jmpress.jmpress('initialized') ) {
1499
+ jmpress.jmpress("scrollFix");
1500
+ }
1501
+ if(urlItem && urlItem.length) {
1502
+ if(urlItem.attr("id") !== jmpress.jmpress("active").attr("id")) {
1503
+ jmpress.jmpress('select', urlItem);
1504
+ }
1505
+ setHash(urlItem.attr("id"));
1506
+ }
1507
+ event.preventDefault();
1508
+ });
1509
+ $(hashLink).on("click"+current.hashNamespace, function(event) {
1510
+ var href = $(this).attr("href");
1511
+ try {
1512
+ if($(href).is(settings.stepSelector)) {
1513
+ jmpress.jmpress("select", href);
1514
+ event.preventDefault();
1515
+ event.stopPropagation();
1516
+ }
1517
+ } catch(e) {}
1518
+ });
1519
+ }
1520
+ return getElementFromUrl(settings);
1521
+ }
1522
+ });
1523
+ $jmpress('afterDeinit', function( nil, eventData ) {
1524
+ $(hashLink).off(eventData.current.hashNamespace);
1525
+ $(window).unbind(eventData.current.hashNamespace);
1526
+ });
1527
+ $jmpress('setActive', function( step, eventData ) {
1528
+ var settings = eventData.settings,
1529
+ current = eventData.current;
1530
+ // `#/step-id` is used instead of `#step-id` to prevent default browser
1531
+ // scrolling to element in hash
1532
+ if ( settings.hash.use && settings.hash.update ) {
1533
+ clearTimeout(current.hashtimeout);
1534
+ current.hashtimeout = setTimeout(function() {
1535
+ setHash($(eventData.delegatedFrom).attr('id'));
1536
+ }, settings.transitionDuration + 200);
1537
+ }
1538
+ });
1539
+
1540
+ }(jQuery, document, window));
1541
+ /*
1542
+ * keyboard.js
1543
+ * Keyboard event mapping and default keyboard actions
1544
+ */
1545
+ (function( $, document, window, undefined ) {
1546
+
1547
+ 'use strict';
1548
+ var $jmpress = $.jmpress,
1549
+ jmpressNext = "next",
1550
+ jmpressPrev = "prev";
1551
+
1552
+ /* FUNCTIONS */
1553
+ function randomString() {
1554
+ return "" + Math.round(Math.random() * 100000, 0);
1555
+ }
1556
+ function stopEvent(event) {
1557
+ event.preventDefault();
1558
+ event.stopPropagation();
1559
+ }
1560
+
1561
+ /* DEFAULTS */
1562
+ $jmpress('defaults').keyboard = {
1563
+ use: true
1564
+ ,keys: {
1565
+ 33: jmpressPrev // pg up
1566
+ ,37: jmpressPrev // left
1567
+ ,38: jmpressPrev // up
1568
+
1569
+ ,9: jmpressNext+":"+jmpressPrev // tab
1570
+ ,32: jmpressNext // space
1571
+ ,34: jmpressNext // pg down
1572
+ ,39: jmpressNext // right
1573
+ ,40: jmpressNext // down
1574
+
1575
+ ,36: "home" // home
1576
+
1577
+ ,35: "end" // end
1578
+ }
1579
+ ,ignore: {
1580
+ "INPUT": [
1581
+ 32 // space
1582
+ ,37 // left
1583
+ ,38 // up
1584
+ ,39 // right
1585
+ ,40 // down
1586
+ ]
1587
+ ,"TEXTAREA": [
1588
+ 32 // space
1589
+ ,37 // left
1590
+ ,38 // up
1591
+ ,39 // right
1592
+ ,40 // down
1593
+ ]
1594
+ ,"SELECT": [
1595
+ 38 // up
1596
+ ,40 // down
1597
+ ]
1598
+ }
1599
+ ,tabSelector: "a[href]:visible, :input:visible"
1600
+ };
1601
+
1602
+ /* HOOKS */
1603
+ $jmpress('afterInit', function( nil, eventData ) {
1604
+ var settings = eventData.settings,
1605
+ keyboardSettings = settings.keyboard,
1606
+ ignoreKeyboardSettings = keyboardSettings.ignore,
1607
+ current = eventData.current,
1608
+ jmpress = $(this);
1609
+
1610
+ // tabindex make it focusable so that it can recieve key events
1611
+ if(!settings.fullscreen) {
1612
+ jmpress.attr("tabindex", 0);
1613
+ }
1614
+
1615
+ current.keyboardNamespace = ".jmpress-"+randomString();
1616
+
1617
+ // KEYPRESS EVENT: this fixes a Opera bug
1618
+ $(settings.fullscreen ? document : jmpress)
1619
+ .bind("keypress"+current.keyboardNamespace, function( event ) {
1620
+
1621
+ for( var nodeName in ignoreKeyboardSettings ) {
1622
+ if ( event.target.nodeName === nodeName && ignoreKeyboardSettings[nodeName].indexOf(event.which) !== -1 ) {
1623
+ return;
1624
+ }
1625
+ }
1626
+ if(event.which >= 37 && event.which <= 40 || event.which === 32) {
1627
+ stopEvent(event);
1628
+ }
1629
+ });
1630
+ // KEYDOWN EVENT
1631
+ $(settings.fullscreen ? document : jmpress)
1632
+ .bind("keydown"+current.keyboardNamespace, function( event ) {
1633
+ var eventTarget = $(event.target);
1634
+
1635
+ if ( !settings.fullscreen && !eventTarget.closest(jmpress).length || !keyboardSettings.use ) {
1636
+ return;
1637
+ }
1638
+
1639
+ for( var nodeName in ignoreKeyboardSettings ) {
1640
+ if ( eventTarget[0].nodeName === nodeName && ignoreKeyboardSettings[nodeName].indexOf(event.which) !== -1 ) {
1641
+ return;
1642
+ }
1643
+ }
1644
+
1645
+ var reverseSelect = false;
1646
+ var nextFocus;
1647
+ if (event.which === 9) {
1648
+ // tab
1649
+ if ( !eventTarget.closest( jmpress.jmpress('active') ).length ) {
1650
+ if ( !event.shiftKey ) {
1651
+ nextFocus = jmpress.jmpress('active').find("a[href], :input").filter(":visible").first();
1652
+ } else {
1653
+ reverseSelect = true;
1654
+ }
1655
+ } else {
1656
+ nextFocus = eventTarget.near( keyboardSettings.tabSelector, event.shiftKey );
1657
+ if( !$(nextFocus)
1658
+ .closest( settings.stepSelector )
1659
+ .is(jmpress.jmpress('active') ) ) {
1660
+ nextFocus = undefined;
1661
+ }
1662
+ }
1663
+ if( nextFocus && nextFocus.length > 0 ) {
1664
+ nextFocus.focus();
1665
+ jmpress.jmpress("scrollFix");
1666
+ stopEvent(event);
1667
+ return;
1668
+ } else {
1669
+ if(event.shiftKey) {
1670
+ reverseSelect = true;
1671
+ }
1672
+ }
1673
+ }
1674
+
1675
+ var action = keyboardSettings.keys[ event.which ];
1676
+ if ( typeof action === "string" ) {
1677
+ if (action.indexOf(":") !== -1) {
1678
+ action = action.split(":");
1679
+ action = event.shiftKey ? action[1] : action[0];
1680
+ }
1681
+ jmpress.jmpress( action );
1682
+ stopEvent(event);
1683
+ } else if ( $.isFunction(action) ) {
1684
+ action.call(jmpress, event);
1685
+ } else if ( action ) {
1686
+ jmpress.jmpress.apply( jmpress, action );
1687
+ stopEvent(event);
1688
+ }
1689
+
1690
+ if (reverseSelect) {
1691
+ // tab
1692
+ nextFocus = jmpress.jmpress('active').find("a[href], :input").filter(":visible").last();
1693
+ nextFocus.focus();
1694
+ jmpress.jmpress("scrollFix");
1695
+ }
1696
+ });
1697
+ });
1698
+ $jmpress('afterDeinit', function( nil, eventData ) {
1699
+ $(document).unbind(eventData.current.keyboardNamespace);
1700
+ });
1701
+
1702
+
1703
+ }(jQuery, document, window));
1704
+ /*
1705
+ * viewport.js
1706
+ * Scale to fit a given viewport
1707
+ */
1708
+ (function( $, document, window, undefined ) {
1709
+
1710
+ 'use strict';
1711
+
1712
+ function randomString() {
1713
+ return "" + Math.round(Math.random() * 100000, 0);
1714
+ }
1715
+
1716
+ var browser = (function() {
1717
+ var ua = navigator.userAgent.toLowerCase();
1718
+ var match = /(chrome)[ \/]([\w.]+)/.exec(ua) ||
1719
+ /(webkit)[ \/]([\w.]+)/.exec(ua) ||
1720
+ /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) ||
1721
+ /(msie) ([\w.]+)/.exec(ua) ||
1722
+ ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) ||
1723
+ [];
1724
+ return match[1] || "";
1725
+ }());
1726
+
1727
+ var defaults = $.jmpress("defaults");
1728
+ defaults.viewPort = {
1729
+ width: false
1730
+ ,height: false
1731
+ ,maxScale: 0
1732
+ ,minScale: 0
1733
+ ,zoomable: 0
1734
+ ,zoomBindMove: true
1735
+ ,zoomBindWheel: true
1736
+ };
1737
+ var keys = defaults.keyboard.keys;
1738
+ keys[browser === 'mozilla' ? 107 : 187] = "zoomIn"; // +
1739
+ keys[browser === 'mozilla' ? 109 : 189] = "zoomOut"; // -
1740
+ defaults.reasonableAnimation.resize = {
1741
+ transitionDuration: '0s'
1742
+ ,transitionDelay: '0ms'
1743
+ };
1744
+ defaults.reasonableAnimation.zoom = {
1745
+ transitionDuration: '0s'
1746
+ ,transitionDelay: '0ms'
1747
+ };
1748
+ $.jmpress("initStep", function( step, eventData ) {
1749
+ for(var variable in {"viewPortHeight":1, "viewPortWidth":1, "viewPortMinScale":1, "viewPortMaxScale":1, "viewPortZoomable":1}) {
1750
+ eventData.stepData[variable] = eventData.data[variable] && parseFloat(eventData.data[variable]);
1751
+ }
1752
+ });
1753
+ $.jmpress("afterInit", function( nil, eventData ) {
1754
+ var jmpress = this;
1755
+ eventData.current.viewPortNamespace = ".jmpress-"+randomString();
1756
+ $(window).bind("resize"+eventData.current.viewPortNamespace, function (event) {
1757
+ $(jmpress).jmpress("reselect", "resize");
1758
+ });
1759
+ eventData.current.userZoom = 0;
1760
+ eventData.current.userTranslateX = 0;
1761
+ eventData.current.userTranslateY = 0;
1762
+ if(eventData.settings.viewPort.zoomBindWheel) {
1763
+ $(eventData.settings.fullscreen ? document : this)
1764
+ .bind("mousewheel"+eventData.current.viewPortNamespace+" DOMMouseScroll"+eventData.current.viewPortNamespace, function( event, delta ) {
1765
+ delta = delta || event.originalEvent.wheelDelta || -event.originalEvent.detail /* mozilla */;
1766
+ var direction = (delta / Math.abs(delta));
1767
+ if(direction < 0) {
1768
+ $(eventData.jmpress).jmpress("zoomOut", event.originalEvent.x, event.originalEvent.y);
1769
+ } else if(direction > 0) {
1770
+ $(eventData.jmpress).jmpress("zoomIn", event.originalEvent.x, event.originalEvent.y);
1771
+ }
1772
+ return false;
1773
+ });
1774
+ }
1775
+ if(eventData.settings.viewPort.zoomBindMove) {
1776
+ $(eventData.settings.fullscreen ? document : this).bind("mousedown"+eventData.current.viewPortNamespace, function (event) {
1777
+ if(eventData.current.userZoom) {
1778
+ eventData.current.userTranslating = { x: event.clientX, y: event.clientY };
1779
+ event.preventDefault();
1780
+ event.stopImmediatePropagation();
1781
+ }
1782
+ }).bind("mousemove"+eventData.current.viewPortNamespace, function (event) {
1783
+ var userTranslating = eventData.current.userTranslating;
1784
+ if(userTranslating) {
1785
+ $(jmpress).jmpress("zoomTranslate", event.clientX - userTranslating.x, event.clientY - userTranslating.y);
1786
+ userTranslating.x = event.clientX;
1787
+ userTranslating.y = event.clientY;
1788
+ event.preventDefault();
1789
+ event.stopImmediatePropagation();
1790
+ }
1791
+ }).bind("mouseup"+eventData.current.viewPortNamespace, function (event) {
1792
+ if(eventData.current.userTranslating) {
1793
+ eventData.current.userTranslating = undefined;
1794
+ event.preventDefault();
1795
+ event.stopImmediatePropagation();
1796
+ }
1797
+ });
1798
+ }
1799
+ });
1800
+ function maxAbs(value, range) {
1801
+ return Math.max(Math.min(value, range), -range);
1802
+ }
1803
+ function zoom(x, y, direction) {
1804
+ var current = $(this).jmpress("current"),
1805
+ settings = $(this).jmpress("settings"),
1806
+ stepData = $(this).jmpress("active").data("stepData"),
1807
+ container = $(this).jmpress("container");
1808
+ if(current.userZoom === 0 && direction < 0) {
1809
+ return;
1810
+ }
1811
+ var zoomableSteps = stepData.viewPortZoomable || settings.viewPort.zoomable;
1812
+ if(current.userZoom === zoomableSteps && direction > 0) {
1813
+ return;
1814
+ }
1815
+ current.userZoom += direction;
1816
+
1817
+ var halfWidth = $(container).innerWidth()/2,
1818
+ halfHeight = $(container).innerHeight()/2;
1819
+
1820
+ x = x ? x - halfWidth : x;
1821
+ y = y ? y - halfHeight : y;
1822
+
1823
+ // TODO this is not perfect... too much math... :(
1824
+ current.userTranslateX =
1825
+ maxAbs(current.userTranslateX - direction * x / current.zoomOriginWindowScale / zoomableSteps,
1826
+ halfWidth * current.userZoom * current.userZoom / zoomableSteps);
1827
+ current.userTranslateY =
1828
+ maxAbs(current.userTranslateY - direction * y / current.zoomOriginWindowScale / zoomableSteps,
1829
+ halfHeight * current.userZoom * current.userZoom / zoomableSteps);
1830
+
1831
+ $(this).jmpress("reselect", "zoom");
1832
+ }
1833
+ $.jmpress("register", "zoomIn", function(x, y) {
1834
+ zoom.call(this, x||0, y||0, 1);
1835
+ });
1836
+ $.jmpress("register", "zoomOut", function(x, y) {
1837
+ zoom.call(this, x||0, y||0, -1);
1838
+ });
1839
+ $.jmpress("register", "zoomTranslate", function(x, y) {
1840
+ var current = $(this).jmpress("current"),
1841
+ settings = $(this).jmpress("settings"),
1842
+ stepData = $(this).jmpress("active").data("stepData"),
1843
+ container = $(this).jmpress("container");
1844
+ var zoomableSteps = stepData.viewPortZoomable || settings.viewPort.zoomable;
1845
+ var halfWidth = $(container).innerWidth(),
1846
+ halfHeight = $(container).innerHeight();
1847
+ current.userTranslateX =
1848
+ maxAbs(current.userTranslateX + x / current.zoomOriginWindowScale,
1849
+ halfWidth * current.userZoom * current.userZoom / zoomableSteps);
1850
+ current.userTranslateY =
1851
+ maxAbs(current.userTranslateY + y / current.zoomOriginWindowScale,
1852
+ halfHeight * current.userZoom * current.userZoom / zoomableSteps);
1853
+ $(this).jmpress("reselect", "zoom");
1854
+ });
1855
+ $.jmpress('afterDeinit', function( nil, eventData ) {
1856
+ $(eventData.settings.fullscreen ? document : this).unbind(eventData.current.viewPortNamespace);
1857
+ $(window).unbind(eventData.current.viewPortNamespace);
1858
+ });
1859
+ $.jmpress("setActive", function( step, eventData ) {
1860
+ var viewPort = eventData.settings.viewPort;
1861
+ var viewPortHeight = eventData.stepData.viewPortHeight || viewPort.height;
1862
+ var viewPortWidth = eventData.stepData.viewPortWidth || viewPort.width;
1863
+ var viewPortMaxScale = eventData.stepData.viewPortMaxScale || viewPort.maxScale;
1864
+ var viewPortMinScale = eventData.stepData.viewPortMinScale || viewPort.minScale;
1865
+ // Correct the scale based on the window's size
1866
+ var windowScaleY = viewPortHeight && $(eventData.container).innerHeight()/viewPortHeight;
1867
+ var windowScaleX = viewPortWidth && $(eventData.container).innerWidth()/viewPortWidth;
1868
+ var windowScale = (windowScaleX || windowScaleY) && Math.min( windowScaleX || windowScaleY, windowScaleY || windowScaleX );
1869
+
1870
+ if(windowScale) {
1871
+ windowScale = windowScale || 1;
1872
+ if(viewPortMaxScale) {
1873
+ windowScale = Math.min(windowScale, viewPortMaxScale);
1874
+ }
1875
+ if(viewPortMinScale) {
1876
+ windowScale = Math.max(windowScale, viewPortMinScale);
1877
+ }
1878
+
1879
+ var zoomableSteps = eventData.stepData.viewPortZoomable || eventData.settings.viewPort.zoomable;
1880
+ if(zoomableSteps) {
1881
+ var diff = (1/windowScale) - (1/viewPortMaxScale);
1882
+ diff /= zoomableSteps;
1883
+ windowScale = 1/((1/windowScale) - diff * eventData.current.userZoom);
1884
+ }
1885
+
1886
+ eventData.target.transform.reverse();
1887
+ if(eventData.current.userTranslateX && eventData.current.userTranslateY) {
1888
+ eventData.target.transform.push(["translate", eventData.current.userTranslateX, eventData.current.userTranslateY, 0]);
1889
+ } else {
1890
+ eventData.target.transform.push(["translate"]);
1891
+ }
1892
+ eventData.target.transform.push(["scale",
1893
+ windowScale,
1894
+ windowScale,
1895
+ 1]);
1896
+ eventData.target.transform.reverse();
1897
+ eventData.target.perspectiveScale /= windowScale;
1898
+ }
1899
+ eventData.current.zoomOriginWindowScale = windowScale;
1900
+ });
1901
+ $.jmpress("setInactive", function( step, eventData ) {
1902
+ if(!eventData.nextStep || !step || $(eventData.nextStep).attr("id") !== $(step).attr("id")) {
1903
+ eventData.current.userZoom = 0;
1904
+ eventData.current.userTranslateX = 0;
1905
+ eventData.current.userTranslateY = 0;
1906
+ }
1907
+ });
1908
+
1909
+ }(jQuery, document, window));
1910
+
1911
+ /*
1912
+ * mouse.js
1913
+ * Clicking to select a step
1914
+ */
1915
+ (function( $, document, window, undefined ) {
1916
+
1917
+ 'use strict';
1918
+ var $jmpress = $.jmpress;
1919
+
1920
+ /* FUNCTIONS */
1921
+ function randomString() {
1922
+ return "" + Math.round(Math.random() * 100000, 0);
1923
+ }
1924
+
1925
+ /* DEFAULTS */
1926
+ $jmpress("defaults").mouse = {
1927
+ clickSelects: true
1928
+ };
1929
+
1930
+ /* HOOKS */
1931
+ $jmpress("afterInit", function( nil, eventData ) {
1932
+ var settings = eventData.settings,
1933
+ stepSelector = settings.stepSelector,
1934
+ current = eventData.current,
1935
+ jmpress = $(this);
1936
+ current.clickableStepsNamespace = ".jmpress-"+randomString();
1937
+ jmpress.bind("click"+current.clickableStepsNamespace, function(event) {
1938
+ if (!settings.mouse.clickSelects || current.userZoom) {
1939
+ return;
1940
+ }
1941
+
1942
+ // get clicked step
1943
+ var clickedStep = $(event.target).closest(stepSelector);
1944
+
1945
+ // clicks on the active step do default
1946
+ if ( clickedStep.is( jmpress.jmpress("active") ) ) {
1947
+ return;
1948
+ }
1949
+
1950
+ if (clickedStep.length) {
1951
+ // select the clicked step
1952
+ jmpress.jmpress("select", clickedStep[0], "click");
1953
+ event.preventDefault();
1954
+ event.stopPropagation();
1955
+ }
1956
+ });
1957
+ });
1958
+ $jmpress('afterDeinit', function( nil, eventData ) {
1959
+ $(this).unbind(eventData.current.clickableStepsNamespace);
1960
+ });
1961
+
1962
+ }(jQuery, document, window));
1963
+ /*
1964
+ * mobile.js
1965
+ * Adds support for swipe on touch supported browsers
1966
+ */
1967
+ (function( $, document, window, undefined ) {
1968
+
1969
+ 'use strict';
1970
+ var $jmpress = $.jmpress;
1971
+
1972
+ /* FUNCTIONS */
1973
+ function randomString() {
1974
+ return "" + Math.round(Math.random() * 100000, 0);
1975
+ }
1976
+
1977
+ /* HOOKS */
1978
+ $jmpress( 'afterInit', function( step, eventData ) {
1979
+ var settings = eventData.settings,
1980
+ current = eventData.current,
1981
+ jmpress = eventData.jmpress;
1982
+ current.mobileNamespace = ".jmpress-"+randomString();
1983
+ var data, start = [0,0];
1984
+ $(settings.fullscreen ? document : jmpress)
1985
+ .bind("touchstart"+current.mobileNamespace, function( event ) {
1986
+
1987
+ data = event.originalEvent.touches[0];
1988
+ start = [ data.pageX, data.pageY ];
1989
+
1990
+ }).bind("touchmove"+current.mobileNamespace, function( event ) {
1991
+ data = event.originalEvent.touches[0];
1992
+ event.preventDefault();
1993
+ return false;
1994
+ }).bind("touchend"+current.mobileNamespace, function( event ) {
1995
+ var end = [ data.pageX, data.pageY ],
1996
+ diff = [ end[0]-start[0], end[1]-start[1] ];
1997
+
1998
+ if(Math.max(Math.abs(diff[0]), Math.abs(diff[1])) > 50) {
1999
+ diff = Math.abs(diff[0]) > Math.abs(diff[1]) ? diff[0] : diff[1];
2000
+ $(jmpress).jmpress(diff > 0 ? "prev" : "next");
2001
+ event.preventDefault();
2002
+ return false;
2003
+ }
2004
+ });
2005
+ });
2006
+ $jmpress('afterDeinit', function( nil, eventData ) {
2007
+ var settings = eventData.settings,
2008
+ current = eventData.current,
2009
+ jmpress = eventData.jmpress;
2010
+ $(settings.fullscreen ? document : jmpress).unbind(current.mobileNamespace);
2011
+ });
2012
+
2013
+ }(jQuery, document, window));
2014
+ /*
2015
+ * templates.js
2016
+ * The amazing template engine
2017
+ */
2018
+ (function( $, document, window, undefined ) {
2019
+
2020
+ 'use strict';
2021
+ var $jmpress = $.jmpress,
2022
+ templateFromParentIdent = "_template_",
2023
+ templateFromApplyIdent = "_applied_template_";
2024
+
2025
+ /* STATIC VARS */
2026
+ var templates = {};
2027
+
2028
+ /* FUNCTIONS */
2029
+ function addUndefined( target, values, prefix ) {
2030
+ for( var name in values ) {
2031
+ var targetName = name;
2032
+ if ( prefix ) {
2033
+ targetName = prefix + targetName.substr(0, 1).toUpperCase() + targetName.substr(1);
2034
+ }
2035
+ if ( $.isPlainObject(values[name]) ) {
2036
+ addUndefined( target, values[name], targetName );
2037
+ } else if( target[targetName] === undefined ) {
2038
+ target[targetName] = values[name];
2039
+ }
2040
+ }
2041
+ }
2042
+ function applyChildrenTemplates( children, templateChildren ) {
2043
+ if ($.isArray(templateChildren)) {
2044
+ if (templateChildren.length < children.length) {
2045
+ $.error("more nested steps than children in template");
2046
+ } else {
2047
+ children.each(function(idx, child) {
2048
+ child = $(child);
2049
+ var tmpl = child.data(templateFromParentIdent) || {};
2050
+ addUndefined(tmpl, templateChildren[idx]);
2051
+ child.data(templateFromParentIdent, tmpl);
2052
+ });
2053
+ }
2054
+ } else if($.isFunction(templateChildren)) {
2055
+ children.each(function(idx, child) {
2056
+ child = $(child);
2057
+ var tmpl = child.data(templateFromParentIdent) || {};
2058
+ addUndefined(tmpl, templateChildren(idx, child, children));
2059
+ child.data(templateFromParentIdent, tmpl);
2060
+ });
2061
+ } // TODO: else if(object)
2062
+ }
2063
+ function applyTemplate( data, element, template, eventData ) {
2064
+ if (template.children) {
2065
+ var children = element.children( eventData.settings.stepSelector );
2066
+ applyChildrenTemplates( children, template.children );
2067
+ }
2068
+ applyTemplateData( data, template );
2069
+ }
2070
+ function applyTemplateData( data, template ) {
2071
+ addUndefined(data, template);
2072
+ }
2073
+
2074
+ /* HOOKS */
2075
+ $jmpress("beforeInitStep", function( step, eventData ) {
2076
+ step = $(step);
2077
+ var data = eventData.data,
2078
+ templateFromAttr = data.template,
2079
+ templateFromApply = step.data(templateFromApplyIdent),
2080
+ templateFromParent = step.data(templateFromParentIdent);
2081
+ if(templateFromAttr) {
2082
+ $.each(templateFromAttr.split(" "), function(idx, tmpl) {
2083
+ var template = templates[tmpl];
2084
+ applyTemplate( data, step, template, eventData );
2085
+ });
2086
+ }
2087
+ if (templateFromApply) {
2088
+ applyTemplate( data, step, templateFromApply, eventData );
2089
+ }
2090
+ if (templateFromParent) {
2091
+ applyTemplate( data, step, templateFromParent, eventData );
2092
+ step.data(templateFromParentIdent, null);
2093
+ if(templateFromParent.template) {
2094
+ $.each(templateFromParent.template.split(" "), function(idx, tmpl) {
2095
+ var template = templates[tmpl];
2096
+ applyTemplate( data, step, template, eventData );
2097
+ });
2098
+ }
2099
+ }
2100
+ });
2101
+ $jmpress("beforeInit", function( nil, eventData ) {
2102
+ var data = $jmpress("dataset", this),
2103
+ dataTemplate = data.template,
2104
+ stepSelector = eventData.settings.stepSelector;
2105
+ if (dataTemplate) {
2106
+ var template = templates[dataTemplate];
2107
+ applyChildrenTemplates( $(this).find(stepSelector).filter(function() {
2108
+ return !$(this).parent().is(stepSelector);
2109
+ }), template.children );
2110
+ }
2111
+ });
2112
+
2113
+ /* EXPORTED FUNCTIONS */
2114
+ $jmpress("register", "template", function( name, tmpl ) {
2115
+ if (templates[name]) {
2116
+ templates[name] = $.extend(true, {}, templates[name], tmpl);
2117
+ } else {
2118
+ templates[name] = $.extend(true, {}, tmpl);
2119
+ }
2120
+ });
2121
+ $jmpress("register", "apply", function( selector, tmpl ) {
2122
+ if( !tmpl ) {
2123
+ // TODO ERROR because settings not found
2124
+ var stepSelector = $(this).jmpress("settings").stepSelector;
2125
+ applyChildrenTemplates( $(this).find(stepSelector).filter(function() {
2126
+ return !$(this).parent().is(stepSelector);
2127
+ }), selector );
2128
+ } else if($.isArray(tmpl)) {
2129
+ applyChildrenTemplates( $(selector), tmpl );
2130
+ } else {
2131
+ var template;
2132
+ if(typeof tmpl === "string") {
2133
+ template = templates[tmpl];
2134
+ } else {
2135
+ template = $.extend(true, {}, tmpl);
2136
+ }
2137
+ $(selector).each(function(idx, element) {
2138
+ element = $(element);
2139
+ var tmpl = element.data(templateFromApplyIdent) || {};
2140
+ addUndefined(tmpl, template);
2141
+ element.data(templateFromApplyIdent, tmpl);
2142
+ });
2143
+ }
2144
+ });
2145
+
2146
+ }(jQuery, document, window));
2147
+ /*
2148
+ * jqevents.js
2149
+ * Fires jQuery events
2150
+ */
2151
+ (function( $, document, window, undefined ) {
2152
+
2153
+ 'use strict';
2154
+
2155
+ /* HOOKS */
2156
+ // the events should not bubble up the tree
2157
+ // elsewise nested jmpress would cause buggy behavior
2158
+ $.jmpress("setActive", function( step, eventData ) {
2159
+ if(eventData.prevStep !== step) {
2160
+ $(step).triggerHandler("enterStep");
2161
+ }
2162
+ });
2163
+ $.jmpress("setInactive", function( step, eventData ) {
2164
+ if(eventData.nextStep !== step) {
2165
+ $(step).triggerHandler("leaveStep");
2166
+ }
2167
+ });
2168
+
2169
+ }(jQuery, document, window));
2170
+ /*
2171
+ * animation.js
2172
+ * Apply custom animations to steps
2173
+ */
2174
+ (function( $, document, window, undefined ) {
2175
+
2176
+ 'use strict';
2177
+
2178
+ function parseSubstepInfo(str) {
2179
+ var arr = str.split(" ");
2180
+ var className = arr[0];
2181
+ var config = { willClass: "will-"+className, doClass: "do-"+className, hasClass: "has-"+className };
2182
+ var state = "";
2183
+ for(var i = 1; i < arr.length; i++) {
2184
+ var s = arr[i];
2185
+ switch(state) {
2186
+ case "":
2187
+ if(s === "after") {
2188
+ state = "after";
2189
+ } else {
2190
+ $.warn("unknown keyword in '"+str+"'. '"+s+"' unknown.");
2191
+ }
2192
+ break;
2193
+ case "after":
2194
+ if(s.match(/^[1-9][0-9]*m?s?/)) {
2195
+ var value = parseFloat(s);
2196
+ if(s.indexOf("ms") !== -1) {
2197
+ value *= 1;
2198
+ } else if(s.indexOf("s") !== -1) {
2199
+ value *= 1000;
2200
+ } else if(s.indexOf("m") !== -1) {
2201
+ value *= 60000;
2202
+ }
2203
+ config.delay = value;
2204
+ } else {
2205
+ config.after = Array.prototype.slice.call(arr, i).join(" ");
2206
+ i = arr.length;
2207
+ }
2208
+ }
2209
+ }
2210
+ return config;
2211
+ }
2212
+ function find(array, selector, start, end) {
2213
+ end = end || (array.length - 1);
2214
+ start = start || 0;
2215
+ for(var i = start; i < end + 1; i++) {
2216
+ if($(array[i].element).is(selector)) {
2217
+ return i;
2218
+ }
2219
+ }
2220
+ }
2221
+ function addOn(list, substep, delay) {
2222
+ $.each(substep._on, function(idx, child) {
2223
+ list.push({substep: child.substep, delay: child.delay + delay});
2224
+ addOn(list, child.substep, child.delay + delay);
2225
+ });
2226
+ }
2227
+ $.jmpress("defaults").customAnimationDataAttribute = "jmpress";
2228
+ $.jmpress("afterInit", function( nil, eventData ) {
2229
+ eventData.current.animationTimeouts = [];
2230
+ eventData.current.animationCleanupWaiting = [];
2231
+ });
2232
+ $.jmpress("applyStep", function( step, eventData ) {
2233
+ // read custom animation from elements
2234
+ var substepsData = {};
2235
+ var listOfSubsteps = [];
2236
+ $(step).find("[data-"+eventData.settings.customAnimationDataAttribute+"]")
2237
+ .each(function(idx, element) {
2238
+ if($(element).closest(eventData.settings.stepSelector).is(step)) {
2239
+ listOfSubsteps.push({element: element});
2240
+ }
2241
+ });
2242
+ if(listOfSubsteps.length === 0) {
2243
+ return;
2244
+ }
2245
+ $.each(listOfSubsteps, function(idx, substep) {
2246
+ substep.info = parseSubstepInfo(
2247
+ $(substep.element).data(eventData.settings.customAnimationDataAttribute));
2248
+ $(substep.element).addClass(substep.info.willClass);
2249
+ substep._on = [];
2250
+ substep._after = null;
2251
+ });
2252
+ var current = {_after: undefined, _on: [], info: {}}; // virtual zero step
2253
+ $.each(listOfSubsteps, function(idx, substep) {
2254
+ var other = substep.info.after;
2255
+ if(other) {
2256
+ if(other === "step") {
2257
+ other = current;
2258
+ } else if(other === "prev") {
2259
+ other = listOfSubsteps[idx-1];
2260
+ } else {
2261
+ var index = find(listOfSubsteps, other, 0, idx - 1);
2262
+ if(index === undefined) {
2263
+ index = find(listOfSubsteps, other);
2264
+ }
2265
+ other = (index === undefined || index === idx) ? listOfSubsteps[idx-1] : listOfSubsteps[index];
2266
+ }
2267
+ } else {
2268
+ other = listOfSubsteps[idx-1];
2269
+ }
2270
+ if(other) {
2271
+ if(!substep.info.delay) {
2272
+ if(!other._after) {
2273
+ other._after = substep;
2274
+ return;
2275
+ }
2276
+ other = other._after;
2277
+ }
2278
+ other._on.push({substep: substep, delay: substep.info.delay || 0});
2279
+ }
2280
+ });
2281
+ if(current._after === undefined && current._on.length === 0) {
2282
+ var startStep = find(listOfSubsteps, eventData.stepData.startSubstep) || 0;
2283
+ current._after = listOfSubsteps[startStep];
2284
+ }
2285
+ var substepsInOrder = [];
2286
+ function findNextFunc(idx, item) {
2287
+ if(item.substep._after) {
2288
+ current = item.substep._after;
2289
+ return false;
2290
+ }
2291
+ }
2292
+ do {
2293
+ var substepList = [{substep: current, delay: 0}];
2294
+ addOn(substepList, current, 0);
2295
+ substepsInOrder.push(substepList);
2296
+ current = null;
2297
+ $.each(substepList, findNextFunc);
2298
+ } while(current);
2299
+ substepsData.list = substepsInOrder;
2300
+ $(step).data("substepsData", substepsData);
2301
+ });
2302
+ $.jmpress("unapplyStep", function( step, eventData ) {
2303
+ var substepsData = $(step).data("substepsData");
2304
+ if(substepsData) {
2305
+ $.each(substepsData.list, function(idx, activeSubsteps) {
2306
+ $.each(activeSubsteps, function(idx, substep) {
2307
+ if(substep.substep.info.willClass) {
2308
+ $(substep.substep.element).removeClass(substep.substep.info.willClass);
2309
+ }
2310
+ if(substep.substep.info.hasClass) {
2311
+ $(substep.substep.element).removeClass(substep.substep.info.hasClass);
2312
+ }
2313
+ if(substep.substep.info.doClass) {
2314
+ $(substep.substep.element).removeClass(substep.substep.info.doClass);
2315
+ }
2316
+ });
2317
+ });
2318
+ }
2319
+ });
2320
+ $.jmpress("setActive", function(step, eventData) {
2321
+ var substepsData = $(step).data("substepsData");
2322
+ if(!substepsData) {
2323
+ return;
2324
+ }
2325
+ if(eventData.substep === undefined) {
2326
+ eventData.substep =
2327
+ (eventData.reason === "prev" ?
2328
+ substepsData.list.length-1 :
2329
+ 0
2330
+ );
2331
+ }
2332
+ var substep = eventData.substep;
2333
+ $.each(eventData.current.animationTimeouts, function(idx, timeout) {
2334
+ clearTimeout(timeout);
2335
+ });
2336
+ eventData.current.animationTimeouts = [];
2337
+ $.each(substepsData.list, function(idx, activeSubsteps) {
2338
+ var applyHas = idx < substep;
2339
+ var applyDo = idx <= substep;
2340
+ $.each(activeSubsteps, function(idx, substep) {
2341
+ if(substep.substep.info.hasClass) {
2342
+ $(substep.substep.element)[(applyHas?"add":"remove")+"Class"](substep.substep.info.hasClass);
2343
+ }
2344
+ function applyIt() {
2345
+ $(substep.substep.element).addClass(substep.substep.info.doClass);
2346
+ }
2347
+ if(applyDo && !applyHas && substep.delay && eventData.reason !== "prev") {
2348
+ if(substep.substep.info.doClass) {
2349
+ $(substep.substep.element).removeClass(substep.substep.info.doClass);
2350
+ eventData.current.animationTimeouts.push(setTimeout(applyIt, substep.delay));
2351
+ }
2352
+ } else {
2353
+ if(substep.substep.info.doClass) {
2354
+ $(substep.substep.element)[(applyDo?"add":"remove")+"Class"](substep.substep.info.doClass);
2355
+ }
2356
+ }
2357
+ });
2358
+ });
2359
+ });
2360
+ $.jmpress("setInactive", function(step, eventData) {
2361
+ if(eventData.nextStep === step) {
2362
+ return;
2363
+ }
2364
+ function cleanupAnimation( substepsData ) {
2365
+ $.each(substepsData.list, function(idx, activeSubsteps) {
2366
+ $.each(activeSubsteps, function(idx, substep) {
2367
+ if(substep.substep.info.hasClass) {
2368
+ $(substep.substep.element).removeClass(substep.substep.info.hasClass);
2369
+ }
2370
+ if(substep.substep.info.doClass) {
2371
+ $(substep.substep.element).removeClass(substep.substep.info.doClass);
2372
+ }
2373
+ });
2374
+ });
2375
+ }
2376
+ $.each(eventData.current.animationCleanupWaiting, function(idx, item) {
2377
+ cleanupAnimation(item);
2378
+ });
2379
+ eventData.current.animationCleanupWaiting = [];
2380
+ var substepsData = $(step).data("substepsData");
2381
+ if(substepsData) {
2382
+ eventData.current.animationCleanupWaiting.push( substepsData );
2383
+ }
2384
+ });
2385
+ $.jmpress("selectNext", function( step, eventData ) {
2386
+ if(eventData.substep === undefined) {
2387
+ return;
2388
+ }
2389
+ var substepsData = $(step).data("substepsData");
2390
+ if(!substepsData) {
2391
+ return;
2392
+ }
2393
+ if(eventData.substep < substepsData.list.length-1) {
2394
+ return {step: step, substep: eventData.substep+1};
2395
+ }
2396
+ });
2397
+ $.jmpress("selectPrev", function( step, eventData ) {
2398
+ if(eventData.substep === undefined) {
2399
+ return;
2400
+ }
2401
+ var substepsData = $(step).data("substepsData");
2402
+ if(!substepsData) {
2403
+ return;
2404
+ }
2405
+ if(eventData.substep > 0) {
2406
+ return {step: step, substep: eventData.substep-1};
2407
+ }
2408
+ });
2409
+
2410
+ }(jQuery, document, window));
2411
+ /*!
2412
+ * plugin for jmpress.js v0.4.5
2413
+ *
2414
+ * Copyright 2013 Kyle Robinson Young @shama & Tobias Koppers @sokra
2415
+ * Licensed MIT
2416
+ * http://www.opensource.org/licenses/mit-license.php
2417
+ *//*
2418
+ * jmpress.toggle plugin
2419
+ * For binding a key to toggle de/initialization of jmpress.js.
2420
+ */
2421
+ (function( $, document, window, undefined ) {
2422
+ 'use strict';
2423
+ $.jmpress("register", "toggle", function( key, config, initial ) {
2424
+ var jmpress = this;
2425
+ $(document).bind("keydown", function( event ) {
2426
+ if ( event.keyCode === key ) {
2427
+ if ($(jmpress).jmpress("initialized")) {
2428
+ $(jmpress).jmpress("deinit");
2429
+ } else {
2430
+ $(jmpress).jmpress(config);
2431
+ }
2432
+ }
2433
+ });
2434
+ if ( initial ) {
2435
+ $(jmpress).jmpress(config);
2436
+ }
2437
+ });
2438
+ }(jQuery, document, window));
2439
+
2440
+ /*
2441
+ * jmpress.secondary plugin
2442
+ * Apply a secondary animation when step is selected.
2443
+ */
2444
+ (function( $, document, window, undefined ) {
2445
+ 'use strict';
2446
+ $.jmpress("initStep", function( step, eventData ) {
2447
+ for(var name in eventData.data) {
2448
+ if(name.indexOf("secondary") === 0) {
2449
+ eventData.stepData[name] = eventData.data[name];
2450
+ }
2451
+ }
2452
+ });
2453
+ function exchangeIf(childStepData, condition, step) {
2454
+ if(childStepData.secondary &&
2455
+ childStepData.secondary.split(" ").indexOf(condition) !== -1) {
2456
+ for(var name in childStepData) {
2457
+ if(name.length > 9 && name.indexOf("secondary") === 0) {
2458
+ var tmp = childStepData[name];
2459
+ var normal = name.substr(9);
2460
+ normal = normal.substr(0, 1).toLowerCase() + normal.substr(1);
2461
+ childStepData[name] = childStepData[normal];
2462
+ childStepData[normal] = tmp;
2463
+ }
2464
+ }
2465
+ $(this).jmpress("reapply", $(step));
2466
+ }
2467
+ }
2468
+ $.jmpress("beforeActive", function( step, eventData ) {
2469
+ exchangeIf.call(eventData.jmpress, $(step).data("stepData"), "self", step);
2470
+ var parent = $(step).parent();
2471
+ $(parent)
2472
+ .children(eventData.settings.stepSelector)
2473
+ .each(function(idx, child) {
2474
+ var childStepData = $(child).data("stepData");
2475
+ exchangeIf.call(eventData.jmpress, childStepData, "siblings", child);
2476
+ });
2477
+ function grandchildrenFunc(idx, child) {
2478
+ var childStepData = $(child).data("stepData");
2479
+ exchangeIf.call(eventData.jmpress, childStepData, "grandchildren", child);
2480
+ }
2481
+ for(var i = 1; i < eventData.parents.length; i++) {
2482
+ $(eventData.parents[i])
2483
+ .children(eventData.settings.stepSelector)
2484
+ .each();
2485
+ }
2486
+ });
2487
+ $.jmpress("setInactive", function( step, eventData ) {
2488
+ exchangeIf.call(eventData.jmpress, $(step).data("stepData"), "self", step);
2489
+ var parent = $(step).parent();
2490
+ $(parent)
2491
+ .children(eventData.settings.stepSelector)
2492
+ .each(function(idx, child) {
2493
+ var childStepData = $(child).data("stepData");
2494
+ exchangeIf.call(eventData.jmpress, childStepData, "siblings", child);
2495
+ });
2496
+ function grandchildrenFunc(idx, child) {
2497
+ var childStepData = $(child).data("stepData");
2498
+ exchangeIf.call(eventData.jmpress, childStepData, "grandchildren", child);
2499
+ }
2500
+ for(var i = 1; i < eventData.parents.length; i++) {
2501
+ $(eventData.parents[i])
2502
+ .children(eventData.settings.stepSelector)
2503
+ .each(grandchildrenFunc);
2504
+ }
2505
+ });
2506
+ }(jQuery, document, window));
2507
+
2508
+ /*
2509
+ * jmpress.duration plugin
2510
+ * For auto advancing steps after a given duration and optionally displaying a
2511
+ * progress bar.
2512
+ */
2513
+ (function( $, document, window, undefined ) {
2514
+ 'use strict';
2515
+
2516
+ $.jmpress("defaults").duration = {
2517
+ defaultValue: -1
2518
+ ,defaultAction: "next"
2519
+ ,barSelector: undefined
2520
+ ,barProperty: "width"
2521
+ ,barPropertyStart: "0"
2522
+ ,barPropertyEnd: "100%"
2523
+ };
2524
+ $.jmpress("initStep", function( step, eventData ) {
2525
+ eventData.stepData.duration = eventData.data.duration && parseInt(eventData.data.duration, 10);
2526
+ eventData.stepData.durationAction = eventData.data.durationAction;
2527
+ });
2528
+ $.jmpress("setInactive", function( step, eventData ) {
2529
+ var settings = eventData.settings,
2530
+ durationSettings = settings.duration,
2531
+ current = eventData.current;
2532
+ var dur = eventData.stepData.duration || durationSettings.defaultValue;
2533
+ if( current.durationTimeout ) {
2534
+ if( durationSettings.barSelector ) {
2535
+ var css = {
2536
+ transitionProperty: durationSettings.barProperty
2537
+ ,transitionDuration: '0'
2538
+ ,transitionDelay: '0'
2539
+ ,transitionTimingFunction: 'linear'
2540
+ };
2541
+ css[durationSettings.barProperty] = durationSettings.barPropertyStart;
2542
+ var bars = $(durationSettings.barSelector);
2543
+ $.jmpress("css", bars, css);
2544
+ bars.each(function(idx, element) {
2545
+ var next = $(element).next();
2546
+ var parent = $(element).parent();
2547
+ $(element).detach();
2548
+ if(next.length) {
2549
+ next.insertBefore(element);
2550
+ } else {
2551
+ parent.append(element);
2552
+ }
2553
+ });
2554
+ }
2555
+ clearTimeout(current.durationTimeout);
2556
+ delete current.durationTimeout;
2557
+ }
2558
+ });
2559
+ $.jmpress("setActive", function( step, eventData ) {
2560
+ var settings = eventData.settings,
2561
+ durationSettings = settings.duration,
2562
+ current = eventData.current;
2563
+ var dur = eventData.stepData.duration || durationSettings.defaultValue;
2564
+ if( dur && dur > 0 ) {
2565
+ if( durationSettings.barSelector ) {
2566
+ var css = {
2567
+ transitionProperty: durationSettings.barProperty
2568
+ ,transitionDuration: (dur-settings.transitionDuration*2/3-100)+"ms"
2569
+ ,transitionDelay: (settings.transitionDuration*2/3)+'ms'
2570
+ ,transitionTimingFunction: 'linear'
2571
+ };
2572
+ css[durationSettings.barProperty] = durationSettings.barPropertyEnd;
2573
+ $.jmpress("css", $(durationSettings.barSelector), css);
2574
+ }
2575
+ var jmpress = this;
2576
+ if(current.durationTimeout) {
2577
+ clearTimeout(current.durationTimeout);
2578
+ current.durationTimeout = undefined;
2579
+ }
2580
+ current.durationTimeout = setTimeout(function() {
2581
+ var action = eventData.stepData.durationAction || durationSettings.defaultAction;
2582
+ $(jmpress).jmpress(action);
2583
+ }, dur);
2584
+ }
2585
+ });
2586
+ }(jQuery, document, window));
2587
+
2588
+ /*
2589
+ * jmpress.presentation-mode plugin
2590
+ * Display a window for the presenter with notes and a control and view of the
2591
+ * presentation
2592
+ */
2593
+ (function( $, document, window, undefined ) {
2594
+
2595
+ 'use strict';
2596
+ var $jmpress = $.jmpress;
2597
+
2598
+ var PREFIX = "jmpress-presentation-";
2599
+
2600
+ /* FUNCTIONS */
2601
+ function randomString() {
2602
+ return "" + Math.round(Math.random() * 100000, 0);
2603
+ }
2604
+
2605
+ /* DEFAULTS */
2606
+ $jmpress("defaults").presentationMode = {
2607
+ use: true,
2608
+ url: "presentation-screen.html",
2609
+ notesUrl: false,
2610
+ transferredValues: ["userZoom", "userTranslateX", "userTranslateY"]
2611
+ };
2612
+ $jmpress("defaults").keyboard.keys[80] = "presentationPopup"; // p key
2613
+
2614
+ /* HOOKS */
2615
+ $jmpress("afterInit", function( nil, eventData) {
2616
+ var current = eventData.current;
2617
+
2618
+ current.selectMessageListeners = [];
2619
+
2620
+ if(eventData.settings.presentationMode.use) {
2621
+
2622
+ window.addEventListener("message", function(event) {
2623
+ // We do not test orgin, because we want to accept messages
2624
+ // from all orgins
2625
+ try {
2626
+ if(typeof event.data !== "string" || event.data.indexOf(PREFIX) !== 0) {
2627
+ return;
2628
+ }
2629
+ var json = JSON.parse(event.data.slice(PREFIX.length));
2630
+ switch(json.type) {
2631
+ case "select":
2632
+ $.each(eventData.settings.presentationMode.transferredValues, function(idx, name) {
2633
+ eventData.current[name] = json[name];
2634
+ });
2635
+ if(/[a-z0-9\-]+/i.test(json.targetId) && typeof json.substep in {number:1,undefined:1}) {
2636
+ $(eventData.jmpress).jmpress("select", {step: "#"+json.targetId, substep: json.substep}, json.reason);
2637
+ } else {
2638
+ $.error("For security reasons the targetId must match /[a-z0-9\\-]+/i and substep must be a number.");
2639
+ }
2640
+ break;
2641
+ case "listen":
2642
+ current.selectMessageListeners.push(event.source);
2643
+ break;
2644
+ case "ok":
2645
+ clearTimeout(current.presentationPopupTimeout);
2646
+ break;
2647
+ case "read":
2648
+ try {
2649
+ event.source.postMessage(PREFIX + JSON.stringify({type: "url", url: window.location.href, notesUrl: eventData.settings.presentationMode.notesUrl}), "*");
2650
+ } catch(e) {
2651
+ $.error("Cannot post message to source: " + e);
2652
+ }
2653
+ break;
2654
+ default:
2655
+ throw "Unknown message type: " + json.type;
2656
+ }
2657
+ } catch(e) {
2658
+ $.error("Received message is malformed: " + e);
2659
+ }
2660
+ });
2661
+ try {
2662
+ if(window.parent && window.parent !== window) {
2663
+ window.parent.postMessage(PREFIX + JSON.stringify({
2664
+ "type": "afterInit"
2665
+ }), "*");
2666
+ }
2667
+ } catch(e) {
2668
+ $.error("Cannot post message to parent: " + e);
2669
+ }
2670
+ }
2671
+ });
2672
+ $jmpress("afterDeinit", function( nil, eventData) {
2673
+ if(eventData.settings.presentationMode.use) {
2674
+ try {
2675
+ if(window.parent && window.parent !== window) {
2676
+ window.parent.postMessage(PREFIX + JSON.stringify({
2677
+ "type": "afterDeinit"
2678
+ }), "*");
2679
+ }
2680
+ } catch(e) {
2681
+ $.error("Cannot post message to parent: " + e);
2682
+ }
2683
+ }
2684
+ });
2685
+ $jmpress("setActive", function( step, eventData) {
2686
+ var stepId = $(eventData.delegatedFrom).attr("id"),
2687
+ substep = eventData.substep,
2688
+ reason = eventData.reason;
2689
+ $.each(eventData.current.selectMessageListeners, function(idx, listener) {
2690
+ try {
2691
+ var msg = {
2692
+ "type": "select",
2693
+ "targetId": stepId,
2694
+ "substep": substep,
2695
+ "reason": reason
2696
+ };
2697
+ $.each(eventData.settings.presentationMode.transferredValues, function(idx, name) {
2698
+ msg[name] = eventData.current[name];
2699
+ });
2700
+ listener.postMessage(PREFIX + JSON.stringify(msg), "*");
2701
+ } catch(e) {
2702
+ $.error("Cannot post message to listener: " + e);
2703
+ }
2704
+ });
2705
+ });
2706
+ $jmpress("register", "presentationPopup", function() {
2707
+ function trySend() {
2708
+ jmpress.jmpress("current").presentationPopupTimeout = setTimeout(trySend, 100);
2709
+ try {
2710
+ popup.postMessage(PREFIX + JSON.stringify({type: "url", url: window.location.href, notesUrl: jmpress.jmpress("settings").presentationMode.notesUrl}), "*");
2711
+ } catch(e) {
2712
+ }
2713
+ }
2714
+ var jmpress = $(this),
2715
+ popup;
2716
+ if(jmpress.jmpress("settings").presentationMode.use) {
2717
+ popup = window.open($(this).jmpress("settings").presentationMode.url);
2718
+ jmpress.jmpress("current").presentationPopupTimeout = setTimeout(trySend, 100);
2719
+ }
2720
+ });
2721
+ }(jQuery, document, window));
modules/shortcodes/js/jmpress.min.js ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*!
2
+ * jmpress.js v0.4.5
3
+ * http://jmpressjs.github.com/jmpress.js
4
+ *
5
+ * A jQuery plugin to build a website on the infinite canvas.
6
+ *
7
+ * Copyright 2013 Kyle Robinson Young @shama & Tobias Koppers @sokra
8
+ * Licensed MIT
9
+ * http://www.opensource.org/licenses/mit-license.php
10
+ *
11
+ * Based on the foundation laid by Bartek Szopka @bartaz
12
+ */(function(e,t,s,a){"use strict";function r(e){if(e){var t=1+e.substr(1).search(/[A-Z]/),s=e.substr(0,t).toLowerCase(),a=e.substr(t).toLowerCase();return"-"+s+"-"+a}}function n(e){return e?e+",":""}function i(e){return e.length>0?e:null}function o(r){function n(t,s){var a=p(t),r={oldStyle:e(t).attr("style")||""},n={data:a,stepData:r};f.call(this,"beforeInitStep",e(t),n),r.delegate=a.delegate,f.call(this,"initStep",e(t),n),e(t).data("stepData",r),e(t).attr("id")||e(t).attr("id","step-"+(s+1)),f.call(this,"applyStep",e(t),n)}function o(t){var s=e(t).data("stepData");e(t).attr("style",s.oldStyle),f.call(this,"unapplyStep",e(t),{stepData:s})}function c(t){f.call(this,"unapplyStep",e(t),{stepData:t.data("stepData")}),f.call(this,"applyStep",e(t),{stepData:t.data("stepData")})}function l(){O&&f.call(this,"setInactive",O,{stepData:e(O).data("stepData"),reason:"deinit"}),Y.jmpressClass&&e(I).removeClass(Y.jmpressClass),f.call(this,"beforeDeinit",e(this),{}),e(A.stepSelector,I).each(function(){o.call(I,this)}),k.attr("style",Z.container),A.fullscreen&&e("html").attr("style",""),z.attr("style",Z.area),e(X).children().each(function(){I.append(e(this))}),A.fullscreen?X.remove():(X.remove(),z.remove()),f.call(this,"afterDeinit",e(this),{}),e(I).data("jmpressmethods",!1)}function f(t,s,a){a.settings=A,a.current=Y,a.container=k,a.parents=s?d(s):null,a.current=Y,a.jmpress=this;var r={};return e.each(A[t],function(e,t){r.value=t.call(I,s,a)||r.value}),r.value}function d(t){return e(t).parentsUntil(I).not(I).filter(A.stepSelector)}function v(e){return g({step:O,substep:F},e)}function g(t,s){var r;if(e.isPlainObject(t)&&(r=t.substep,t=t.step),"string"==typeof t&&(t=I.find(t).first()),!t||!e(t).data("stepData"))return!1;b.call(this);var n=e(t).data("stepData"),o=!1;if(f.call(this,"beforeChange",t,{stepData:n,reason:s,cancel:function(){o=!0}}),o)return a;var c={},l=t;e(t).data("stepData").delegate&&(l=i(e(t).parentsUntil(I).filter(A.stepSelector).filter(n.delegate))||i(e(t).near(n.delegate))||i(e(t).near(n.delegate,!0))||i(e(n.delegate,I)),l?n=l.data("stepData"):l=t),Q&&f.call(this,"setInactive",Q,{stepData:e(Q).data("stepData"),delegatedFrom:O,reason:s,target:c,nextStep:l,nextSubstep:r,nextStepData:n});var u={stepData:n,delegatedFrom:t,reason:s,target:c,substep:r,prevStep:Q,prevSubstep:F,prevStepData:Q&&e(Q).data("stepData")};return f.call(this,"beforeActive",l,u),f.call(this,"setActive",l,u),Y.jmpressClass&&e(I).removeClass(Y.jmpressClass),e(I).addClass(Y.jmpressClass="step-"+e(l).attr("id")),Y.jmpressDelegatedClass&&e(I).removeClass(Y.jmpressDelegatedClass),e(I).addClass(Y.jmpressDelegatedClass="delegating-step-"+e(t).attr("id")),f.call(this,"applyTarget",l,e.extend({canvas:X,area:z,beforeActive:Q},u)),O=t,F=u.substep,Q=l,Y.idleTimeout&&clearTimeout(Y.idleTimeout),Y.idleTimeout=setTimeout(function(){f.call(this,"idle",l,u)},Math.max(1,A.transitionDuration-100)),l}function b(){(function t(){function a(){(0!==e(k).scrollTop()||0!==e(k).scrollLeft())&&t()}if("BODY"===e(k)[0].tagName)try{s.scrollTo(0,0)}catch(r){}e(k).scrollTop(0),e(k).scrollLeft(0),setTimeout(a,1),setTimeout(a,10),setTimeout(a,100),setTimeout(a,200),setTimeout(a,400)})()}function y(e){return g.call(this,e,"jump")}function j(){return g.call(this,f.call(this,"selectNext",O,{stepData:e(O).data("stepData"),substep:F}),"next")}function D(){return g.call(this,f.call(this,"selectPrev",O,{stepData:e(O).data("stepData"),substep:F}),"prev")}function S(){return g.call(this,f.call(this,"selectHome",O,{stepData:e(O).data("stepData")}),"home")}function x(){return g.call(this,f.call(this,"selectEnd",O,{stepData:e(O).data("stepData")}),"end")}function w(t){return u(X,t||{}),e(X)}function C(){return Q&&e(Q)}function T(t,s,r){return h[t]?f.call(this,t,s,r):(e.error("callback "+t+" is not registered."),a)}function M(){var e=navigator.userAgent.toLowerCase();return-1===e.search(/(iphone)|(ipod)|(android)/)||-1!==e.search(/(chrome)/)}r=e.extend(!0,{},r||{});var P={},N=null;for(N in h)P[N]=e.isFunction(r[N])?[r[N]]:r[N],r[N]=[];var A=e.extend(!0,{},m,r);for(N in h)P[N]&&Array.prototype.push.apply(A[N],P[N]);var I=e(this),k=null,z=null,Z={container:"",area:""},X=null,Y=null,O=!1,F=null,Q=!1;if(I.data("jmpressmethods",{select:g,reselect:v,scrollFix:b,goTo:y,next:j,prev:D,home:S,end:x,canvas:w,container:function(){return k},settings:function(){return A},active:C,current:function(){return Y},fire:T,init:function(t){n.call(this,e(t),Y.nextIdNumber++)},deinit:function(t){t?o.call(this,e(t)):l.call(this)},reapply:c}),M()===!1)return A.notSupportedClass&&I.addClass(A.notSupportedClass),a;A.notSupportedClass&&I.removeClass(A.notSupportedClass);var E=e(A.stepSelector,I);k=I,z=e("<div />"),X=e("<div />"),e(I).children().filter(E).each(function(){X.append(e(this))}),A.fullscreen&&(k=e("body"),e("html").css({overflow:"hidden"}),z=I),Z.area=z.attr("style")||"",Z.container=k.attr("style")||"",A.fullscreen?(k.css({height:"100%"}),I.append(X)):(k.css({position:"relative"}),z.append(X),I.append(z)),e(k).addClass(A.containerClass),e(z).addClass(A.areaClass),e(X).addClass(A.canvasClass),t.documentElement.style.height="100%",k.css({overflow:"hidden"});var L={position:"absolute",transitionDuration:"0s"};L=e.extend({},A.animation,L),u(z,L),u(z,{top:"50%",left:"50%",perspective:"1000px"}),u(X,L),Y={},f.call(this,"beforeInit",null,{}),E.each(function(e){n.call(I,this,e)}),Y.nextIdNumber=E.length,f.call(this,"afterInit",null,{}),g.call(this,f.call(this,"selectInitialStep","init",{})),A.initClass&&e(E).removeClass(A.initClass)}function c(){return m}function l(t,s){e.isFunction(s)?g[t]?e.error("function "+t+" is already registered."):g[t]=s:h[t]?e.error("callback "+t+" is already registered."):(h[t]=1,m[t]=[])}function u(t,s){var a,r,n={};for(a in s)s.hasOwnProperty(a)&&(r=d(a),null!==r&&(n[r]=s[a]));return e(t).css(n),t}function p(t){function s(e){e=e.split("-");for(var t=1;e.length>t;t++)e[t]=e[t].substr(0,1).toUpperCase()+e[t].substr(1);return e.join("")}if(e(t)[0].dataset)return e.extend({},e(t)[0].dataset);var a={},r=e(t)[0].attributes;return e.each(r,function(e,t){"data-"===t.nodeName.substr(0,5)&&(a[s(t.nodeName.substr(5))]=t.nodeValue)}),a}function f(){return!!e(this).data("jmpressmethods")}var d=function(){var e=t.createElement("dummy").style,s="Webkit Moz O ms Khtml".split(" "),r={};return function(t){if(r[t]===a){var n=t.charAt(0).toUpperCase()+t.substr(1),i=(t+" "+s.join(n+" ")+n).split(" ");r[t]=null;for(var o in i)if(e[i[o]]!==a){r[t]=i[o];break}}return r[t]}}(),m={stepSelector:".step",containerClass:"",canvasClass:"",areaClass:"",notSupportedClass:"not-supported",fullscreen:!0,animation:{transformOrigin:"top left",transitionProperty:n(r(d("transform")))+n(r(d("perspective")))+"opacity",transitionDuration:"1s",transitionDelay:"500ms",transitionTimingFunction:"ease-in-out",transformStyle:"preserve-3d"},transitionDuration:1500},h={beforeChange:1,beforeInitStep:1,initStep:1,beforeInit:1,afterInit:1,beforeDeinit:1,afterDeinit:1,applyStep:1,unapplyStep:1,setInactive:1,beforeActive:1,setActive:1,selectInitialStep:1,selectPrev:1,selectNext:1,selectHome:1,selectEnd:1,idle:1,applyTarget:1};for(var v in h)m[v]=[];var g={init:o,initialized:f,deinit:function(){},css:u,pfx:d,defaults:c,register:l,dataset:p};e.fn.jmpress=function(t){function s(){var s=e(this).data("jmpressmethods");if(s&&s[t])return s[t].apply(this,Array.prototype.slice.call(arguments,1));if(g[t])return g[t].apply(this,Array.prototype.slice.call(arguments,1));if(h[t]&&s){var a=s.settings(),r=Array.prototype.slice.call(arguments,1)[0];e.isFunction(r)&&(a[t]=a[t]||[],a[t].push(r))}else{if("object"==typeof t||!t)return o.apply(this,arguments);e.error("Method "+t+" does not exist on jQuery.jmpress")}return this}var a,r=arguments;return e(this).each(function(e,t){a=s.apply(t,r)}),a},e.extend({jmpress:function(t){if(g[t])return g[t].apply(this,Array.prototype.slice.call(arguments,1));if(h[t]){var s=Array.prototype.slice.call(arguments,1)[0];e.isFunction(s)?m[t].push(s):e.error("Second parameter should be a function: $.jmpress( callbackName, callbackFunction )")}else e.error("Method "+t+" does not exist on jQuery.jmpress")}})})(jQuery,document,window),function(e){"use strict";function t(t,s,a,r){var n;return t.each(function(t,i){return r&&(n=s(i,a,r))?!1:e(i).is(a)?(n=i,!1):!r&&(n=s(i,a,r))?!1:undefined}),n}function s(a,r,n){var i=e(a).children();return n&&(i=e(i.get().reverse())),t(i,s,r,n)}function a(a,r,n){return t(e(a)[n?"prevAll":"nextAll"](),s,r,n)}function r(t,s,r){var n,i=e(t).parents();return i=e(i.get()),e.each(i.get(),function(t,i){return r&&e(i).is(s)?(n=i,!1):(n=a(i,s,r),n?!1:undefined)}),n}e.fn.near=function(t,n){var i=[];return e(this).each(function(e,o){var c=(n?!1:s(o,t,n))||a(o,t,n)||r(o,t,n);c&&i.push(c)}),e(i)}}(jQuery,document,window),function(e,t,s,a){"use strict";function r(e){return Math.round(1e4*e)/1e4+""}var n={3:{transform:function(t,s){var a="translate(-50%,-50%)";e.each(s,function(e,t){var s,n=["X","Y","Z"];if("translate"===t[0])a+=" translate3d("+r(t[1]||0)+"px,"+r(t[2]||0)+"px,"+r(t[3]||0)+"px)";else if("rotate"===t[0]){var i=t[4]?[1,2,3]:[3,2,1];for(s=0;3>s;s++)a+=" rotate"+n[i[s]-1]+"("+r(t[i[s]]||0)+"deg)"}else if("scale"===t[0])for(s=0;3>s;s++)a+=" scale"+n[s]+"("+r(t[s+1]||1)+")"}),e.jmpress("css",t,e.extend({},{transform:a}))}},2:{transform:function(t,s){var a="translate(-50%,-50%)";e.each(s,function(e,t){var s=["X","Y"];if("translate"===t[0])a+=" translate("+r(t[1]||0)+"px,"+r(t[2]||0)+"px)";else if("rotate"===t[0])a+=" rotate("+r(t[3]||0)+"deg)";else if("scale"===t[0])for(var n=0;2>n;n++)a+=" scale"+s[n]+"("+r(t[n+1]||1)+")"}),e.jmpress("css",t,e.extend({},{transform:a}))}},1:{transform:function(t,s){var a={top:0,left:0};e.each(s,function(e,t){"translate"===t[0]&&(a.left=Math.round(t[1]||0)+"px",a.top=Math.round(t[2]||0)+"px")}),t.animate(a,1e3)}}},i=function(){return e.jmpress("pfx","perspective")?n[3]:e.jmpress("pfx","transform")?n[2]:n[1]}();e.jmpress("defaults").reasonableAnimation={},e.jmpress("initStep",function(t,s){var a=s.data,r=s.stepData,n=parseFloat;e.extend(r,{x:n(a.x)||0,y:n(a.y)||0,z:n(a.z)||0,r:n(a.r)||0,phi:n(a.phi)||0,rotate:n(a.rotate)||0,rotateX:n(a.rotateX)||0,rotateY:n(a.rotateY)||0,rotateZ:n(a.rotateZ)||0,revertRotate:!1,scale:n(a.scale)||1,scaleX:n(a.scaleX)||!1,scaleY:n(a.scaleY)||!1,scaleZ:n(a.scaleZ)||1})}),e.jmpress("afterInit",function(t,s){var a=s.settings.stepSelector,r=s.current;r.perspectiveScale=1,r.maxNestedDepth=0;for(var n=e(s.jmpress).find(a).children(a);n.length;)r.maxNestedDepth++,n=n.children(a)}),e.jmpress("applyStep",function(t,s){e.jmpress("css",e(t),{position:"absolute",transformStyle:"preserve-3d"}),s.parents.length>0&&e.jmpress("css",e(t),{top:"50%",left:"50%"});var a=s.stepData,r=[["translate",a.x||a.r*Math.sin(a.phi*Math.PI/180),a.y||-a.r*Math.cos(a.phi*Math.PI/180),a.z],["rotate",a.rotateX,a.rotateY,a.rotateZ||a.rotate,!0],["scale",a.scaleX||a.scale,a.scaleY||a.scale,a.scaleZ||a.scale]];i.transform(t,r)}),e.jmpress("setActive",function(t,s){var r=s.target,n=s.stepData,i=r.transform=[];r.perspectiveScale=1;for(var o=s.current.maxNestedDepth;o>(s.parents.length||0);o--)i.push(["scale"],["rotate"],["translate"]);i.push(["scale",1/(n.scaleX||n.scale),1/(n.scaleY||n.scale),1/n.scaleZ]),i.push(["rotate",-n.rotateX,-n.rotateY,-(n.rotateZ||n.rotate)]),i.push(["translate",-(n.x||n.r*Math.sin(n.phi*Math.PI/180)),-(n.y||-n.r*Math.cos(n.phi*Math.PI/180)),-n.z]),r.perspectiveScale*=n.scaleX||n.scale,e.each(s.parents,function(t,s){var a=e(s).data("stepData");i.push(["scale",1/(a.scaleX||a.scale),1/(a.scaleY||a.scale),1/a.scaleZ]),i.push(["rotate",-a.rotateX,-a.rotateY,-(a.rotateZ||a.rotate)]),i.push(["translate",-(a.x||a.r*Math.sin(a.phi*Math.PI/180)),-(a.y||-a.r*Math.cos(a.phi*Math.PI/180)),-a.z]),r.perspectiveScale*=a.scaleX||a.scale}),e.each(i,function(e,t){function r(r){s.current["rotate"+r+"-"+e]===a&&(s.current["rotate"+r+"-"+e]=t[r]||0);var n=s.current["rotate"+r+"-"+e],i=t[r]||0,o=n%360,c=i%360;0>o&&(o+=360),0>c&&(c+=360);var l=c-o;-180>l?l+=360:l>180&&(l-=360),s.current["rotate"+r+"-"+e]=t[r]=n+l}"rotate"===t[0]&&(r(1),r(2),r(3))})}),e.jmpress("applyTarget",function(t,s){var r,n=s.target,o=(s.stepData,s.settings),c=1.3*n.perspectiveScale<s.current.perspectiveScale,l=n.perspectiveScale>1.3*s.current.perspectiveScale,u=-1;e.each(n.transform,function(e,t){return 1>=t.length||"rotate"===t[0]&&0===t[1]%360&&0===t[2]%360&&0===t[3]%360?a:"scale"!==t[0]?!1:(u=e,a)}),u!==s.current.oldLastScale&&(c=l=!1,s.current.oldLastScale=u);var p=[];if(-1!==u)for(;u>=0;)"scale"===n.transform[u][0]&&(p.push(n.transform[u]),n.transform[u]=["scale"]),u--;var f=o.animation;o.reasonableAnimation[s.reason]&&(f=e.extend({},f,o.reasonableAnimation[s.reason])),r={perspective:Math.round(1e3*n.perspectiveScale)+"px"},r=e.extend({},f,r),c||(r.transitionDelay="0s"),s.beforeActive||(r.transitionDuration="0s",r.transitionDelay="0s"),e.jmpress("css",s.area,r),i.transform(s.area,p),r=e.extend({},f),l||(r.transitionDelay="0s"),s.beforeActive||(r.transitionDuration="0s",r.transitionDelay="0s"),s.current.perspectiveScale=n.perspectiveScale,e.jmpress("css",s.canvas,r),i.transform(s.canvas,n.transform)})}(jQuery,document,window),function(e){"use strict";var t=e.jmpress,s="activeClass",a="nestedActiveClass",r=t("defaults");r[a]="nested-active",r[s]="active",t("setInactive",function(t,r){var n=r.settings,i=n[s],o=n[a];i&&e(t).removeClass(i),o&&e.each(r.parents,function(t,s){e(s).removeClass(o)})}),t("setActive",function(t,r){var n=r.settings,i=n[s],o=n[a];i&&e(t).addClass(i),o&&e.each(r.parents,function(t,s){e(s).addClass(o)})})}(jQuery,document,window),function(e){"use strict";function t(t,s){return e(this).find(s.settings.stepSelector).first()}function s(t,s,a,r){if(!s)return!1;var n=a.settings.stepSelector;s=e(s);do{var i=s.near(n,r);if((0===i.length||0===i.closest(t).length)&&(i=e(t).find(n)[r?"last":"first"]()),!i.length)return!1;s=i}while(s.data("stepData").exclude);return s}var a=e.jmpress;a("initStep",function(e,t){t.stepData.exclude=t.data.exclude&&-1===["false","no"].indexOf(t.data.exclude)}),a("selectInitialStep",t),a("selectHome",t),a("selectEnd",function(t,s){return e(this).find(s.settings.stepSelector).last()}),a("selectPrev",function(e,t){return s(this,e,t,!0)}),a("selectNext",function(e,t){return s(this,e,t)})}(jQuery,document,window),function(e){"use strict";e.jmpress("selectInitialStep",function(e,t){return t.settings.start})}(jQuery,document,window),function(e){"use strict";function t(t,s,a){for(var r=0;s.length-1>r;r++){var n=s[r],i=s[r+1];e(t).jmpress("initialized")?e(n,t).data("stepData")[a]=i:e(n,t).attr("data-"+a,i)}}function s(t,s,a,r){var n=s.stepData;if(n[a]){var i=e(t).near(n[a],r);if(i&&i.length)return i;if(i=e(n[a],this)[r?"last":"first"](),i&&i.length)return i}}var a=e.jmpress;a("register","route",function(e,s,a){"string"==typeof e&&(e=[e,e]),t(this,e,a?"prev":"next"),s||t(this,e.reverse(),a?"next":"prev")}),a("initStep",function(e,t){for(var s in{next:1,prev:1})t.stepData[s]=t.data[s]}),a("selectNext",function(e,t){return s.call(this,e,t,"next")}),a("selectPrev",function(e,t){return s.call(this,e,t,"prev",!0)})}(jQuery,document,window),function(e){"use strict";var t=e.jmpress,s="ajax:afterStepLoaded",a="ajax:loadStep";t("register",a),t("register",s),t("defaults").ajaxLoadedClass="loaded",t("initStep",function(t,s){s.stepData.src=e(t).attr("href")||s.data.src||!1,s.stepData.srcLoaded=!1}),t(a,function(t,a){var r=a.stepData,n=r&&r.src,i=a.settings;n&&(e(t).addClass(i.ajaxLoadedClass),r.srcLoaded=!0,e(t).load(n,function(r,n,i){e(a.jmpress).jmpress("fire",s,t,e.extend({},a,{response:r,status:n,xhr:i}))}))}),t("idle",function(t,s){if(t){var r=s.settings,n=e(this);s.stepData;var i=e(t).add(e(t).near(r.stepSelector)).add(e(t).near(r.stepSelector,!0)).add(n.jmpress("fire","selectPrev",t,{stepData:e(t).data("stepData")})).add(n.jmpress("fire","selectNext",t,{stepData:e(t).data("stepData")}));i.each(function(){var t=this,s=e(t).data("stepData");s.src&&!s.srcLoaded&&n.jmpress("fire",a,t,{stepData:e(t).data("stepData")})})}}),t("setActive",function(t){var s=e(t).data("stepData");s.src&&!s.srcLoaded&&e(this).jmpress("fire",a,t,{stepData:e(t).data("stepData")})})}(jQuery,document,window),function(e,t,s,a){"use strict";function r(){return""+Math.round(1e5*Math.random(),0)}function n(t){try{var r=e("#"+s.location.hash.replace(/^#\/?/,""));return r.length>0&&r.is(t.stepSelector)?r:a}catch(n){}}function i(e){var t="#/"+e;s.history&&s.history.pushState?s.location.hash!==t&&s.history.pushState({},"",t):s.location.hash!==t&&(s.location.hash=t)}var o=e.jmpress,c="a[href^=#]";o("defaults").hash={use:!0,update:!0,bindChange:!0},o("selectInitialStep",function(t,o){var l=o.settings,u=l.hash,p=o.current,f=e(this);return o.current.hashNamespace=".jmpress-"+r(),u.use?(u.bindChange&&(e(s).bind("hashchange"+p.hashNamespace,function(e){var t=n(l);f.jmpress("initialized")&&f.jmpress("scrollFix"),t&&t.length&&(t.attr("id")!==f.jmpress("active").attr("id")&&f.jmpress("select",t),i(t.attr("id"))),e.preventDefault()}),e(c).on("click"+p.hashNamespace,function(t){var s=e(this).attr("href");try{e(s).is(l.stepSelector)&&(f.jmpress("select",s),t.preventDefault(),t.stopPropagation())}catch(a){}})),n(l)):a}),o("afterDeinit",function(t,a){e(c).off(a.current.hashNamespace),e(s).unbind(a.current.hashNamespace)}),o("setActive",function(t,s){var a=s.settings,r=s.current;a.hash.use&&a.hash.update&&(clearTimeout(r.hashtimeout),r.hashtimeout=setTimeout(function(){i(e(s.delegatedFrom).attr("id"))},a.transitionDuration+200))})}(jQuery,document,window),function(e,t,s,a){"use strict";function r(){return""+Math.round(1e5*Math.random(),0)}function n(e){e.preventDefault(),e.stopPropagation()}var i=e.jmpress,o="next",c="prev";i("defaults").keyboard={use:!0,keys:{33:c,37:c,38:c,9:o+":"+c,32:o,34:o,39:o,40:o,36:"home",35:"end"},ignore:{INPUT:[32,37,38,39,40],TEXTAREA:[32,37,38,39,40],SELECT:[38,40]},tabSelector:"a[href]:visible, :input:visible"},i("afterInit",function(s,i){var o=i.settings,c=o.keyboard,l=c.ignore,u=i.current,p=e(this);o.fullscreen||p.attr("tabindex",0),u.keyboardNamespace=".jmpress-"+r(),e(o.fullscreen?t:p).bind("keypress"+u.keyboardNamespace,function(e){for(var t in l)if(e.target.nodeName===t&&-1!==l[t].indexOf(e.which))return;(e.which>=37&&40>=e.which||32===e.which)&&n(e)}),e(o.fullscreen?t:p).bind("keydown"+u.keyboardNamespace,function(t){var s=e(t.target);if((o.fullscreen||s.closest(p).length)&&c.use){for(var r in l)if(s[0].nodeName===r&&-1!==l[r].indexOf(t.which))return;var i,u=!1;if(9===t.which){if(s.closest(p.jmpress("active")).length?(i=s.near(c.tabSelector,t.shiftKey),e(i).closest(o.stepSelector).is(p.jmpress("active"))||(i=a)):t.shiftKey?u=!0:i=p.jmpress("active").find("a[href], :input").filter(":visible").first(),i&&i.length>0)return i.focus(),p.jmpress("scrollFix"),n(t),a;t.shiftKey&&(u=!0)}var f=c.keys[t.which];"string"==typeof f?(-1!==f.indexOf(":")&&(f=f.split(":"),f=t.shiftKey?f[1]:f[0]),p.jmpress(f),n(t)):e.isFunction(f)?f.call(p,t):f&&(p.jmpress.apply(p,f),n(t)),u&&(i=p.jmpress("active").find("a[href], :input").filter(":visible").last(),i.focus(),p.jmpress("scrollFix"))}})}),i("afterDeinit",function(s,a){e(t).unbind(a.current.keyboardNamespace)})}(jQuery,document,window),function(e,t,s,a){"use strict";function r(){return""+Math.round(1e5*Math.random(),0)}function n(e,t){return Math.max(Math.min(e,t),-t)}function i(t,s,a){var r=e(this).jmpress("current"),i=e(this).jmpress("settings"),o=e(this).jmpress("active").data("stepData"),c=e(this).jmpress("container");if(!(0===r.userZoom&&0>a)){var l=o.viewPortZoomable||i.viewPort.zoomable;if(!(r.userZoom===l&&a>0)){r.userZoom+=a;var u=e(c).innerWidth()/2,p=e(c).innerHeight()/2;t=t?t-u:t,s=s?s-p:s,r.userTranslateX=n(r.userTranslateX-a*t/r.zoomOriginWindowScale/l,u*r.userZoom*r.userZoom/l),r.userTranslateY=n(r.userTranslateY-a*s/r.zoomOriginWindowScale/l,p*r.userZoom*r.userZoom/l),e(this).jmpress("reselect","zoom")}}}var o=function(){var e=navigator.userAgent.toLowerCase(),t=/(chrome)[ \/]([\w.]+)/.exec(e)||/(webkit)[ \/]([\w.]+)/.exec(e)||/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(e)||/(msie) ([\w.]+)/.exec(e)||0>e.indexOf("compatible")&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(e)||[];return t[1]||""}(),c=e.jmpress("defaults");c.viewPort={width:!1,height:!1,maxScale:0,minScale:0,zoomable:0,zoomBindMove:!0,zoomBindWheel:!0};var l=c.keyboard.keys;l["mozilla"===o?107:187]="zoomIn",l["mozilla"===o?109:189]="zoomOut",c.reasonableAnimation.resize={transitionDuration:"0s",transitionDelay:"0ms"},c.reasonableAnimation.zoom={transitionDuration:"0s",transitionDelay:"0ms"},e.jmpress("initStep",function(e,t){for(var s in{viewPortHeight:1,viewPortWidth:1,viewPortMinScale:1,viewPortMaxScale:1,viewPortZoomable:1})t.stepData[s]=t.data[s]&&parseFloat(t.data[s])}),e.jmpress("afterInit",function(n,i){var o=this;i.current.viewPortNamespace=".jmpress-"+r(),e(s).bind("resize"+i.current.viewPortNamespace,function(){e(o).jmpress("reselect","resize")}),i.current.userZoom=0,i.current.userTranslateX=0,i.current.userTranslateY=0,i.settings.viewPort.zoomBindWheel&&e(i.settings.fullscreen?t:this).bind("mousewheel"+i.current.viewPortNamespace+" DOMMouseScroll"+i.current.viewPortNamespace,function(t,s){s=s||t.originalEvent.wheelDelta||-t.originalEvent.detail;var a=s/Math.abs(s);return 0>a?e(i.jmpress).jmpress("zoomOut",t.originalEvent.x,t.originalEvent.y):a>0&&e(i.jmpress).jmpress("zoomIn",t.originalEvent.x,t.originalEvent.y),!1}),i.settings.viewPort.zoomBindMove&&e(i.settings.fullscreen?t:this).bind("mousedown"+i.current.viewPortNamespace,function(e){i.current.userZoom&&(i.current.userTranslating={x:e.clientX,y:e.clientY},e.preventDefault(),e.stopImmediatePropagation())}).bind("mousemove"+i.current.viewPortNamespace,function(t){var s=i.current.userTranslating;s&&(e(o).jmpress("zoomTranslate",t.clientX-s.x,t.clientY-s.y),s.x=t.clientX,s.y=t.clientY,t.preventDefault(),t.stopImmediatePropagation())}).bind("mouseup"+i.current.viewPortNamespace,function(e){i.current.userTranslating&&(i.current.userTranslating=a,e.preventDefault(),e.stopImmediatePropagation())})}),e.jmpress("register","zoomIn",function(e,t){i.call(this,e||0,t||0,1)}),e.jmpress("register","zoomOut",function(e,t){i.call(this,e||0,t||0,-1)}),e.jmpress("register","zoomTranslate",function(t,s){var a=e(this).jmpress("current"),r=e(this).jmpress("settings"),i=e(this).jmpress("active").data("stepData"),o=e(this).jmpress("container"),c=i.viewPortZoomable||r.viewPort.zoomable,l=e(o).innerWidth(),u=e(o).innerHeight();a.userTranslateX=n(a.userTranslateX+t/a.zoomOriginWindowScale,l*a.userZoom*a.userZoom/c),a.userTranslateY=n(a.userTranslateY+s/a.zoomOriginWindowScale,u*a.userZoom*a.userZoom/c),e(this).jmpress("reselect","zoom")}),e.jmpress("afterDeinit",function(a,r){e(r.settings.fullscreen?t:this).unbind(r.current.viewPortNamespace),e(s).unbind(r.current.viewPortNamespace)}),e.jmpress("setActive",function(t,s){var a=s.settings.viewPort,r=s.stepData.viewPortHeight||a.height,n=s.stepData.viewPortWidth||a.width,i=s.stepData.viewPortMaxScale||a.maxScale,o=s.stepData.viewPortMinScale||a.minScale,c=r&&e(s.container).innerHeight()/r,l=n&&e(s.container).innerWidth()/n,u=(l||c)&&Math.min(l||c,c||l);if(u){u=u||1,i&&(u=Math.min(u,i)),o&&(u=Math.max(u,o));var p=s.stepData.viewPortZoomable||s.settings.viewPort.zoomable;if(p){var f=1/u-1/i;f/=p,u=1/(1/u-f*s.current.userZoom)}s.target.transform.reverse(),s.current.userTranslateX&&s.current.userTranslateY?s.target.transform.push(["translate",s.current.userTranslateX,s.current.userTranslateY,0]):s.target.transform.push(["translate"]),s.target.transform.push(["scale",u,u,1]),s.target.transform.reverse(),s.target.perspectiveScale/=u}s.current.zoomOriginWindowScale=u}),e.jmpress("setInactive",function(t,s){s.nextStep&&t&&e(s.nextStep).attr("id")===e(t).attr("id")||(s.current.userZoom=0,s.current.userTranslateX=0,s.current.userTranslateY=0)})}(jQuery,document,window),function(e){"use strict";function t(){return""+Math.round(1e5*Math.random(),0)}var s=e.jmpress;s("defaults").mouse={clickSelects:!0},s("afterInit",function(s,a){var r=a.settings,n=r.stepSelector,i=a.current,o=e(this);i.clickableStepsNamespace=".jmpress-"+t(),o.bind("click"+i.clickableStepsNamespace,function(t){if(r.mouse.clickSelects&&!i.userZoom){var s=e(t.target).closest(n);s.is(o.jmpress("active"))||s.length&&(o.jmpress("select",s[0],"click"),t.preventDefault(),t.stopPropagation())}})}),s("afterDeinit",function(t,s){e(this).unbind(s.current.clickableStepsNamespace)})}(jQuery,document,window),function(e,t){"use strict";function s(){return""+Math.round(1e5*Math.random(),0)}var a=e.jmpress;a("afterInit",function(a,r){var n=r.settings,i=r.current,o=r.jmpress;i.mobileNamespace=".jmpress-"+s();var c,l=[0,0];e(n.fullscreen?t:o).bind("touchstart"+i.mobileNamespace,function(e){c=e.originalEvent.touches[0],l=[c.pageX,c.pageY]}).bind("touchmove"+i.mobileNamespace,function(e){return c=e.originalEvent.touches[0],e.preventDefault(),!1}).bind("touchend"+i.mobileNamespace,function(t){var s=[c.pageX,c.pageY],a=[s[0]-l[0],s[1]-l[1]];return Math.max(Math.abs(a[0]),Math.abs(a[1]))>50?(a=Math.abs(a[0])>Math.abs(a[1])?a[0]:a[1],e(o).jmpress(a>0?"prev":"next"),t.preventDefault(),!1):undefined})}),a("afterDeinit",function(s,a){var r=a.settings,n=a.current,i=a.jmpress;e(r.fullscreen?t:i).unbind(n.mobileNamespace)})}(jQuery,document,window),function(e,t,s,a){"use strict";function r(t,s,n){for(var i in s){var o=i;n&&(o=n+o.substr(0,1).toUpperCase()+o.substr(1)),e.isPlainObject(s[i])?r(t,s[i],o):t[o]===a&&(t[o]=s[i])}}function n(t,s){e.isArray(s)?s.length<t.length?e.error("more nested steps than children in template"):t.each(function(t,a){a=e(a);var n=a.data(l)||{};r(n,s[t]),a.data(l,n)}):e.isFunction(s)&&t.each(function(a,n){n=e(n);var i=n.data(l)||{};r(i,s(a,n,t)),n.data(l,i)})}function i(e,t,s,a){if(s.children){var r=t.children(a.settings.stepSelector);n(r,s.children)}o(e,s)}function o(e,t){r(e,t)}var c=e.jmpress,l="_template_",u="_applied_template_",p={};c("beforeInitStep",function(t,s){t=e(t);var a=s.data,r=a.template,n=t.data(u),o=t.data(l);r&&e.each(r.split(" "),function(e,r){var n=p[r];i(a,t,n,s)}),n&&i(a,t,n,s),o&&(i(a,t,o,s),t.data(l,null),o.template&&e.each(o.template.split(" "),function(e,r){var n=p[r];i(a,t,n,s)}))}),c("beforeInit",function(t,s){var a=c("dataset",this),r=a.template,i=s.settings.stepSelector;if(r){var o=p[r];n(e(this).find(i).filter(function(){return!e(this).parent().is(i)}),o.children)}}),c("register","template",function(t,s){p[t]=p[t]?e.extend(!0,{},p[t],s):e.extend(!0,{},s)}),c("register","apply",function(t,s){if(s)if(e.isArray(s))n(e(t),s);else{var a;a="string"==typeof s?p[s]:e.extend(!0,{},s),e(t).each(function(t,s){s=e(s);var n=s.data(u)||{};r(n,a),s.data(u,n)})}else{var i=e(this).jmpress("settings").stepSelector;n(e(this).find(i).filter(function(){return!e(this).parent().is(i)}),t)}})}(jQuery,document,window),function(e){"use strict";e.jmpress("setActive",function(t,s){s.prevStep!==t&&e(t).triggerHandler("enterStep")}),e.jmpress("setInactive",function(t,s){s.nextStep!==t&&e(t).triggerHandler("leaveStep")})}(jQuery,document,window),function(e,t,s,a){"use strict";function r(t){for(var s=t.split(" "),a=s[0],r={willClass:"will-"+a,doClass:"do-"+a,hasClass:"has-"+a},n="",i=1;s.length>i;i++){var o=s[i];switch(n){case"":"after"===o?n="after":e.warn("unknown keyword in '"+t+"'. '"+o+"' unknown.");break;case"after":if(o.match(/^[1-9][0-9]*m?s?/)){var c=parseFloat(o);-1!==o.indexOf("ms")?c*=1:-1!==o.indexOf("s")?c*=1e3:-1!==o.indexOf("m")&&(c*=6e4),r.delay=c}else r.after=Array.prototype.slice.call(s,i).join(" "),i=s.length}}return r}function n(t,s,a,r){r=r||t.length-1,a=a||0;for(var n=a;r+1>n;n++)if(e(t[n].element).is(s))return n}function i(t,s,a){e.each(s._on,function(e,s){t.push({substep:s.substep,delay:s.delay+a}),i(t,s.substep,s.delay+a)})}e.jmpress("defaults").customAnimationDataAttribute="jmpress",e.jmpress("afterInit",function(e,t){t.current.animationTimeouts=[],t.current.animationCleanupWaiting=[]}),e.jmpress("applyStep",function(t,s){function o(e,t){return t.substep._after?(u=t.substep._after,!1):a}var c={},l=[];if(e(t).find("[data-"+s.settings.customAnimationDataAttribute+"]").each(function(a,r){e(r).closest(s.settings.stepSelector).is(t)&&l.push({element:r})}),0!==l.length){e.each(l,function(t,a){a.info=r(e(a.element).data(s.settings.customAnimationDataAttribute)),e(a.element).addClass(a.info.willClass),a._on=[],a._after=null});var u={_after:a,_on:[],info:{}};if(e.each(l,function(e,t){var s=t.info.after;if(s)if("step"===s)s=u;else if("prev"===s)s=l[e-1];else{var r=n(l,s,0,e-1);r===a&&(r=n(l,s)),s=r===a||r===e?l[e-1]:l[r]}else s=l[e-1];if(s){if(!t.info.delay){if(!s._after)return s._after=t,a;s=s._after}s._on.push({substep:t,delay:t.info.delay||0})}}),u._after===a&&0===u._on.length){var p=n(l,s.stepData.startSubstep)||0;u._after=l[p]}var f=[];do{var d=[{substep:u,delay:0}];i(d,u,0),f.push(d),u=null,e.each(d,o)}while(u);c.list=f,e(t).data("substepsData",c)}}),e.jmpress("unapplyStep",function(t){var s=e(t).data("substepsData");s&&e.each(s.list,function(t,s){e.each(s,function(t,s){s.substep.info.willClass&&e(s.substep.element).removeClass(s.substep.info.willClass),s.substep.info.hasClass&&e(s.substep.element).removeClass(s.substep.info.hasClass),s.substep.info.doClass&&e(s.substep.element).removeClass(s.substep.info.doClass)})})}),e.jmpress("setActive",function(t,s){var r=e(t).data("substepsData");if(r){s.substep===a&&(s.substep="prev"===s.reason?r.list.length-1:0);var n=s.substep;e.each(s.current.animationTimeouts,function(e,t){clearTimeout(t)}),s.current.animationTimeouts=[],e.each(r.list,function(t,a){var r=n>t,i=n>=t;e.each(a,function(t,a){function n(){e(a.substep.element).addClass(a.substep.info.doClass)}a.substep.info.hasClass&&e(a.substep.element)[(r?"add":"remove")+"Class"](a.substep.info.hasClass),i&&!r&&a.delay&&"prev"!==s.reason?a.substep.info.doClass&&(e(a.substep.element).removeClass(a.substep.info.doClass),s.current.animationTimeouts.push(setTimeout(n,a.delay))):a.substep.info.doClass&&e(a.substep.element)[(i?"add":"remove")+"Class"](a.substep.info.doClass)})})}}),e.jmpress("setInactive",function(t,s){function a(t){e.each(t.list,function(t,s){e.each(s,function(t,s){s.substep.info.hasClass&&e(s.substep.element).removeClass(s.substep.info.hasClass),s.substep.info.doClass&&e(s.substep.element).removeClass(s.substep.info.doClass)})})}if(s.nextStep!==t){e.each(s.current.animationCleanupWaiting,function(e,t){a(t)}),s.current.animationCleanupWaiting=[];var r=e(t).data("substepsData");r&&s.current.animationCleanupWaiting.push(r)}}),e.jmpress("selectNext",function(t,s){if(s.substep!==a){var r=e(t).data("substepsData");if(r)return s.substep<r.list.length-1?{step:t,substep:s.substep+1}:a}}),e.jmpress("selectPrev",function(t,s){if(s.substep!==a){var r=e(t).data("substepsData");if(r)return s.substep>0?{step:t,substep:s.substep-1}:a}})}(jQuery,document,window),function(e,t){"use strict";e.jmpress("register","toggle",function(s,a,r){var n=this;e(t).bind("keydown",function(t){t.keyCode===s&&(e(n).jmpress("initialized")?e(n).jmpress("deinit"):e(n).jmpress(a))}),r&&e(n).jmpress(a)})}(jQuery,document,window),function(e){"use strict";function t(t,s,a){if(t.secondary&&-1!==t.secondary.split(" ").indexOf(s)){for(var r in t)if(r.length>9&&0===r.indexOf("secondary")){var n=t[r],i=r.substr(9);i=i.substr(0,1).toLowerCase()+i.substr(1),t[r]=t[i],t[i]=n}e(this).jmpress("reapply",e(a))}}e.jmpress("initStep",function(e,t){for(var s in t.data)0===s.indexOf("secondary")&&(t.stepData[s]=t.data[s])}),e.jmpress("beforeActive",function(s,a){t.call(a.jmpress,e(s).data("stepData"),"self",s);var r=e(s).parent();e(r).children(a.settings.stepSelector).each(function(s,r){var n=e(r).data("stepData");t.call(a.jmpress,n,"siblings",r)});for(var n=1;a.parents.length>n;n++)e(a.parents[n]).children(a.settings.stepSelector).each()}),e.jmpress("setInactive",function(s,a){function r(s,r){var n=e(r).data("stepData");t.call(a.jmpress,n,"grandchildren",r)}t.call(a.jmpress,e(s).data("stepData"),"self",s);
13
+ var n=e(s).parent();e(n).children(a.settings.stepSelector).each(function(s,r){var n=e(r).data("stepData");t.call(a.jmpress,n,"siblings",r)});for(var i=1;a.parents.length>i;i++)e(a.parents[i]).children(a.settings.stepSelector).each(r)})}(jQuery,document,window),function(e,t,s,a){"use strict";e.jmpress("defaults").duration={defaultValue:-1,defaultAction:"next",barSelector:a,barProperty:"width",barPropertyStart:"0",barPropertyEnd:"100%"},e.jmpress("initStep",function(e,t){t.stepData.duration=t.data.duration&&parseInt(t.data.duration,10),t.stepData.durationAction=t.data.durationAction}),e.jmpress("setInactive",function(t,s){var a=s.settings,r=a.duration,n=s.current;if(s.stepData.duration||r.defaultValue,n.durationTimeout){if(r.barSelector){var i={transitionProperty:r.barProperty,transitionDuration:"0",transitionDelay:"0",transitionTimingFunction:"linear"};i[r.barProperty]=r.barPropertyStart;var o=e(r.barSelector);e.jmpress("css",o,i),o.each(function(t,s){var a=e(s).next(),r=e(s).parent();e(s).detach(),a.length?a.insertBefore(s):r.append(s)})}clearTimeout(n.durationTimeout),delete n.durationTimeout}}),e.jmpress("setActive",function(t,s){var r=s.settings,n=r.duration,i=s.current,o=s.stepData.duration||n.defaultValue;if(o&&o>0){if(n.barSelector){var c={transitionProperty:n.barProperty,transitionDuration:o-2*r.transitionDuration/3-100+"ms",transitionDelay:2*r.transitionDuration/3+"ms",transitionTimingFunction:"linear"};c[n.barProperty]=n.barPropertyEnd,e.jmpress("css",e(n.barSelector),c)}var l=this;i.durationTimeout&&(clearTimeout(i.durationTimeout),i.durationTimeout=a),i.durationTimeout=setTimeout(function(){var t=s.stepData.durationAction||n.defaultAction;e(l).jmpress(t)},o)}})}(jQuery,document,window),function(e,t,s){"use strict";var a=e.jmpress,r="jmpress-presentation-";a("defaults").presentationMode={use:!0,url:"presentation-screen.html",notesUrl:!1,transferredValues:["userZoom","userTranslateX","userTranslateY"]},a("defaults").keyboard.keys[80]="presentationPopup",a("afterInit",function(t,a){var n=a.current;if(n.selectMessageListeners=[],a.settings.presentationMode.use){s.addEventListener("message",function(t){try{if("string"!=typeof t.data||0!==t.data.indexOf(r))return;var i=JSON.parse(t.data.slice(r.length));switch(i.type){case"select":e.each(a.settings.presentationMode.transferredValues,function(e,t){a.current[t]=i[t]}),/[a-z0-9\-]+/i.test(i.targetId)&&typeof i.substep in{number:1,undefined:1}?e(a.jmpress).jmpress("select",{step:"#"+i.targetId,substep:i.substep},i.reason):e.error("For security reasons the targetId must match /[a-z0-9\\-]+/i and substep must be a number.");break;case"listen":n.selectMessageListeners.push(t.source);break;case"ok":clearTimeout(n.presentationPopupTimeout);break;case"read":try{t.source.postMessage(r+JSON.stringify({type:"url",url:s.location.href,notesUrl:a.settings.presentationMode.notesUrl}),"*")}catch(o){e.error("Cannot post message to source: "+o)}break;default:throw"Unknown message type: "+i.type}}catch(o){e.error("Received message is malformed: "+o)}});try{s.parent&&s.parent!==s&&s.parent.postMessage(r+JSON.stringify({type:"afterInit"}),"*")}catch(i){e.error("Cannot post message to parent: "+i)}}}),a("afterDeinit",function(t,a){if(a.settings.presentationMode.use)try{s.parent&&s.parent!==s&&s.parent.postMessage(r+JSON.stringify({type:"afterDeinit"}),"*")}catch(n){e.error("Cannot post message to parent: "+n)}}),a("setActive",function(t,s){var a=e(s.delegatedFrom).attr("id"),n=s.substep,i=s.reason;e.each(s.current.selectMessageListeners,function(t,o){try{var c={type:"select",targetId:a,substep:n,reason:i};e.each(s.settings.presentationMode.transferredValues,function(e,t){c[t]=s.current[t]}),o.postMessage(r+JSON.stringify(c),"*")}catch(l){e.error("Cannot post message to listener: "+l)}})}),a("register","presentationPopup",function(){function t(){n.jmpress("current").presentationPopupTimeout=setTimeout(t,100);try{a.postMessage(r+JSON.stringify({type:"url",url:s.location.href,notesUrl:n.jmpress("settings").presentationMode.notesUrl}),"*")}catch(e){}}var a,n=e(this);n.jmpress("settings").presentationMode.use&&(a=s.open(e(this).jmpress("settings").presentationMode.url),n.jmpress("current").presentationPopupTimeout=setTimeout(t,100))})}(jQuery,document,window);
modules/shortcodes/js/main.js ADDED
@@ -0,0 +1,197 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ (function($){
2
+ var jmpressOpts = {
3
+ fullscreen : false,
4
+ hash : { use : false },
5
+ mouse : { clickSelects : false },
6
+ keyboard : { use : true },
7
+ animation : { transitionDuration : '1s' },
8
+ presentationMode : false,
9
+ stepSelector : '.step'
10
+ };
11
+
12
+ /**
13
+ * Presentation constructor
14
+ */
15
+ function Presentation (wrapper) {
16
+ var _self, size, duration, new_css, ie_regex, matches;
17
+
18
+ _self = this;
19
+
20
+ _self.wrapper = $(wrapper); // The wrapper for toggling fullscreen
21
+ _self.slideshow = $('.presentation', wrapper); // Holds the slides for jmpress
22
+ _self.navLeft = $('.nav-arrow-left', wrapper);
23
+ _self.navRight = $('.nav-arrow-right', wrapper);
24
+ _self.expandButton = $('.nav-fullscreen-button', wrapper);
25
+ _self.fullscreen = false;
26
+
27
+ // The wrapper is scaled to the contents' size so that its border wraps tightly
28
+ _self.wrapper.css({
29
+ width: _self.slideshow.width(),
30
+ height: _self.slideshow.height()
31
+ });
32
+
33
+ duration = _self.slideshow.attr('duration') || '1s';
34
+ jmpressOpts.animation.transitionDuration = duration;
35
+
36
+ // Set the opacity transition duration
37
+ // as it is delegated by css and not jmpress
38
+ duration = 'opacity ' + duration;
39
+ new_css = {
40
+ 'width' : _self.slideshow.width(),
41
+ 'height' : _self.slideshow.height(),
42
+ '-webkit-transition': duration,
43
+ '-moz-transition' : duration,
44
+ '-ms-transition' : duration,
45
+ '-o-transition' : duration,
46
+ 'transition' : duration
47
+ };
48
+
49
+ $('.step', _self.slideshow).each(function(i, step) {
50
+ $(step).css(new_css);
51
+ });
52
+
53
+ // Register resizing to window when fullscreen
54
+ $(window).resize(function() {
55
+ if ( _self.fullscreen )
56
+ _self.resizePresentation();
57
+ });
58
+
59
+ // Register the nav bars to move the slides
60
+ _self.navLeft.on('click', function(){
61
+ _self.slideshow.jmpress('prev');
62
+ });
63
+
64
+ _self.navRight.on('click', function(){
65
+ _self.slideshow.jmpress('next');
66
+ });
67
+
68
+ // Register toggling fullscreen except for IE 9 or lower
69
+ ie_regex = /MSIE\s(\d+)\.\d+/;
70
+ matches = ie_regex.exec(navigator.userAgent);
71
+
72
+ if ( matches && parseInt(matches[1]) < 10 ) {
73
+ _self.expandButton.remove();
74
+ _self.expandButton = null;
75
+ } else {
76
+ _self.expandButton.on('click', function() {
77
+ _self.setFullscreen( !_self.fullscreen );
78
+ });
79
+ }
80
+
81
+ // Register ESC key to exit fullscreen
82
+ $(window).on('keydown', function( event ) {
83
+ if ( event.which == 27 )
84
+ _self.setFullscreen( false );
85
+ });
86
+
87
+ // Start the presentation
88
+ _self.slideshow.jmpress(jmpressOpts);
89
+
90
+ // Make content visible and remove error message on jmpress success
91
+ if ( _self.slideshow.jmpress('initialized') ) {
92
+ _self.slideshow.css('display', '');
93
+ $('.not-supported-msg', _self.wrapper).remove();
94
+ }
95
+
96
+ // A bug in Firefox causes issues with the nav arrows appearing
97
+ // on hover in presentation mode. Explicitly disabling fullscreen
98
+ // on init seems to fix the issue
99
+ _self.setFullscreen( false );
100
+ }
101
+
102
+ $.extend( Presentation.prototype, {
103
+ resizePresentation: function () {
104
+ var scale, duration, settings, new_css, widthScale, heightScale;
105
+
106
+ // Set the animation duration to 0 during resizing
107
+ // so that there isn't an animation delay when scaling
108
+ // up the slide contents
109
+ settings = this.slideshow.jmpress('settings');
110
+ duration = settings.animation.transitionDuration;
111
+
112
+ settings.animation.transitionDuration = '0s';
113
+ this.slideshow.jmpress('reselect');
114
+
115
+ scale = 1;
116
+ new_css = {
117
+ top : 0,
118
+ left : 0,
119
+ zoom : 1
120
+ };
121
+
122
+ // Expand the presentation to fill the lesser of the max width or height
123
+ // This avoids content moving past the window for certain window sizes
124
+ if ( this.fullscreen ) {
125
+ widthScale = $(window).width() / this.slideshow.width();
126
+ heightScale = $(window).height() / this.slideshow.height();
127
+
128
+ scale = Math.min(widthScale, heightScale);
129
+
130
+ new_css.top = ( $(window).height() - (scale * this.slideshow.height()) ) / 2;
131
+ new_css.left = ( $(window).width() - (scale * this.slideshow.width() ) ) / 2;
132
+ }
133
+
134
+ // Firefox does not support the zoom property; IE does, but it does not work
135
+ // well like in webkit, so we manually transform and position the slideshow
136
+ if ( this.slideshow.css('-moz-transform') || this.slideshow.css('-ms-transform') ) {
137
+ // Firefox keeps the center of the element in place and expands outward
138
+ // so we must shift everything to compensate
139
+ new_css.top += (scale - 1) * this.slideshow.height() / 2;
140
+ new_css.left += (scale - 1) * this.slideshow.width() / 2;
141
+
142
+ scale = 'scale(' + scale + ')';
143
+
144
+ $.extend(new_css, {
145
+ '-moz-transform' : scale,
146
+ '-ms-transform' : scale,
147
+ 'transform' : scale,
148
+ });
149
+ } else {
150
+ // webkit scales everything with zoom so we need to offset the right amount
151
+ // so that the content is vertically centered after scaling effects
152
+ new_css.top /= scale;
153
+ new_css.left /= scale;
154
+ new_css.zoom = scale;
155
+ }
156
+
157
+ this.slideshow.css(new_css);
158
+
159
+ settings.animation.transitionDuration = duration;
160
+ this.slideshow.jmpress('reselect');
161
+ },
162
+
163
+ setFullscreen: function ( on ) {
164
+ this.fullscreen = on;
165
+
166
+ // Save the scroll positions before going into fullscreen mode
167
+ if ( on ) {
168
+ this.scrollVert = $(window).scrollTop();
169
+ this.scrollHoriz = $(window).scrollLeft();
170
+ }
171
+
172
+ $('html').toggleClass('presentation-global-fullscreen', on);
173
+ $('body').toggleClass('presentation-global-fullscreen', on);
174
+
175
+ this.wrapper.toggleClass('presentation-wrapper-fullscreen', on);
176
+
177
+ this.wrapper.parents().each(function(i, e){
178
+ $(e).toggleClass('presentation-wrapper-fullscreen-parent', on);
179
+ });
180
+
181
+ this.resizePresentation();
182
+
183
+ // Reset the scroll positions after exiting fullscreen mode
184
+ if ( !on ) {
185
+ $(window).scrollTop(this.scrollVert);
186
+ $(window).scrollLeft(this.scrollHoriz);
187
+ }
188
+ }
189
+ });
190
+
191
+ $( document ).ready( function(){
192
+ $('.presentation-wrapper').map(function() {
193
+ new Presentation(this);
194
+ });
195
+ });
196
+
197
+ })(jQuery);
modules/shortcodes/presentations.php ADDED
@@ -0,0 +1,382 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Plugin Name: Presentations
4
+ Plugin URI: http://automattic.com/wordpress-plugins/
5
+ Description: Presentations plugin based on the work done by <a href="http://darylkoop.com/">Daryl Koopersmith</a>. Powered by jmpress.js
6
+ Version: 0.2
7
+ Author: Automattic
8
+ Author URI: http://automattic.com/wordpress-plugins/
9
+
10
+ This program is free software; you can redistribute it and/or modify
11
+ it under the terms of the GNU General Public License as published by
12
+ the Free Software Foundation; either version 2 of the License, or
13
+ (at your option) any later version.
14
+
15
+ This program is distributed in the hope that it will be useful,
16
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
17
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
+ GNU General Public License for more details.
19
+
20
+ You should have received a copy of the GNU General Public License
21
+ along with this program; if not, write to the Free Software
22
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23
+ */
24
+
25
+
26
+ /**
27
+ * Known issues:
28
+ *
29
+ * - IE 7/8 are not supported by jmpress and presentations will not work
30
+ * - IE 9 will not animate transitions at all, though it's possible to at least
31
+ * switch between slides.
32
+ * - Infinite Scroll themes will not load presentations properly unless the post
33
+ * happens to be on the first loaded page. The permalink page will function
34
+ * properly, however.
35
+ * - Exiting fullscreen mode will not properly reset the scroll locations in Safari
36
+ */
37
+
38
+
39
+ /*
40
+ HOW TO: How the plugin settings are organized and which features are supported.
41
+
42
+ The entire presentation should be wrapped with a [presentation] shortcode, and every
43
+ individual slide should be wrapped with a [slide] shortcode. Any settings supported
44
+ by [slide] can be set into [presentation], which will apply that setting for the entire
45
+ presentation unless overridden by individual slides.
46
+
47
+ - [presentation] only settings:
48
+ - duration: transition durations, default is one second.
49
+ - height: content height, default is 400px
50
+ - width: content width, default is 550px
51
+
52
+ - [slide] settings:
53
+ - transition: specifies where the next slide will be placed relative
54
+ to the last one before it. Supported values are "up", "down"
55
+ "left", "right", or "none". Default value is "down".
56
+
57
+ - scale: scales the content relative to other slides, default value is one
58
+
59
+ - rotate: rotates the content by the specified degrees, default is zero
60
+
61
+ - fade: slides will fade in and out during transition. Values of "on" or
62
+ "true" will enable fading, while values of "no" or "false" will
63
+ disable it. Default value is "on"
64
+
65
+ - bgcolor: specifies a background color for the slides. Any CSS valid value
66
+ is permitted. Default color is transparent.
67
+
68
+ - bgimg: specifies an image url which will fill the background. Image is
69
+ set to fill the background 100% width and height
70
+ */
71
+
72
+ if ( ! class_exists( 'Presentations' ) ) :
73
+
74
+ class Presentations {
75
+
76
+ private $presentation_settings;
77
+ private $presentation_initialized;
78
+ private $scripts_and_style_included;
79
+
80
+ /**
81
+ * Constructor
82
+ */
83
+ function __construct() {
84
+ // Bail without 3.0.
85
+ if ( ! function_exists( '__return_false' ) )
86
+ return;
87
+
88
+ $this->presentation_initialized = false;
89
+ $this->scripts_and_style_included = false;
90
+
91
+ // Registers shortcodes
92
+ add_action( 'wp_head', array( &$this, 'add_scripts' ), 1 );
93
+
94
+ add_shortcode( 'presentation', array( &$this, 'presentation_shortcode' ) );
95
+ add_shortcode( 'slide', array( &$this, 'slide_shortcode' ) );
96
+ }
97
+
98
+ function add_scripts() {
99
+ $this->scripts_and_style_included = false;
100
+
101
+ if ( empty( $GLOBALS['posts'] ) || !is_array( $GLOBALS['posts'] ) ) {
102
+ return;
103
+ }
104
+
105
+ foreach ( $GLOBALS['posts'] as $p ) {
106
+ if ( false !== strpos( $p->post_content, '[presentation' ) ) {
107
+ $this->scripts_and_style_included = true;
108
+ break;
109
+ }
110
+ }
111
+
112
+ if ( ! $this->scripts_and_style_included )
113
+ return;
114
+
115
+ $plugin = plugin_dir_url( __FILE__ );
116
+ // Add CSS
117
+ wp_enqueue_style('presentations', $plugin . 'css/style.css');
118
+ // Add JavaScript
119
+ wp_enqueue_script('jquery');
120
+ wp_enqueue_script('jmpress',
121
+ $plugin . 'js/jmpress.min.js',
122
+ array('jquery'),
123
+ '0.4.5',
124
+ true);
125
+ wp_enqueue_script('presentations',
126
+ $plugin . 'js/main.js',
127
+ array('jquery', 'jmpress'),
128
+ false,
129
+ true);
130
+ }
131
+
132
+ function presentation_shortcode( $atts, $content='' ) {
133
+ // Mark that we've found a valid [presentation] shortcode
134
+ $this->presentation_initialized = true;
135
+
136
+ $atts = shortcode_atts( array(
137
+ 'duration' => '',
138
+ 'height' => '',
139
+ 'width' => '',
140
+ 'bgcolor' => '',
141
+ 'bgimg' => '',
142
+
143
+ // Settings
144
+ 'transition' => '',
145
+ 'scale' => '',
146
+ 'rotate' => '',
147
+ 'fade' => '',
148
+ ), $atts );
149
+
150
+ $this->presentation_settings = array(
151
+ 'transition' => 'down',
152
+ 'scale' => 1,
153
+ 'rotate' => 0,
154
+ 'fade' => 'on',
155
+ 'last' => array(
156
+ 'x' => 0,
157
+ 'y' => 0,
158
+ 'scale' => 1,
159
+ 'rotate' => 0,
160
+ ),
161
+ );
162
+
163
+ // Set the presentation-wide settings
164
+ if ( '' != trim( $atts['transition'] ) )
165
+ $this->presentation_settings['transition'] = $atts['transition'];
166
+
167
+ if ( '' != trim( $atts['scale'] ) )
168
+ $this->presentation_settings['scale'] = floatval( $atts['scale'] );
169
+
170
+ if ( '' != trim( $atts['rotate'] ) )
171
+ $this->presentation_settings['rotate'] = floatval( $atts['rotate'] );
172
+
173
+ if ( '' != trim( $atts['fade'] ) )
174
+ $this->presentation_settings['fade'] = $atts['fade'];
175
+
176
+ // Set any settings the slides don't care about
177
+ if ( '' != trim( $atts['duration'] ) )
178
+ $duration = floatval( $atts['duration'] ) . 's';
179
+ else
180
+ $duration = '1s';
181
+
182
+ // Set the presentation size as specified or with some nicely sized dimensions
183
+ if ( '' != trim( $atts['width'] ) )
184
+ $this->presentation_settings['width'] = intval( $atts['width'] );
185
+ else
186
+ $this->presentation_settings['width'] = 480;
187
+
188
+ if ( '' != trim( $atts['height'] ) )
189
+ $this->presentation_settings['height'] = intval( $atts['height'] );
190
+ else
191
+ $this->presentation_settings['height'] = 370;
192
+
193
+ // Hide the content by default in case the scripts fail
194
+ $style = 'display: none; width: ' . $this->presentation_settings['width'] . 'px; height: ' . $this->presentation_settings['height'] . 'px;';
195
+
196
+ // Check for background color XOR background image
197
+ // Use a white background if nothing specified
198
+ if ( preg_match( '/https?\:\/\/[^\'"\s]*/', $atts['bgimg'], $matches ) ) {
199
+ $style .= ' background-image: url("' . esc_url( $matches[0] ) . '");';
200
+ } else if ( '' != trim( $atts['bgcolor'] ) ) {
201
+ $style .= ' background-color: ' . esc_attr( $atts['bgcolor'] ) . ';';
202
+ } else {
203
+ $style .= ' background-color: #fff;';
204
+ }
205
+
206
+ // Not supported message style is inlined incase the style sheet doesn't get included
207
+ $out = "<section class='presentation-wrapper'>";
208
+ $out.= "<p class='not-supported-msg' style='display: inherit; padding: 25%; text-align: center;'>";
209
+ $out.= __( 'This slideshow could not be started. Try refreshing the page or viewing it in another browser.', 'jetpack' ) . '</p>';
210
+
211
+ // Bail out unless the scripts were added
212
+ if ( $this->scripts_and_style_included ) {
213
+ $out.= "<div class='presentation' duration='$duration' style='$style'>";
214
+ $out.= "<div class='nav-arrow-left'></div>";
215
+ $out.= "<div class='nav-arrow-right'></div>";
216
+ $out.= "<div class='nav-fullscreen-button'></div>";
217
+ $out.= do_shortcode( $content );
218
+ $out.= "</section>";
219
+ }
220
+
221
+ $out.= "</section>";
222
+
223
+ $this->presentation_initialized = false;
224
+ return $out;
225
+ }
226
+
227
+ function slide_shortcode( $atts, $content = '' ) {
228
+ // Bail out unless wrapped by a [presentation] shortcode
229
+ if ( ! $this->presentation_initialized )
230
+ return $content;
231
+
232
+ $atts = shortcode_atts( array(
233
+ 'transition' => '',
234
+ 'scale' => '',
235
+ 'rotate' => '',
236
+ 'fade' => '',
237
+ 'bgcolor' => '',
238
+ 'bgimg' => '',
239
+ ), $atts );
240
+
241
+ // Determine positioning based on transition
242
+ if ( '' == trim( $atts['transition'] ) )
243
+ $atts['transition'] = $this->presentation_settings['transition'];
244
+
245
+ // Setting the content scale
246
+ if ( '' == trim( $atts['scale'] ) )
247
+ $atts['scale'] = $this->presentation_settings['scale'];
248
+
249
+ if( '' == trim( $atts['scale'] ) )
250
+ $scale = 1;
251
+ else
252
+ $scale = floatval( $atts['scale'] );
253
+
254
+ if ( $scale < 0 )
255
+ $scale *= -1;
256
+
257
+ // Setting the content rotation
258
+ if ( '' == trim( $atts['rotate'] ) )
259
+ $atts['rotate'] = $this->presentation_settings['rotate'];
260
+
261
+ if( '' == trim( $atts['rotate'] ) )
262
+ $rotate = 0;
263
+ else
264
+ $rotate = floatval( $atts['rotate'] );
265
+
266
+ // Setting if the content should fade
267
+ if ( '' == trim( $atts['fade'] ) )
268
+ $atts['fade'] = $this->presentation_settings['fade'];
269
+
270
+ if ( 'on' == $atts['fade'] || 'true' == $atts['fade'] )
271
+ $fade = 'fade';
272
+ else
273
+ $fade = '';
274
+
275
+ $coords = $this->get_coords( array(
276
+ 'transition' => $atts['transition'],
277
+ 'scale' => $scale,
278
+ 'rotate' => $rotate,
279
+ ));
280
+
281
+ $x = $coords['x'];
282
+ $y = $coords['y'];
283
+
284
+ // Check for background color XOR background image
285
+ // Use a white background if nothing specified
286
+ if ( preg_match( '/https?\:\/\/[^\'"\s]*/', $atts['bgimg'], $matches ) ) {
287
+ $style = 'background-image: url("' . esc_url( $matches[0] ) . '");';
288
+ } else if ( '' != trim( $atts['bgcolor'] ) ) {
289
+ $style = 'background-color: ' . esc_attr( $atts['bgcolor'] ) . ';';
290
+ } else {
291
+ $style = '';
292
+ }
293
+
294
+ // Put everything together and let jmpress do the magic!
295
+ $out = "<div class='step $fade' data-x='$x' data-y='$y' data-scale='$scale' data-rotate='$rotate' style='$style'>";
296
+ $out.= "<div class='slide-content'>";
297
+ $out.= do_shortcode( $content );
298
+ $out.= "</div></div>";
299
+ return $out;
300
+ }
301
+
302
+ /**
303
+ * Determines the position of the next slide based on the position and scaling of the previous slide.
304
+ *
305
+ * @param array $args: an array with the following key-value pairs
306
+ * string $transition: the transition name, "up", "down", "left", or "right"
307
+ * float $scale: the scale of the next slide (used to determine the position of the slide after that)
308
+ *
309
+ * @return array with the 'x' and 'y' coordinates of the slide
310
+ */
311
+ function get_coords( $args ) {
312
+ if ( 0 == $args['scale'] )
313
+ $args['scale'] = 1;
314
+
315
+ $width = $this->presentation_settings['width'];
316
+ $height = $this->presentation_settings['height'];
317
+ $last = $this->presentation_settings['last'];
318
+ $scale = $last['scale'];
319
+
320
+ $next = array(
321
+ 'x' => $last['x'],
322
+ 'y' => $last['y'],
323
+ 'scale' => $args['scale'],
324
+ 'rotate' => $args['rotate'],
325
+ );
326
+
327
+ // All angles are measured from the vertical axis, so everything is backwards!
328
+ $diagAngle = atan2( $width, $height );
329
+ $diagonal = sqrt( pow( $width, 2 ) + pow( $height, 2 ) );
330
+
331
+ // We offset the angles by the angle formed by the diagonal so that
332
+ // we can multiply the sines directly against the diagonal length
333
+ $theta = deg2rad( $last['rotate'] ) - $diagAngle;
334
+ $phi = deg2rad( $next['rotate'] ) - $diagAngle;
335
+
336
+ // We start by displacing by the slide dimensions
337
+ $totalHorizDisp = $width * $scale;
338
+ $totalVertDisp = $height * $scale;
339
+
340
+ // If the previous slide was rotated, we add the incremental offset from the rotation
341
+ // Namely the difference between the regular dimension (no rotation) and the component
342
+ // of the diagonal for that angle
343
+ $totalHorizDisp += ( ( ( abs( sin( $theta ) ) * $diagonal) - $width ) / 2) * $scale;
344
+ $totalVertDisp += ( ( ( abs( cos( $theta ) ) * $diagonal) - $height) / 2) * $scale;
345
+
346
+ // Similarly, we check if the current slide has been rotated and add whatever additional
347
+ // offset has been added. This is so that two rotated corners don't clash with each other.
348
+ // Note: we are checking the raw angle relative to the vertical axis, NOT the diagonal angle.
349
+ if ( $next['rotate'] % 180 != 0 ){
350
+ $totalHorizDisp += ( abs( ( sin( $phi ) * $diagonal ) - $width ) / 2) * $next['scale'];
351
+ $totalVertDisp += ( abs( ( cos( $phi ) * $diagonal ) - $height ) / 2) * $next['scale'];
352
+ }
353
+
354
+ switch ( trim( $args['transition'] ) ) {
355
+ case 'none':
356
+ break;
357
+
358
+ case 'left':
359
+ $next['x'] -= $totalHorizDisp;
360
+ break;
361
+
362
+ case 'right':
363
+ $next['x'] += $totalHorizDisp;
364
+ break;
365
+
366
+ case 'up':
367
+ $next['y'] -= $totalVertDisp;
368
+ break;
369
+
370
+ case 'down':
371
+ default:
372
+ $next['y'] += $totalVertDisp;
373
+ break;
374
+ }
375
+
376
+ $this->presentation_settings['last'] = $next;
377
+ return $next;
378
+ }
379
+ }
380
+
381
+ $GLOBALS['presentations'] = new Presentations();
382
+ endif;
modules/shortcodes/twitter-timeline.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ add_shortcode( 'twitter-timeline', 'twitter_timeline_shortcode' );
3
+
4
+ function twitter_timeline_shortcode( $attr ) {
5
+
6
+ $default_atts = array(
7
+ 'username' => '',
8
+ 'id' => '',
9
+ 'height' => 282,
10
+ 'width' => 450,
11
+
12
+ );
13
+
14
+ $attr = shortcode_atts( $default_atts, $attr );
15
+
16
+ if ( $attr['username'] != preg_replace( '/[^A-Za-z0-9_]+/', '', $attr['username'] ) )
17
+ return '<!--' . __( 'Invalid username', 'jetpack' ) . '-->';
18
+
19
+ if ( ! is_numeric( $attr['id'] ) )
20
+ return '<!--' . __( 'Invalid id', 'jetpack' ) . '-->';
21
+
22
+ $tweets_by = sprintf( __( 'Tweets by @%s', 'jetpack' ), $attr['username'] );
23
+ $output = '<a class="twitter-timeline" width="' . (int)$attr['width'] . '" height="' . (int)$attr['width'] . '" href="' . esc_url( 'https://twitter.com/'. $attr['username'] ) . '" data-widget-id="' . (int)$attr['id'] . '">' . esc_html( $tweets_by ) . '</a>';
24
+ add_action( 'wp_footer', 'twitter_timeline_js' );
25
+
26
+ return $output;
27
+ }
28
+
29
+ function twitter_timeline_js() {
30
+ echo '<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script>';
31
+ }
modules/shortcodes/vine.php ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Vine shortcode
4
+ */
5
+
6
+ /**
7
+ * Vine embed code:
8
+ * <iframe class="vine-embed" src="https://vine.co/v/bjHh0zHdgZT" width="600" height="600" frameborder="0"></iframe>
9
+ * <script async src="//platform.vine.co/static/scripts/embed.js" charset="utf-8"></script>
10
+ *
11
+ * URL example:
12
+ * https://vine.co/v/bjHh0zHdgZT/
13
+ *
14
+ * Embed shortcode examples:
15
+ * [embed]https://vine.co/v/bjHh0zHdgZT[/embed]
16
+ * [embed width="300"]https://vine.co/v/bjHh0zHdgZT[/embed]
17
+ * [embed type="postcard" width="300"]https://vine.co/v/bjHh0zHdgZT[/embed]
18
+ **/
19
+
20
+ function vine_embed_video( $matches, $attr, $url, $rawattr ) {
21
+ static $vine_flag_embedded_script;
22
+
23
+ $max_height = 300;
24
+ $type = 'simple';
25
+
26
+ // Only allow 'postcard' or 'simple' types
27
+ if ( isset( $rawattr['type'] ) && $rawattr['type'] === 'postcard' )
28
+ $type = 'postcard';
29
+
30
+ $vine_size = Jetpack::get_content_width();
31
+
32
+ // If the user enters a value for width or height, we ignore the Jetpack::get_content_width()
33
+ if ( isset( $rawattr['width'] ) || isset( $rawattr['height'] ) ) {
34
+ // 300 is the minimum size that Vine provides for embeds. Lower than that, the postcard embeds looks weird.
35
+ $vine_size = max( $max_height, min( $attr['width'], $attr['height'] ) );
36
+ }
37
+
38
+ if ( empty( $vine_size ) ) {
39
+ $vine_size = $max_height;
40
+ }
41
+
42
+ $url = 'https://vine.co/v/' . $matches[1] . '/embed/' . $type;
43
+ $vine_html = sprintf( '<iframe class="vine-embed" src="%s" width="%s" height="%s" frameborder="0"></iframe>', esc_url( $url ), (int) $vine_size, (int) $vine_size );
44
+
45
+ if ( $vine_flag_embedded_script !== true ) {
46
+ $vine_html .= '<script async src="//platform.vine.co/static/scripts/embed.js" charset="utf-8"></script>';
47
+ $vine_flag_embedded_script = true;
48
+ }
49
+
50
+ return $vine_html;
51
+ }
52
+ wp_embed_register_handler( 'jetpack_vine', '#https?://vine.co/v/([a-z0-9]+).*#i', 'vine_embed_video' );
53
+
54
+ function vine_shortcode( $atts ) {
55
+ global $wp_embed;
56
+
57
+ if ( empty( $atts['url'] ) )
58
+ return '';
59
+
60
+ if ( ! preg_match( '#https?://vine.co/v/([a-z0-9]+).*#i', $atts['url'] ) )
61
+ return '';
62
+
63
+ return $wp_embed->shortcode( $atts, $atts['url'] );
64
+ }
65
+ add_shortcode( 'vine', 'vine_shortcode' );
modules/shortlinks.php CHANGED
@@ -5,6 +5,7 @@
5
  * Sort Order: 10
6
  * First Introduced: 1.1
7
  * Requires Connection: Yes
 
8
  */
9
 
10
  add_filter( 'get_shortlink', 'wpme_get_shortlink_handler', 1, 4 );
5
  * Sort Order: 10
6
  * First Introduced: 1.1
7
  * Requires Connection: Yes
8
+ * Auto Activate: Yes
9
  */
10
 
11
  add_filter( 'get_shortlink', 'wpme_get_shortlink_handler', 1, 4 );
modules/stats.php CHANGED
@@ -5,6 +5,7 @@
5
  * Sort Order: 1
6
  * First Introduced: 1.1
7
  * Requires Connection: Yes
 
8
  */
9
 
10
  if ( defined( 'STATS_VERSION' ) ) {
5
  * Sort Order: 1
6
  * First Introduced: 1.1
7
  * Requires Connection: Yes
8
+ * Auto Activate: Yes
9
  */
10
 
11
  if ( defined( 'STATS_VERSION' ) ) {
modules/subscriptions.php CHANGED
@@ -5,6 +5,7 @@
5
  * Sort Order: 3
6
  * First Introduced: 1.2
7
  * Requires Connection: Yes
 
8
  */
9
 
10
  add_action( 'jetpack_modules_loaded', 'jetpack_subscriptions_load' );
@@ -82,7 +83,9 @@ class Jetpack_Subscriptions {
82
  return false;
83
  }
84
 
85
- return 'publish' === $post->post_status && strlen( (string) $post->post_password ) < 1;
 
 
86
  }
87
 
88
  /**
@@ -280,7 +283,7 @@ class Jetpack_Subscriptions {
280
  * unknown : strange error. Jetpack servers at WordPress.com returned something malformed.
281
  * unknown_status : strange error. Jetpack servers at WordPress.com returned something I didn't understand.
282
  */
283
- function subscribe( $email, $post_ids = 0, $async = true ) {
284
  if ( !is_email( $email ) ) {
285
  return new Jetpack_Error( 'invalid_email' );
286
  }
@@ -299,9 +302,9 @@ class Jetpack_Subscriptions {
299
  }
300
 
301
  if ( $async ) {
302
- Jetpack::xmlrpc_async_call( 'jetpack.subscribeToSite', $email, $post_id );
303
  } else {
304
- $xml->addCall( 'jetpack.subscribeToSite', $email, $post_id );
305
  }
306
  }
307
 
@@ -383,7 +386,17 @@ class Jetpack_Subscriptions {
383
  $redirect_fragment = 'subscribe-blog';
384
  }
385
 
386
- $subscribe = Jetpack_Subscriptions::subscribe( $_REQUEST['email'], 0, false );
 
 
 
 
 
 
 
 
 
 
387
 
388
  if ( is_wp_error( $subscribe ) ) {
389
  $error = $subscribe->get_error_code();
@@ -484,7 +497,17 @@ class Jetpack_Subscriptions {
484
  if ( isset( $_REQUEST['subscribe_blog'] ) )
485
  $post_ids[] = 0;
486
 
487
- Jetpack_Subscriptions::subscribe( $comment->comment_author_email, $post_ids );
 
 
 
 
 
 
 
 
 
 
488
  }
489
 
490
  /**
@@ -527,10 +550,7 @@ class Jetpack_Subscriptions_Widget extends WP_Widget {
527
  function widget( $args, $instance ) {
528
  global $current_user;
529
 
530
- $source = 'widget';
531
-
532
- extract( $args );
533
-
534
  $instance = wp_parse_args( (array) $instance, $this->defaults() );
535
  $title = isset( $instance['title'] ) ? stripslashes( $instance['title'] ) : '';
536
  $subscribe_text = isset( $instance['subscribe_text'] ) ? stripslashes( $instance['subscribe_text'] ) : '';
@@ -593,9 +613,9 @@ class Jetpack_Subscriptions_Widget extends WP_Widget {
593
  <input type="hidden" name="source" value="<?php echo esc_url( $referer ); ?>" />
594
  <input type="hidden" name="sub-type" value="<?php echo esc_attr( $source ); ?>" />
595
  <input type="hidden" name="redirect_fragment" value="<?php echo esc_attr( $widget_id ); ?>" />
596
- <?php
597
  if ( is_user_logged_in() ) {
598
- wp_nonce_field( 'blogsub_subscribe_'. get_current_blog_id(), '_wpnonce', false );
599
  }
600
  ?>
601
  <input type="submit" value="<?php echo esc_attr( $subscribe_button ); ?>" name="jetpack_subscriptions_widget" />
5
  * Sort Order: 3
6
  * First Introduced: 1.2
7
  * Requires Connection: Yes
8
+ * Auto Activate: Yes
9
  */
10
 
11
  add_action( 'jetpack_modules_loaded', 'jetpack_subscriptions_load' );
83
  return false;
84
  }
85
 
86
+ if ( 'publish' === $post->post_status && strlen( (string) $post->post_password ) < 1 ) {
87
+ return apply_filters( 'jetpack_is_post_mailable', true );
88
+ }
89
  }
90
 
91
  /**
283
  * unknown : strange error. Jetpack servers at WordPress.com returned something malformed.
284
  * unknown_status : strange error. Jetpack servers at WordPress.com returned something I didn't understand.
285
  */
286
+ function subscribe( $email, $post_ids = 0, $async = true, $extra_data = array() ) {
287
  if ( !is_email( $email ) ) {
288
  return new Jetpack_Error( 'invalid_email' );
289
  }
302
  }
303
 
304
  if ( $async ) {
305
+ Jetpack::xmlrpc_async_call( 'jetpack.subscribeToSite', $email, $post_id, serialize( $extra_data ) );
306
  } else {
307
+ $xml->addCall( 'jetpack.subscribeToSite', $email, $post_id, serialize( $extra_data) );
308
  }
309
  }
310
 
386
  $redirect_fragment = 'subscribe-blog';
387
  }
388
 
389
+ $subscribe = Jetpack_Subscriptions::subscribe(
390
+ $_REQUEST['email'],
391
+ 0,
392
+ false,
393
+ array(
394
+ 'source' => 'widget',
395
+ 'widget-in-use' => is_active_widget( false, false, 'blog_subscription', true ) ? 'yes' : 'no',
396
+ 'comment_status' => '',
397
+ 'server_data' => $_SERVER,
398
+ )
399
+ );
400
 
401
  if ( is_wp_error( $subscribe ) ) {
402
  $error = $subscribe->get_error_code();
497
  if ( isset( $_REQUEST['subscribe_blog'] ) )
498
  $post_ids[] = 0;
499
 
500
+ Jetpack_Subscriptions::subscribe(
501
+ $comment->comment_author_email,
502
+ $post_ids,
503
+ true,
504
+ array(
505
+ 'source' => 'comment-form',
506
+ 'widget-in-use' => is_active_widget( false, false, 'blog_subscription', true ) ? 'yes' : 'no',
507
+ 'comment_status' => $approved,
508
+ 'server_data' => $_SERVER,
509
+ )
510
+ );
511
  }
512
 
513
  /**
550
  function widget( $args, $instance ) {
551
  global $current_user;
552
 
553
+ $source = 'widget';
 
 
 
554
  $instance = wp_parse_args( (array) $instance, $this->defaults() );
555
  $title = isset( $instance['title'] ) ? stripslashes( $instance['title'] ) : '';
556
  $subscribe_text = isset( $instance['subscribe_text'] ) ? stripslashes( $instance['subscribe_text'] ) : '';
613
  <input type="hidden" name="source" value="<?php echo esc_url( $referer ); ?>" />
614
  <input type="hidden" name="sub-type" value="<?php echo esc_attr( $source ); ?>" />
615
  <input type="hidden" name="redirect_fragment" value="<?php echo esc_attr( $widget_id ); ?>" />
616
+ <?php
617
  if ( is_user_logged_in() ) {
618
+ wp_nonce_field( 'blogsub_subscribe_'. get_current_blog_id(), '_wpnonce', false );
619
  }
620
  ?>
621
  <input type="submit" value="<?php echo esc_attr( $subscribe_button ); ?>" name="jetpack_subscriptions_widget" />
modules/theme-tools.php ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * Load code specific to themes or theme tools
4
+ */
5
+
6
+ /**
7
+ * INFINITE SCROLL
8
+ */
9
+
10
+ /**
11
+ * Load theme's infinite scroll annotation file, if present in the IS plugin.
12
+ * The `setup_theme` action is used because the annotation files should be using `after_setup_theme` to register support for IS.
13
+ *
14
+ * As released in Jetpack 2.0, a child theme's parent wasn't checked for in the plugin's bundled support, hence the convoluted way the parent is checked for now.
15
+ *
16
+ * @uses is_admin, wp_get_theme, get_theme, get_current_theme, apply_filters
17
+ * @action setup_theme
18
+ * @return null
19
+ */
20
+ function jetpack_load_infinite_scroll_annotation() {
21
+ if ( is_admin() && isset( $_GET['page'] ) && 'jetpack' == $_GET['page'] ) {
22
+ $theme = function_exists( 'wp_get_theme' ) ? wp_get_theme() : get_theme( get_current_theme() );
23
+
24
+ if ( ! is_a( $theme, 'WP_Theme' ) && ! is_array( $theme ) )
25
+ return;
26
+
27
+ $customization_file = apply_filters( 'infinite_scroll_customization_file', dirname( __FILE__ ) . "/infinite-scroll/themes/{$theme['Stylesheet']}.php", $theme['Stylesheet'] );
28
+
29
+ if ( is_readable( $customization_file ) ) {
30
+ require_once( $customization_file );
31
+ }
32
+ elseif ( ! empty( $theme['Template'] ) ) {
33
+ $customization_file = dirname( __FILE__ ) . "/infinite-scroll/themes/{$theme['Template']}.php";
34
+
35
+ if ( is_readable( $customization_file ) )
36
+ require_once( $customization_file );
37
+ }
38
+ }
39
+ }
40
+ add_action( 'setup_theme', 'jetpack_load_infinite_scroll_annotation' );
41
+
42
+ /**
43
+ * Prevent IS from being activated if theme doesn't support it
44
+ *
45
+ * @param bool $can_activate
46
+ * @filter jetpack_can_activate_infinite-scroll
47
+ * @return bool
48
+ */
49
+ function jetpack_can_activate_infinite_scroll( $can_activate ) {
50
+ return (bool) current_theme_supports( 'infinite-scroll' );
51
+ }
52
+ add_filter( 'jetpack_can_activate_infinite-scroll', 'jetpack_can_activate_infinite_scroll' );
53
+
54
+ require_once( dirname( __FILE__ ) . '/featured-content/featured-content.php' );
55
+
56
+ require_once( dirname( __FILE__ ) . '/social-links.php' );
57
+
58
+ // Custom Post Types - we don't want a module card for these (yet)
59
+ require_once( dirname( __FILE__ ) . '/custom-post-types/comics.php' );
60
+ require_once( dirname( __FILE__ ) . '/custom-post-types/testimonial.php' );
61
+
62
+ require_once( dirname( __FILE__ ) . '/random-redirect.php' );
modules/tiled-gallery.php CHANGED
@@ -5,6 +5,7 @@
5
  * Module Description: Create elegant magazine-style mosaic layouts for your photos without using an external graphic editor.
6
  * First Introduced: 2.1
7
  * Requires Connection: Yes
 
8
  */
9
 
10
  function jetpack_load_tiled_gallery() {
5
  * Module Description: Create elegant magazine-style mosaic layouts for your photos without using an external graphic editor.
6
  * First Introduced: 2.1
7
  * Requires Connection: Yes
8
+ * Auto Activate: No
9
  */
10
 
11
  function jetpack_load_tiled_gallery() {
modules/tiled-gallery/tiled-gallery.php CHANGED
@@ -59,6 +59,11 @@ class Jetpack_Tiled_Gallery {
59
  foreach ( $_attachments as $key => $val ) {
60
  $attachments[$val->ID] = $_attachments[$key];
61
  }
 
 
 
 
 
62
  } elseif ( !empty( $exclude ) ) {
63
  $exclude = preg_replace( '/[^0-9,]+/', '', $exclude );
64
  $attachments = get_children( array('post_parent' => $id, 'exclude' => $exclude, 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => $order, 'orderby' => $orderby) );
59
  foreach ( $_attachments as $key => $val ) {
60
  $attachments[$val->ID] = $_attachments[$key];
61
  }
62
+ } elseif ( 0 == $id ) {
63
+ // Should NEVER Happen but infinite_scroll_load_other_plugins_scripts means it does
64
+ // Querying with post_parent == 0 can generate stupidly memcache sets on sites with 10000's of unattached attachments as get_children puts every post in the cache.
65
+ // TODO Fix this properly
66
+ $attachments = array();
67
  } elseif ( !empty( $exclude ) ) {
68
  $exclude = preg_replace( '/[^0-9,]+/', '', $exclude );
69
  $attachments = get_children( array('post_parent' => $id, 'exclude' => $exclude, 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => $order, 'orderby' => $orderby) );
modules/vaultpress.php CHANGED
@@ -7,6 +7,7 @@
7
  * Deactivate: false
8
  * Free: false
9
  * Requires Connection: Yes
 
10
  */
11
 
12
  add_action( 'jetpack_modules_loaded', 'vaultpress_jetpack_stub' );
7
  * Deactivate: false
8
  * Free: false
9
  * Requires Connection: Yes
10
+ * Auto Activate: Yes
11
  */
12
 
13
  add_action( 'jetpack_modules_loaded', 'vaultpress_jetpack_stub' );
modules/widget-visibility.php ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Module Name: Widget Visibility
5
+ * Module Description: Control what pages your widgets appear on.
6
+ * First Introduced: 2.4
7
+ * Requires Connection: No
8
+ * Auto Activate: Yes
9
+ */
10
+
11
+ include dirname( __FILE__ ) . "/widget-visibility/widget-conditions.php";
modules/widget-visibility/widget-conditions.php ADDED
@@ -0,0 +1,379 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+
4
+ /**
5
+ * Hide or show widgets conditionally.
6
+ */
7
+
8
+ class Jetpack_Widget_Conditions {
9
+ public static function init() {
10
+ if ( is_admin() ) {
11
+ add_action( 'sidebar_admin_setup', array( __CLASS__, 'widget_admin_setup' ) );
12
+ add_filter( 'widget_update_callback', array( __CLASS__, 'widget_update' ), 10, 3 );
13
+ add_action( 'in_widget_form', array( __CLASS__, 'widget_conditions_admin' ), 10, 3 );
14
+ add_action( 'wp_ajax_widget_conditions_options', array( __CLASS__, 'widget_conditions_options' ) );
15
+ }
16
+ else {
17
+ add_action( 'widget_display_callback', array( __CLASS__, 'filter_widget' ) );
18
+ add_action( 'sidebars_widgets', array( __CLASS__, 'sidebars_widgets' ) );
19
+ }
20
+ }
21
+
22
+ public static function widget_admin_setup() {
23
+ wp_enqueue_style( 'widget-conditions', plugins_url( 'widget-conditions/widget-conditions.css', __FILE__ ) );
24
+ wp_enqueue_script( 'widget-conditions', plugins_url( 'widget-conditions/widget-conditions.js', __FILE__ ), array( 'jquery', 'jquery-ui-core' ), 20130129, true );
25
+ }
26
+
27
+ /**
28
+ * Provided a second level of granularity for widget conditions.
29
+ */
30
+ public static function widget_conditions_options_echo( $major = '', $minor = '' ) {
31
+ switch ( $major ) {
32
+ case 'category':
33
+ ?>
34
+ <option value=""><?php _e( 'All category pages', 'jetpack' ); ?></option>
35
+ <?php
36
+
37
+ $categories = get_categories( array( 'number' => 1000, 'orderby' => 'count', 'order' => 'DESC' ) );
38
+ usort( $categories, array( __CLASS__, 'strcasecmp_name' ) );
39
+
40
+ foreach ( $categories as $category ) {
41
+ ?>
42
+ <option value="<?php echo esc_attr( $category->term_id ); ?>" <?php selected( $category->term_id, $minor ); ?>><?php echo esc_html( $category->name ); ?></option>
43
+ <?php
44
+ }
45
+ break;
46
+ case 'author':
47
+ ?>
48
+ <option value=""><?php _e( 'All author pages', 'jetpack' ); ?></option>
49
+ <?php
50
+
51
+ foreach ( get_users( array( 'orderby' => 'name', 'exclude_admin' => true ) ) as $author ) {
52
+ ?>
53
+ <option value="<?php echo esc_attr( $author->ID ); ?>" <?php selected( $author->ID, $minor ); ?>><?php echo esc_html( $author->display_name ); ?></option>
54
+ <?php
55
+ }
56
+ break;
57
+ case 'tag':
58
+ ?>
59
+ <option value=""><?php _e( 'All tag pages', 'jetpack' ); ?></option>
60
+ <?php
61
+
62
+ $tags = get_tags( array( 'number' => 1000, 'orderby' => 'count', 'order' => 'DESC' ) );
63
+ usort( $tags, array( __CLASS__, 'strcasecmp_name' ) );
64
+
65
+ foreach ( $tags as $tag ) {
66
+ ?>
67
+ <option value="<?php echo esc_attr($tag->term_id ); ?>" <?php selected( $tag->term_id, $minor ); ?>><?php echo esc_html( $tag->name ); ?></option>
68
+ <?php
69
+ }
70
+ break;
71
+ case 'date':
72
+ ?>
73
+ <option value="" <?php selected( '', $minor ); ?>><?php _e( 'All date archives', 'jetpack' ); ?></option>
74
+ <option value="day"<?php selected( 'day', $minor ); ?>><?php _e( 'Daily archives', 'jetpack' ); ?></option>
75
+ <option value="month"<?php selected( 'month', $minor ); ?>><?php _e( 'Monthly archives', 'jetpack' ); ?></option>
76
+ <option value="year"<?php selected( 'year', $minor ); ?>><?php _e( 'Yearly archives', 'jetpack' ); ?></option>
77
+ <?php
78
+ break;
79
+ case 'page':
80
+ // Previously hardcoded post type options.
81
+ if ( ! $minor )
82
+ $minor = 'post_type-page';
83
+ else if ( 'post' == $minor )
84
+ $minor = 'post_type-post';
85
+
86
+ ?>
87
+ <option value="front" <?php selected( 'front', $minor ); ?>><?php _e( 'Front page', 'jetpack' ); ?></option>
88
+ <option value="posts" <?php selected( 'posts', $minor ); ?>><?php _e( 'Posts page', 'jetpack' ); ?></option>
89
+ <option value="404" <?php selected( '404', $minor ); ?>><?php _e( '404 error page', 'jetpack' ); ?></option>
90
+ <option value="search" <?php selected( 'search', $minor ); ?>><?php _e( 'Search results', 'jetpack' ); ?></option>
91
+ <optgroup label="<?php esc_attr_e( 'Post type:', 'jetpack' ); ?>">
92
+ <?php
93
+
94
+ $post_types = get_post_types( array( 'public' => true ), 'objects' );
95
+
96
+ foreach ( $post_types as $post_type ) {
97
+ ?>
98
+ <option value="<?php echo esc_attr( 'post_type-' . $post_type->name ); ?>" <?php selected( 'post_type-' . $post_type->name, $minor ); ?>><?php echo esc_html( $post_type->labels->singular_name ); ?></option>
99
+ <?php
100
+ }
101
+
102
+ ?>
103
+ </optgroup>
104
+ <optgroup label="<?php esc_attr_e( 'Static page:', 'jetpack' ); ?>">
105
+ <?php
106
+
107
+ echo str_replace( ' value="' . esc_attr( $minor ) . '"', ' value="' . esc_attr( $minor ) . '" selected="selected"', preg_replace( '/<\/?select[^>]*?>/i', '', wp_dropdown_pages( array( 'echo' => false ) ) ) );
108
+
109
+ ?>
110
+ </optgroup>
111
+ <?php
112
+ break;
113
+ }
114
+ }
115
+
116
+ /**
117
+ * This is the AJAX endpoint for the second level of conditions.
118
+ */
119
+ public static function widget_conditions_options() {
120
+ self::widget_conditions_options_echo( $_REQUEST['major'], isset( $_REQUEST['minor'] ) ? $_REQUEST['minor'] : '' );
121
+ die;
122
+ }
123
+
124
+ /**
125
+ * Add the widget conditions to each widget in the admin.
126
+ *
127
+ * @param $widget unused.
128
+ * @param $return unused.
129
+ * @param array $instance The widget settings.
130
+ */
131
+ public static function widget_conditions_admin( $widget, $return, $instance ) {
132
+ $conditions = array();
133
+
134
+ if ( isset( $instance['conditions'] ) )
135
+ $conditions = $instance['conditions'];
136
+
137
+ if ( ! isset( $conditions['action'] ) )
138
+ $conditions['action'] = 'show';
139
+
140
+ if ( empty( $conditions['rules'] ) )
141
+ $conditions['rules'][] = array( 'major' => '', 'minor' => '' );
142
+
143
+ ?>
144
+ <div class="widget-conditional <?php if ( empty( $_POST['widget-conditions-visible'] ) || $_POST['widget-conditions-visible'] == '0' ) { ?>widget-conditional-hide<?php } ?>">
145
+ <input type="hidden" name="widget-conditions-visible" value="<?php if ( isset( $_POST['widget-conditions-visible'] ) ) { echo esc_attr( $_POST['widget-conditions-visible'] ); } else { ?>0<?php } ?>" />
146
+ <?php if ( ! isset( $_POST['widget-conditions-visible'] ) ) { ?><a href="#" class="button display-options"><?php _e( 'Visibility', 'jetpack' ); ?></a><?php } ?>
147
+ <div class="widget-conditional-inner">
148
+ <div class="condition-top">
149
+ <?php printf( _x( '%s if:', 'placeholder: dropdown menu to select widget visibility; hide if or show if', 'jetpack' ), '<select name="conditions[action]"><option value="show" ' . selected( $conditions['action'], 'show', false ) . '>' . esc_html_x( 'Show', 'Used in the "%s if:" translation for the widget visibility dropdown', 'jetpack' ) . '</option><option value="hide" ' . selected( $conditions['action'], 'hide', false ) . '>' . esc_html_x( 'Hide', 'Used in the "%s if:" translation for the widget visibility dropdown', 'jetpack' ) . '</option></select>' ); ?>
150
+ </div><!-- .condition-top -->
151
+
152
+ <div class="conditions">
153
+ <?php
154
+
155
+ foreach ( $conditions['rules'] as $rule ) {
156
+ ?>
157
+ <div class="condition">
158
+ <div class="alignleft">
159
+ <select class="conditions-rule-major" name="conditions[rules_major][]">
160
+ <option value="" <?php selected( "", $rule['major'] ); ?>><?php echo esc_html_x( '-- Select --', 'Used as the default option in a dropdown list', 'jetpack' ); ?></option>
161
+ <option value="category" <?php selected( "category", $rule['major'] ); ?>><?php esc_html_e( 'Category', 'jetpack' ); ?></option>
162
+ <option value="author" <?php selected( "author", $rule['major'] ); ?>><?php echo esc_html_x( 'Author', 'Noun, as in: "The author of this post is..."', 'jetpack' ); ?></option>
163
+ <option value="tag" <?php selected( "tag", $rule['major'] ); ?>><?php echo esc_html_x( 'Tag', 'Noun, as in: "This post has one tag."', 'jetpack' ); ?></option>
164
+ <option value="date" <?php selected( "date", $rule['major'] ); ?>><?php echo esc_html_x( 'Date', 'Noun, as in: "This page is a date archive."', 'jetpack' ); ?></option>
165
+ <option value="page" <?php selected( "page", $rule['major'] ); ?>><?php echo esc_html_x( 'Page', 'Example: The user is looking at a page, not a post.', 'jetpack' ); ?></option>
166
+ </select>
167
+ <?php _ex( 'is', 'Widget Visibility: {Rule Major [Page]} is {Rule Minor [Search results]}', 'jetpack' ); ?>
168
+ <select class="conditions-rule-minor" name="conditions[rules_minor][]" <?php if ( ! $rule['major'] ) { ?> disabled="disabled"<?php } ?> data-loading-text="<?php esc_attr_e( 'Loading...', 'jetpack' ); ?>">
169
+ <?php self::widget_conditions_options_echo( $rule['major'], $rule['minor'] ); ?>
170
+ </select>
171
+ <span class="condition-conjunction"><?php echo esc_html_x( 'or', 'Shown between widget visibility conditions.', 'jetpack' ); ?></span>
172
+ </div>
173
+ <div class="condition-control alignright">
174
+ <a href="#" class="delete-condition"><?php esc_html_e( 'Delete', 'jetpack' ); ?></a> | <a href="#" class="add-condition"><?php esc_html_e( 'Add', 'jetpack' ); ?></a>
175
+ </div>
176
+ <br class="clear" />
177
+ </div><!-- .condition -->
178
+ <?php
179
+ }
180
+
181
+ ?>
182
+ </div><!-- .conditions -->
183
+ </div><!-- .widget-conditional-inner -->
184
+ </div><!-- .widget-conditional -->
185
+ <?php
186
+ }
187
+
188
+ /**
189
+ * On an AJAX update of the widget settings, process the display conditions.
190
+ *
191
+ * @param array $new_instance New settings for this instance as input by the user.
192
+ * @param array $old_instance Old settings for this instance.
193
+ * @return array Modified settings.
194
+ */
195
+ public static function widget_update( $instance, $new_instance, $old_instance ) {
196
+ $conditions = array();
197
+ $conditions['action'] = $_POST['conditions']['action'];
198
+ $conditions['rules'] = array();
199
+
200
+ foreach ( $_POST['conditions']['rules_major'] as $index => $major_rule ) {
201
+ if ( ! $major_rule )
202
+ continue;
203
+
204
+ $conditions['rules'][] = array(
205
+ 'major' => $major_rule,
206
+ 'minor' => isset( $_POST['conditions']['rules_minor'][$index] ) ? $_POST['conditions']['rules_minor'][$index] : ''
207
+ );
208
+ }
209
+
210
+ if ( ! empty( $conditions['rules'] ) )
211
+ $instance['conditions'] = $conditions;
212
+ else
213
+ unset( $instance['conditions'] );
214
+
215
+ if (
216
+ ( isset( $instance['conditions'] ) && ! isset( $old_instance['conditions'] ) )
217
+ ||
218
+ (
219
+ isset( $instance['conditions'], $old_instance['conditions'] )
220
+ &&
221
+ serialize( $instance['conditions'] ) != serialize( $old_instance['conditions'] )
222
+ )
223
+ ) {
224
+ do_action( 'widget_conditions_save' );
225
+ }
226
+ else if ( ! isset( $instance['conditions'] ) && isset( $old_instance['conditions'] ) ) {
227
+ do_action( 'widget_conditions_delete' );
228
+ }
229
+
230
+ return $instance;
231
+ }
232
+
233
+ /**
234
+ * Filter the list of widgets for a sidebar so that active sidebars work as expected.
235
+ *
236
+ * @param array $widget_areas An array of widget areas and their widgets.
237
+ * @return array The modified $widget_area array.
238
+ */
239
+ public static function sidebars_widgets( $widget_areas ) {
240
+ $settings = array();
241
+
242
+ foreach ( $widget_areas as $widget_area => $widgets ) {
243
+ if ( empty( $widgets ) )
244
+ continue;
245
+
246
+ if ( 'wp_inactive_widgets' == $widget_area )
247
+ continue;
248
+
249
+ foreach ( $widgets as $position => $widget_id ) {
250
+ // Find the conditions for this widget.
251
+ list( $basename, $suffix ) = explode( "-", $widget_id, 2 );
252
+
253
+ if ( ! isset( $settings[$basename] ) )
254
+ $settings[$basename] = get_option( 'widget_' . $basename );
255
+
256
+ if ( isset( $settings[$basename][$suffix] ) ) {
257
+ if ( false === self::filter_widget( $settings[$basename][$suffix] ) )
258
+ unset( $widget_areas[$widget_area][$position] );
259
+ }
260
+ }
261
+ }
262
+
263
+ return $widget_areas;
264
+ }
265
+
266
+ /**
267
+ * Determine whether the widget should be displayed based on conditions set by the user.
268
+ *
269
+ * @param array $instance The widget settings.
270
+ * @return array Settings to display or bool false to hide.
271
+ */
272
+ public static function filter_widget( $instance ) {
273
+ global $post, $wp_query;
274
+
275
+ if ( empty( $instance['conditions'] ) || empty( $instance['conditions']['rules'] ) )
276
+ return $instance;
277
+
278
+ $condition_result = false;
279
+
280
+ foreach ( $instance['conditions']['rules'] as $rule ) {
281
+ switch ( $rule['major'] ) {
282
+ case 'date':
283
+ switch ( $rule['minor'] ) {
284
+ case '':
285
+ $condition_result = is_date();
286
+ break;
287
+ case 'month':
288
+ $condition_result = is_month();
289
+ break;
290
+ case 'day':
291
+ $condition_result = is_day();
292
+ break;
293
+ case 'year':
294
+ $condition_result = is_year();
295
+ break;
296
+ }
297
+ break;
298
+ case 'page':
299
+ // Previously hardcoded post type options.
300
+ if ( 'post' == $rule['minor'] )
301
+ $rule['minor'] = 'post_type-post';
302
+ else if ( ! $rule['minor'] )
303
+ $rule['minor'] = 'post_type-page';
304
+
305
+ switch ( $rule['minor'] ) {
306
+ case '404':
307
+ $condition_result = is_404();
308
+ break;
309
+ case 'search':
310
+ $condition_result = is_search();
311
+ break;
312
+ case 'archive':
313
+ $condition_result = is_archive();
314
+ break;
315
+ case 'posts':
316
+ $condition_result = $wp_query->is_posts_page;
317
+ break;
318
+ case 'home':
319
+ $condition_result = is_home();
320
+ break;
321
+ case 'front':
322
+ $condition_result = is_front_page();
323
+ break;
324
+ default:
325
+ if ( substr( $rule['minor'], 0, 10 ) == 'post_type-' )
326
+ $condition_result = is_singular( substr( $rule['minor'], 10 ) );
327
+ else {
328
+ // $rule['minor'] is a page ID
329
+ $condition_result = is_page( $rule['minor'] );
330
+ }
331
+ break;
332
+ }
333
+ break;
334
+ case 'tag':
335
+ if ( ! $rule['minor'] && is_tag() )
336
+ $condition_result = true;
337
+ else if ( is_singular() && $rule['minor'] && has_tag( $rule['minor'] ) )
338
+ $condition_result = true;
339
+ else {
340
+ $tag = get_tag( $rule['minor'] );
341
+
342
+ if ( $tag && is_tag( $tag->slug ) )
343
+ $condition_result = true;
344
+ }
345
+ break;
346
+ case 'category':
347
+ if ( ! $rule['minor'] && is_category() )
348
+ $condition_result = true;
349
+ else if ( is_category( $rule['minor'] ) )
350
+ $condition_result = true;
351
+ else if ( is_singular() && $rule['minor'] && has_category( $rule['minor'] ) )
352
+ $condition_result = true;
353
+ break;
354
+ case 'author':
355
+ if ( ! $rule['minor'] && is_author() )
356
+ $condition_result = true;
357
+ else if ( $rule['minor'] && is_author( $rule['minor'] ) )
358
+ $condition_result = true;
359
+ else if ( is_singular() && $rule['minor'] && $rule['minor'] == $post->post_author )
360
+ $condition_result = true;
361
+ break;
362
+ }
363
+
364
+ if ( $condition_result )
365
+ break;
366
+ }
367
+
368
+ if ( ( 'show' == $instance['conditions']['action'] && ! $condition_result ) || ( 'hide' == $instance['conditions']['action'] && $condition_result ) )
369
+ return false;
370
+
371
+ return $instance;
372
+ }
373
+
374
+ public static function strcasecmp_name( $a, $b ) {
375
+ return strcasecmp( $a->name, $b->name );
376
+ }
377
+ }
378
+
379
+ add_action( 'init', array( 'Jetpack_Widget_Conditions', 'init' ) );
modules/widget-visibility/widget-conditions/rtl/widget-conditions-rtl.css ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* This file was automatically generated on Mar 14 2013 17:20:54 */
2
+
3
+ .widget-liquid-right .widget.expanded {
4
+ overflow: visible;
5
+ }
6
+ .widget-conditional-hide {
7
+ display: none;
8
+ }
9
+ .widget-conditional .widget-conditional-inner {
10
+ background: #F9F9F9;
11
+ border: 1px solid #DFDFDF;
12
+ padding: 12px 12px 0;
13
+ }
14
+ .widget-conditional .condition,
15
+ .widget-conditional .condition-top {
16
+ margin-bottom: 12px;
17
+ }
18
+ .widget-conditional .condition select {
19
+ width: 120px;
20
+ }
21
+ .widget-conditional .condition-top select {
22
+ width: auto;
23
+ }
24
+ .widget-conditional .condition .alignright {
25
+ padding-top: 4px;
26
+ }
27
+ .widget-conditional .condition-control a {
28
+ text-decoration: none;
29
+ }
30
+ .widget-conditional .condition:last-child .condition-conjunction {
31
+ display: none;
32
+ }
33
+ .widget-control-actions .alignright {
34
+ text-align: left;
35
+ }
36
+ .wp-core-ui .button.display-options {
37
+ margin-left: 5px;
38
+ }
39
+ .wp-core-ui .button.display-options:hover {
40
+ text-decoration: none;
41
+ }
modules/widget-visibility/widget-conditions/widget-conditions.css ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .widget-liquid-right .widget.expanded {
2
+ overflow: visible;
3
+ }
4
+ .widget-conditional-hide {
5
+ display: none;
6
+ }
7
+ .widget-conditional .widget-conditional-inner {
8
+ background: #F9F9F9;
9
+ border: 1px solid #DFDFDF;
10
+ padding: 12px 12px 0;
11
+ }
12
+ .widget-conditional .condition,
13
+ .widget-conditional .condition-top {
14
+ margin-bottom: 12px;
15
+ }
16
+ .widget-conditional .condition select {
17
+ width: 120px;
18
+ }
19
+ .widget-conditional .condition-top select {
20
+ width: auto;
21
+ }
22
+ .widget-conditional .condition .alignright {
23
+ padding-top: 4px;
24
+ }
25
+ .widget-conditional .condition-control a {
26
+ text-decoration: none;
27
+ }
28
+ .widget-conditional .condition:last-child .condition-conjunction {
29
+ display: none;
30
+ }
31
+ .widget-control-actions .alignright {
32
+ text-align: right;
33
+ }
34
+ .wp-core-ui .button.display-options {
35
+ margin-right: 5px;
36
+ }
37
+ .wp-core-ui .button.display-options:hover {
38
+ text-decoration: none;
39
+ }
modules/widget-visibility/widget-conditions/widget-conditions.js ADDED
@@ -0,0 +1,112 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ jQuery( function( $ ) {
2
+ function setWidgetMargin( $widget ) {
3
+ if ( $widget.hasClass( 'expanded' ) ) {
4
+ // The expanded widget must be at least 400px wide in order to
5
+ // contain the visibility settings. IE wasn't handling the
6
+ // margin-left value properly.
7
+
8
+ if ( $widget.attr( 'style' ) )
9
+ $widget.data( 'original-style', $widget.attr( 'style' ) );
10
+
11
+ var currentWidth = $widget.width();
12
+
13
+ if ( currentWidth < 400 ) {
14
+ var extra = 400 - currentWidth;
15
+ $widget.css( 'position', 'relative' ).css( 'left', '-' + extra + 'px' ).css( 'width', '400px' );
16
+ }
17
+ }
18
+ else if ( $widget.data( 'original-style' ) ) {
19
+ // Restore any original inline styles when visibility is toggled off.
20
+ $widget.attr( 'style', $widget.data( 'original-style' ) ).data( 'original-style', null );
21
+ }
22
+ else {
23
+ $widget.removeAttr( 'style' );
24
+ }
25
+ }
26
+
27
+ $( "a.display-options" ).each( function() {
28
+ var $displayOptionsButton = $( this ),
29
+ $widget = $displayOptionsButton.closest( "div.widget" );
30
+ $displayOptionsButton.insertBefore( $widget.find( "input.widget-control-save" ) );
31
+
32
+ // Widgets with no configurable options don't show the Save button's container.
33
+ $displayOptionsButton
34
+ .parent()
35
+ .removeClass( 'widget-control-noform' )
36
+ .find( '.spinner' )
37
+ .remove()
38
+ .css( 'float', 'left' )
39
+ .prependTo( $displayOptionsButton.parent() );
40
+
41
+ } );
42
+
43
+ $( "div#widgets-right" ).on( "click", "a.add-condition", function( e ) {
44
+ e.preventDefault();
45
+ var $condition = $( this ).closest( "div.condition" ),
46
+ $conditionClone = $condition.clone().insertAfter( $condition );
47
+ $conditionClone.find( "select.conditions-rule-major" ).val( "" );
48
+ $conditionClone.find( "select.conditions-rule-minor" ).html( "" ).attr( "disabled" );
49
+ } ).on( "click", "a.display-options", function ( e ) {
50
+ e.preventDefault();
51
+
52
+ var $displayOptionsButton = $( this ),
53
+ $widget = $displayOptionsButton.closest( "div.widget" );
54
+
55
+ $widget.find( "div.widget-conditional" ).toggleClass( "widget-conditional-hide" );
56
+ $( this ).toggleClass( "active" );
57
+ $widget.toggleClass( "expanded" );
58
+ setWidgetMargin( $widget );
59
+
60
+ if ( $( this ).hasClass( 'active' ) )
61
+ $widget.find( 'input[name=widget-conditions-visible]' ).val( '1' );
62
+ else
63
+ $widget.find( 'input[name=widget-conditions-visible]' ).val( '0' );
64
+
65
+ } );
66
+
67
+ $( "div#widgets-right" ).on( "click", "a.delete-condition", function( e ) {
68
+ e.preventDefault();
69
+
70
+ var $condition = $( this ).closest( "div.condition" );
71
+
72
+ if ( $condition.is( ":first-child" ) && $condition.is( ":last-child" ) ) {
73
+ $( this ).closest( "div.widget" ).find( "a.display-options" ).click();
74
+ $condition.find( "select.conditions-rule-major" ).val( "" ).change();
75
+ } else {
76
+ $condition.detach();
77
+ }
78
+ } ).on( "click", "div.widget-top", function() {
79
+ var $widget = $( this ).closest( "div.widget" ),
80
+ $displayOptionsButton = $widget.find( "a.display-options" );
81
+
82
+ if ( $displayOptionsButton.hasClass( "active" ) ) {
83
+ $displayOptionsButton.attr( "opened", "true" );
84
+ }
85
+
86
+ if ( $displayOptionsButton.attr( "opened" ) ) {
87
+ $displayOptionsButton.removeAttr( "opened" );
88
+ $widget.toggleClass( "expanded" );
89
+ setWidgetMargin( $widget );
90
+ }
91
+ } );
92
+
93
+ $( document ).on( "change", "select.conditions-rule-major", function() {
94
+ var $conditionsRuleMajor = $ ( this );
95
+ var $conditionsRuleMinor = $conditionsRuleMajor.siblings( "select.conditions-rule-minor:first" );
96
+
97
+ if ( $conditionsRuleMajor.val() ) {
98
+ $conditionsRuleMinor.html( '' ).append( $( '<option/>' ).text( $conditionsRuleMinor.data( 'loading-text' ) ) );
99
+
100
+ var data = {
101
+ action: 'widget_conditions_options',
102
+ major: $conditionsRuleMajor.val()
103
+ };
104
+
105
+ jQuery.post( ajaxurl, data, function( html ) {
106
+ $conditionsRuleMinor.html( html ).removeAttr( "disabled" );
107
+ } );
108
+ } else {
109
+ $conditionsRuleMajor.siblings( "select.conditions-rule-minor" ).attr( "disabled", "disabled" ).html( "" );
110
+ }
111
+ } );
112
+ } );
modules/widgets.php CHANGED
@@ -5,6 +5,7 @@
5
  * Sort Order: 13
6
  * First Introduced: 1.2
7
  * Requires Connection: No
 
8
  */
9
 
10
  function jetpack_load_widgets() {
5
  * Sort Order: 13
6
  * First Introduced: 1.2
7
  * Requires Connection: No
8
+ * Auto Activate: Yes
9
  */
10
 
11
  function jetpack_load_widgets() {
modules/widgets/top-posts.php CHANGED
@@ -222,7 +222,7 @@ class Jetpack_Top_Posts_Widget extends WP_Widget {
222
 
223
  function get_by_views( $count ) {
224
  global $wpdb;
225
- $post_view_posts = stats_get_csv( 'postviews', array( 'days' => 2, 'limit' => 10 ) );
226
  if ( !$post_view_posts ) {
227
  return array();
228
  }
222
 
223
  function get_by_views( $count ) {
224
  global $wpdb;
225
+ $post_view_posts = stats_get_csv( 'postviews', array( 'days' => 2, 'limit' => 11 ) );
226
  if ( !$post_view_posts ) {
227
  return array();
228
  }
modules/widgets/twitter-timeline.php CHANGED
@@ -49,7 +49,7 @@ class Jetpack_Twitter_Timeline_Widget extends WP_Widget {
49
  if ( $instance['title'] )
50
  echo $args['before_title'] . apply_filters( 'widget_title', $instance['title'] ) . $args['after_title'];
51
 
52
- $data_attribs = array( 'widget-id', 'theme', 'link-color', 'border-color', 'chrome' );
53
  $attribs = array( 'width', 'height', 'lang' );
54
 
55
  // Start tag output
@@ -57,6 +57,9 @@ class Jetpack_Twitter_Timeline_Widget extends WP_Widget {
57
 
58
  foreach ( $data_attribs as $att ) {
59
  if ( !empty( $instance[$att] ) ) {
 
 
 
60
  if ( is_array( $instance[$att] ) )
61
  echo ' data-' . esc_attr( $att ) . '="' . esc_attr( join( ' ', $instance['chrome'] ) ) . '"';
62
  else
@@ -94,8 +97,9 @@ class Jetpack_Twitter_Timeline_Widget extends WP_Widget {
94
  $instance['title'] = sanitize_text_field( $new_instance['title'] );
95
  $instance['width'] = (int) $new_instance['width'];
96
  $instance['height'] = (int) $new_instance['height'];
97
- $instance['width'] = ( 0 !== (int) $instance['width'] ) ? (int) $instance['width'] : 225;
98
- $instance['height'] = ( 0 !== (int) $instance['height'] ) ? (int) $instance['height'] : 400;
 
99
 
100
  // If they entered something that might be a full URL, try to parse it out
101
  if ( is_string( $new_instance['widget-id'] ) ) {
@@ -167,6 +171,11 @@ class Jetpack_Twitter_Timeline_Widget extends WP_Widget {
167
  <input class="widefat" id="<?php echo $this->get_field_id( 'height' ); ?>" name="<?php echo $this->get_field_name( 'height' ); ?>" type="text" value="<?php echo esc_attr( $instance['height'] ); ?>" />
168
  </p>
169
 
 
 
 
 
 
170
  <p><small>
171
  <?php
172
  echo wp_kses_post(
49
  if ( $instance['title'] )
50
  echo $args['before_title'] . apply_filters( 'widget_title', $instance['title'] ) . $args['after_title'];
51
 
52
+ $data_attribs = array( 'widget-id', 'theme', 'link-color', 'border-color', 'chrome', 'tweet-limit' );
53
  $attribs = array( 'width', 'height', 'lang' );
54
 
55
  // Start tag output
57
 
58
  foreach ( $data_attribs as $att ) {
59
  if ( !empty( $instance[$att] ) ) {
60
+ if ( 'tweet-limit' == $att && 0 === $instance[$att] )
61
+ continue;
62
+
63
  if ( is_array( $instance[$att] ) )
64
  echo ' data-' . esc_attr( $att ) . '="' . esc_attr( join( ' ', $instance['chrome'] ) ) . '"';
65
  else
97
  $instance['title'] = sanitize_text_field( $new_instance['title'] );
98
  $instance['width'] = (int) $new_instance['width'];
99
  $instance['height'] = (int) $new_instance['height'];
100
+ $instance['width'] = ( 0 !== (int) $new_instance['width'] ) ? (int) $new_instance['width'] : 225;
101
+ $instance['height'] = ( 0 !== (int) $new_instance['height'] ) ? (int) $new_instance['height'] : 400;
102
+ $instance['tweet-limit'] = (int) $new_instance['tweet-limit'];
103
 
104
  // If they entered something that might be a full URL, try to parse it out
105
  if ( is_string( $new_instance['widget-id'] ) ) {
171
  <input class="widefat" id="<?php echo $this->get_field_id( 'height' ); ?>" name="<?php echo $this->get_field_name( 'height' ); ?>" type="text" value="<?php echo esc_attr( $instance['height'] ); ?>" />
172
  </p>
173
 
174
+ <p>
175
+ <label for="<?php echo $this->get_field_id( 'tweet-limit' ); ?>"><?php esc_html_e( '# of Tweets Shown:', 'jetpack' ); ?></label>
176
+ <input class="widefat" id="<?php echo $this->get_field_id( 'tweet-limit' ); ?>" name="<?php echo $this->get_field_name( 'tweet-limit' ); ?>" type="text" value="<?php echo esc_attr( $instance['tweet-limit'] ); ?>" />
177
+ </p>
178
+
179
  <p><small>
180
  <?php
181
  echo wp_kses_post(
modules/wpcc.php ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Module Name: WordPress.com Connect
5
+ * Module Description: Let users login with their WordPress.com Credentials, through <a href="http://jetpack.me/support/wpcc/">WordPress.com Connect</a>
6
+ * Sort Order: 50
7
+ * First Introduced: 2.4
8
+ * Requires Connection: No
9
+ * Auto Activate: No
10
+ */
11
+
12
+ if ( ! class_exists( 'WPCC_Sign_On' ) )
13
+ require_once( dirname( __FILE__ ) . '/wpcc/wpcc-sign-on.php' );
14
+
15
+ add_action( 'jetpack_modules_loaded', 'jetpack_wpcc_loaded' );
16
+ function jetpack_wpcc_loaded() {
17
+ Jetpack::enable_module_configurable( __FILE__ );
18
+ Jetpack::module_configuration_load( __FILE__, 'jetpack_wpcc_configuration_load' );
19
+ }
20
+
21
+ function jetpack_wpcc_configuration_load() {
22
+ wp_safe_redirect( admin_url( 'options-general.php#wpcc-sign-on-section' ) );
23
+ exit;
24
+ }
modules/wpcc/wpcc-sign-on.css ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ #loginform {
3
+ overflow: hidden;
4
+ padding-bottom: 26px;
5
+ }
6
+
7
+ #wpcc-sign-on {
8
+ display: block;
9
+ float: right;
10
+ margin:1em 0 0;
11
+ }
modules/wpcc/wpcc-sign-on.js ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+
2
+ jQuery(document).ready(function($){
3
+ $( '#loginform' ).append( $( '#wpcc-sign-on' ) );
4
+ });
modules/wpcc/wpcc-sign-on.php ADDED
@@ -0,0 +1,437 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Plugin Name: WPCC Sign On
4
+ * Plugin URI: https://github.com/Automattic/wpcc-sign-on
5
+ * Description: A single-sign-on via WordPress.com for your WordPress.org site!
6
+ * Author: Automatticians
7
+ * Version: 1.0
8
+ * Author URI: http://automattic.com/
9
+ */
10
+
11
+ class WPCC_Sign_On {
12
+ static $instance = null;
13
+
14
+ var $request_token_url, // Fixed URL.
15
+ $authenticate_url, // Fixed URL.
16
+ $user_data_url, // Fixed URL.
17
+ $new_app_url_base, // Fixed URL.
18
+ $options_prefix, // Where the options are in the DB.
19
+ $options, // Options Array.
20
+ $client_id, // Option.
21
+ $client_secret, // Option.
22
+ $new_user_override, // Option.
23
+ $match_by_email, // Option.
24
+ $wpcc_state,
25
+ $secret,
26
+ $user_data;
27
+
28
+ function __construct() {
29
+ if ( self::$instance ) {
30
+ return self::$instance;
31
+ }
32
+
33
+ self::$instance = $this;
34
+
35
+ $this->request_token_url = 'https://public-api.wordpress.com/oauth2/token';
36
+ $this->authenticate_url = 'https://public-api.wordpress.com/oauth2/authenticate';
37
+ $this->user_data_url = 'https://public-api.wordpress.com/rest/v1/me/';
38
+ $this->new_app_url_base = 'https://developer.wordpress.com/apps/new/';
39
+ $this->options_prefix = $this->in_jetpack() ? 'jetpack_' : '';
40
+ $this->options = $this->fetch_options();
41
+ $this->client_id = $this->options['client_id'];
42
+ $this->client_secret = $this->options['client_secret'];
43
+ $this->new_user_override = $this->options['new_user_override'];
44
+ $this->match_by_email = $this->options['match_by_email'];
45
+
46
+ add_action( 'admin_init', array( $this, 'admin_init' ) );
47
+
48
+ if ( empty( $this->client_id ) ) {
49
+ return;
50
+ }
51
+
52
+ add_action( 'login_init', array( $this, 'login_init' ) );
53
+ add_action( 'login_enqueue_scripts', array( $this, 'login_enqueue_scripts' ) );
54
+ add_action( 'login_form', array( $this, 'login_form' ) );
55
+ }
56
+
57
+ function in_jetpack() {
58
+ return '/modules/wpcc' == substr( dirname( __FILE__ ), ( 0 - strlen( '/modules/wpcc' ) ) );
59
+ }
60
+
61
+ function fetch_options() {
62
+ $options = $this->in_jetpack() ? Jetpack_Options::get_option( 'wpcc_options' ) : get_option( 'wpcc_options' );
63
+ $args = wp_parse_args( $options, $this->default_options() );
64
+
65
+ $args['new_user_override'] = defined( 'WPCC_NEW_USER_OVERRIDE' ) ? WPCC_NEW_USER_OVERRIDE : false;
66
+ $args['match_by_email'] = defined( 'WPCC_MATCH_BY_EMAIL' ) ? WPCC_MATCH_BY_EMAIL : true;
67
+
68
+ return $args;
69
+ }
70
+
71
+ function default_options() {
72
+ return array(
73
+ 'client_id' => '',
74
+ 'client_secret' => '',
75
+ 'new_user_override' => false,
76
+ 'match_by_email' => true,
77
+ );
78
+ }
79
+
80
+ function admin_init() {
81
+ // Create the section
82
+ add_settings_section(
83
+ 'wpcc',
84
+ esc_html__( 'WordPress.com Connect', 'jetpack' ),
85
+ array( $this, 'wpcc_settings_section' ),
86
+ 'general'
87
+ );
88
+
89
+ add_settings_field(
90
+ 'wpcc_sign_on_client_id',
91
+ sprintf( '<label for="wpcc_sign_on_client_id">%1$s</label>', __( 'WPCC Client ID', 'jetpack' ) ),
92
+ array( $this, 'wpcc_sign_on_client_id_cb' ),
93
+ 'general',
94
+ 'wpcc'
95
+ );
96
+ add_settings_field(
97
+ 'wpcc_sign_on_client_secret',
98
+ sprintf( '<label for="wpcc_sign_on_client_secret">%1$s</label>', __( 'WPCC Client Secret', 'jetpack' ) ),
99
+ array( $this, 'wpcc_sign_on_client_secret_cb' ),
100
+ 'general',
101
+ 'wpcc'
102
+ );
103
+
104
+ register_setting( 'general', "{$this->options_prefix}wpcc_options", array( $this, 'sanitize_options' ) );
105
+
106
+ if ( ! empty( $this->client_id ) && ! empty( $this->client_secret ) ) {
107
+ add_action( 'show_user_profile', array( $this, 'edit_profile_fields' ) ); // For their own profile
108
+ add_action( 'edit_user_profile', array( $this, 'edit_profile_fields' ) ); // For folks editing others profiles
109
+ } else {
110
+ add_action( 'admin_notices', array( $this, 'no_credentials_admin_notice' ) );
111
+ }
112
+
113
+ if ( $user_ID = get_current_user_id() ) {
114
+ $this->wpcc_state = "localuser{$user_ID}";
115
+ }
116
+ }
117
+
118
+ function no_credentials_admin_notice() {
119
+ $disable_url = wp_nonce_url( Jetpack::admin_url( 'action=deactivate&module=wpcc' ), 'jetpack_deactivate-wpcc' );
120
+ ?>
121
+ <div id="wpcc-needs-config" class="updated">
122
+ <p class="alignright"><a href="<?php echo esc_url( $disable_url ); ?>"><?php _e( 'Close', 'jetpack' ); ?></a></p>
123
+ <p><?php printf( __( '<strong>Almost done.</strong> Before WordPress.com Connect can finish activating, you\'ll need to <a href="%s">register your website as an application on WordPress.com</a>', 'jetpack' ), esc_url( admin_url( 'options-general.php#wpcc-sign-on-section' ) ) ); ?></p>
124
+ </div>
125
+ <?php
126
+ }
127
+
128
+ function sanitize_options( $options ) {
129
+ if ( ! empty( $options['client_id'] ) ) {
130
+ $options['client_id'] = intval( $options['client_id'] );
131
+ }
132
+
133
+ if ( ! empty( $options['client_secret'] ) ) {
134
+ $options['client_secret'] = sanitize_text_field( $options['client_secret'] );
135
+ }
136
+
137
+ return $options;
138
+ }
139
+
140
+ function wpcc_settings_section() {
141
+ ?>
142
+
143
+ <p id="wpcc-sign-on-section">
144
+ <?php
145
+ if ( empty( $this->client_id ) || empty( $this->client_secret ) ) {
146
+ printf( __( 'Visit WordPress.com to <a href="%s">register a new WPCC client id and secret key</a>.', 'jetpack' ), $this->get_new_app_url() );
147
+ } else {
148
+ printf( __( 'Visit WordPress.com to <a href="%s">manage your WPCC client settings</a>.', 'jetpack' ), $this->get_edit_app_url() );
149
+ }
150
+ ?>
151
+ </p>
152
+ <script>
153
+ jQuery('#wpcc-sign-on-section a').attr( 'target', '_blank' );
154
+ </script>
155
+
156
+ <?php
157
+ }
158
+
159
+ function wpcc_sign_on_client_id_cb() {
160
+ echo '<input class="regular-text code" autocomplete="off" type="text" id="wpcc_sign_on_client_id" name="' . $this->options_prefix . 'wpcc_options[client_id]" value="' . esc_attr( $this->client_id ) . '" />';
161
+ }
162
+
163
+ function wpcc_sign_on_client_secret_cb() {
164
+ echo '<input class="regular-text code" autocomplete="off" type="text" id="wpcc_sign_on_client_secret" name="' . $this->options_prefix . 'wpcc_options[client_secret]" value="' . esc_attr( $this->client_secret ) . '" />';
165
+ }
166
+
167
+ function edit_profile_fields( $user ) {
168
+ if ( isset( $_GET['wpcc'] ) && 'purge' == $_GET['wpcc'] ) {
169
+ delete_user_meta( $user->ID, 'wpcom_user_id' );
170
+ delete_user_meta( $user->ID, 'wpcom_user_data' );
171
+ }
172
+ ?>
173
+
174
+ <h3><?php _e( 'WordPress.com Connect', 'jetpack' ); ?></h3>
175
+ <p><?php _e( 'Connecting with WordPress.com Connect enables you to log on via your WordPress.com account.', 'jetpack' ); ?></p>
176
+
177
+ <?php if ( ( $user_data = get_user_meta( $user->ID, 'wpcom_user_data', true ) ) && ! empty( $user_data->ID ) ) : /* If the user is currently connected... */ ?>
178
+
179
+ <table class="form-table wpcc-form-table">
180
+ <tbody>
181
+ <tr>
182
+ <td>
183
+ <div class="profile-card">
184
+ <img src="<?php echo esc_url( $user_data->avatar_URL ); ?>" height="48" width="48" />
185
+ <p class="connected"><strong><?php _e( 'Connected', 'jetpack' ); ?></strong></p>
186
+ <p><?php echo esc_html( $user_data->username ); ?></p>
187
+ </div>
188
+ <p><a class="button button-secondary" href="<?php echo esc_url( add_query_arg( 'wpcc', 'purge' ) ); ?>"><?php _e( 'Unlink This Account', 'jetpack' ); ?></a></p>
189
+ </td>
190
+ </tr>
191
+ </tbody>
192
+ </table>
193
+
194
+ <style>
195
+ .wpcc-form-table td {
196
+ padding-left: 0;
197
+ }
198
+
199
+ .wpcc-form-table .profile-card {
200
+ padding: 10px;
201
+ background: #fff;
202
+ overflow: hidden;
203
+ max-width: 400px;
204
+ box-shadow: 0 2px 5px rgba( 0, 0, 0, 0.4 );
205
+ margin-bottom: 1em;
206
+ }
207
+
208
+ .wpcc-form-table .profile-card img {
209
+ float: left;
210
+ margin-right: 1em;
211
+ }
212
+
213
+ .wpcc-form-table .profile-card .connected {
214
+ float: right;
215
+ margin-right: 0.5em;
216
+ color: #0a0;
217
+ }
218
+
219
+ .wpcc-form-table .profile-card p {
220
+ margin-top: 0.7em;
221
+ font-size: 1.2em;
222
+ }
223
+ </style>
224
+
225
+ <?php elseif ( get_current_user_id() == $user->ID ) : ?>
226
+
227
+ <?php echo $this->button( array( 'redirect_uri' => add_query_arg( 'for', 'profile', wp_login_url() ) ) ); ?>
228
+
229
+ <?php else : ?>
230
+
231
+ <p><?php _e( 'This profile is not currently linked to a WordPress.com Profile.', 'jetpack' ); ?></p>
232
+
233
+ <?php endif;
234
+ }
235
+
236
+ function verify_connection( $get_args = array() ) {
237
+ if ( empty( $_GET['state'] ) ) {
238
+ wp_die( __( 'Warning! State variable missing after authentication.', 'jetpack' ) );
239
+ }
240
+
241
+ if ( $_GET['state'] != $this->wpcc_state ) {
242
+ wp_die( __( 'Warning! State mismatch. Authentication attempt may have been compromised.', 'jetpack' ) );
243
+ }
244
+
245
+ $redirect_uri = wp_login_url();
246
+
247
+ if ( $get_args ) {
248
+ $redirect_uri = add_query_arg( $get_args, $redirect_uri );
249
+ }
250
+
251
+ $args = array(
252
+ 'client_id' => $this->client_id,
253
+ 'redirect_uri' => $redirect_uri,
254
+ 'client_secret' => $this->client_secret,
255
+ 'code' => sanitize_text_field( $_GET['code'] ), // The code from the previous request
256
+ 'grant_type' => 'authorization_code',
257
+ );
258
+
259
+ $response = wp_remote_post( $this->request_token_url, array( 'body' => $args ) );
260
+
261
+ if ( is_wp_error( $response ) ) {
262
+ wp_die( __( 'Warning! Could not confirm request token url!', 'jetpack' ) );
263
+ }
264
+
265
+ $this->secret = json_decode( wp_remote_retrieve_body( $response ) );
266
+
267
+ $args = array(
268
+ 'headers' => array(
269
+ 'Authorization' => sprintf( 'Bearer %s', $this->secret->access_token ),
270
+ ),
271
+ );
272
+
273
+ $response = wp_remote_get( $this->user_data_url, $args );
274
+
275
+ if ( is_wp_error( $response ) ) {
276
+ wp_die( __( 'Warning! Could not fetch user data!', 'jetpack' ) );
277
+ }
278
+
279
+ $this->user_data = json_decode( wp_remote_retrieve_body( $response ) );
280
+
281
+ return $this->user_data;
282
+ }
283
+
284
+ function login_init() {
285
+ // Set the wpcc_state
286
+ $this->wpcc_state = md5( mt_rand() );
287
+ if ( isset( $_COOKIE['wpcc_state'] ) ) {
288
+ $this->wpcc_state = $_COOKIE['wpcc_state'];
289
+ } else {
290
+ setcookie( 'wpcc_state', $this->wpcc_state );
291
+ }
292
+
293
+ if ( isset( $_GET['for'] ) && ( 'profile' == $_GET['for'] ) ) {
294
+ $user_ID = get_current_user_id();
295
+
296
+ $this->wpcc_state = "localuser{$user_ID}";
297
+ $user_data = $this->verify_connection( array( 'for' => 'profile' ) );
298
+
299
+ update_user_meta( get_current_user_id(), 'wpcom_user_id', $user_data->ID );
300
+ update_user_meta( get_current_user_id(), 'wpcom_user_data', $user_data );
301
+
302
+ wp_safe_redirect( admin_url( 'profile.php' ) );
303
+ exit;
304
+ }
305
+
306
+ // If they just got forwarded back ...
307
+ if ( isset( $_GET['code'] ) ) {
308
+
309
+ $user_data = $this->verify_connection();
310
+
311
+ $this->auth_user( $user_data );
312
+ }
313
+ }
314
+
315
+ function login_enqueue_scripts() {
316
+ wp_enqueue_style( 'wpcc-sign-on', plugins_url( 'wpcc-sign-on.css', __FILE__ ), 0, filemtime( dirname( __FILE__ ) . '/wpcc-sign-on.css' ) );
317
+ wp_enqueue_script( 'wpcc-sign-on', plugins_url( 'wpcc-sign-on.js', __FILE__ ), array( 'jquery' ), filemtime( dirname( __FILE__ ) . '/wpcc-sign-on.js' ) );
318
+ }
319
+
320
+ function login_form() {
321
+ if( ! did_action( 'login_init' ) )
322
+ return;
323
+
324
+ echo $this->button();
325
+ }
326
+
327
+ function button( $args = array() ) {
328
+ $defaults = array(
329
+ 'response_type' => 'code',
330
+ 'client_id' => $this->client_id,
331
+ 'state' => $this->wpcc_state,
332
+ 'redirect_uri' => wp_login_url(),
333
+ );
334
+
335
+ $args = wp_parse_args( $args, $defaults );
336
+
337
+ if ( ! empty( $_REQUEST['redirect_to'] ) ) {
338
+ $args['redirect_uri'] = add_query_arg( 'redirect_to', $_REQUEST['redirect_to'], $args['redirect_uri'] );
339
+ }
340
+
341
+ $url = add_query_arg( $args, $this->authenticate_url );
342
+
343
+ return sprintf( '<a id="wpcc-sign-on" href="%1$s"><img src="//s0.wp.com/i/wpcc-button.png" width="231" /></a>', esc_url( $url ) );
344
+ }
345
+
346
+ function auth_user( $user_data ) {
347
+
348
+ if ( ! $user_data->verified ) {
349
+ return false;
350
+ }
351
+
352
+ $user = $this->get_user_by_wpcom_id( $user_data->ID );
353
+
354
+ // If we don't have one by wpcom_user_id, try by the email?
355
+ if ( empty( $user ) && $this->match_by_email ) {
356
+ $user = get_user_by( 'email', $user_data->email );
357
+ if ( $user ) {
358
+ update_user_meta( $user->ID, 'wpcom_user_id', $user_data->ID );
359
+ }
360
+ }
361
+
362
+ // If we've still got nothing, create the user.
363
+ if ( empty( $user ) && ( get_option( 'users_can_register' ) || $this->new_user_override ) ) {
364
+ $username = $user_data->username;
365
+
366
+ if ( username_exists( $username ) ) {
367
+ $username .= '_' . $user_data->ID;
368
+ }
369
+
370
+ if ( username_exists( $username ) )
371
+ $username .= '_' . mt_rand();
372
+
373
+ $password = wp_generate_password( 20 );
374
+ $user_id = wp_create_user( $username, $password, $user_data->email );
375
+ $user = get_userdata( $user_id );
376
+
377
+ $user->display_name = $user_data->display_name;
378
+ wp_update_user( $user );
379
+
380
+ update_user_meta( $user->ID, 'wpcom_user_id', $user_data->ID );
381
+ }
382
+
383
+ if ( $user ) {
384
+ // Cache the user's details, so we can present it back to them on their user screen.
385
+ update_user_meta( $user->ID, 'wpcom_user_data', $user_data );
386
+ wp_set_auth_cookie( $user->ID );
387
+
388
+ $_request_redirect_to = isset( $_REQUEST['redirect_to'] ) ? $_REQUEST['redirect_to'] : '';
389
+ $redirect_to = user_can( $user, 'edit_posts' ) ? admin_url() : admin_url( 'profile.php' );
390
+ wp_safe_redirect( apply_filters( 'login_redirect', $redirect_to, $_request_redirect_to, $user ) );
391
+ exit;
392
+ }
393
+
394
+ add_action( 'login_message', array( $this, 'cant_find_user' ) );
395
+ }
396
+
397
+ function get_user_by_wpcom_id( $wpcom_user_id ) {
398
+ $user_query = new WP_User_Query( array(
399
+ 'meta_key' => 'wpcom_user_id',
400
+ 'meta_value' => intval( $wpcom_user_id ),
401
+ ) );
402
+
403
+ $users = $user_query->get_results();
404
+
405
+ return ( is_array( $users ) && ! empty( $users ) ) ? array_shift( $users ) : $users;
406
+ }
407
+
408
+ function cant_find_user( $message ) {
409
+ $err_format = __( 'We couldn\'t find an account with the email <strong><code>%1$s</code></strong> to log you in with. If you already have an account on <strong>%2$s</strong>, please make sure that <strong><code>%1$s</code></strong> is configured as the email address, or that you have connected to WordPress.com on your profile page.', 'jetpack' );
410
+ if ( ! $this->match_by_email ) {
411
+ $err_format = __( 'We couldn\'t find any account on <strong>%2$s</strong> that is linked to your WordPress.com account to log you in with. If you already have an account on <strong>%2$s</strong>, please make sure that you have connected to WordPress.com on your profile page.', 'jetpack' );
412
+ }
413
+ $err = sprintf( $err_format, $this->user_data->email, get_bloginfo( 'name' ) );
414
+ $message .= sprintf( '<p class="message" id="login_error">%s</p>', $err );
415
+ return $message;
416
+ }
417
+
418
+ function get_new_app_url() {
419
+ $args = array(
420
+ 'for' => 'jetpack',
421
+ 'title' => urlencode( get_bloginfo( 'name' ) ),
422
+ 'description' => urlencode( get_bloginfo( 'description' ) ),
423
+ 'url' => urlencode( site_url() ),
424
+ 'redirect_uri' => urlencode( wp_login_url() ),
425
+ );
426
+ return add_query_arg( $args, $this->new_app_url_base );
427
+ }
428
+
429
+ function get_edit_app_url( $client_id = null ) {
430
+ if ( empty( $client_id ) ) {
431
+ $client_id = $this->client_id;
432
+ }
433
+ return sprintf( 'https://developer.wordpress.com/apps/%d/', $client_id );
434
+ }
435
+ }
436
+
437
+ new WPCC_Sign_On;
readme.txt CHANGED
@@ -3,7 +3,7 @@ Contributors: automattic, alternatekev, andy, apeatling, azaozz, barry, beaulebe
3
  Tags: WordPress.com, statistics, stats, views, tweets, twitter, widget, gravatar, hovercards, profile, equations, latex, math, maths, youtube, shortcode, archives, audio, blip, bliptv, dailymotion, digg, flickr, googlevideo, google, googlemaps, kyte, kytetv, livevideo, redlasso, rockyou, rss, scribd, slide, slideshare, soundcloud, vimeo, shortlinks, wp.me, subscriptions, notifications, notes, json, api, rest, mosaic, gallery, slideshow
4
  Requires at least: 3.5
5
  Tested up to: 3.6
6
- Stable tag: 2.3.8
7
 
8
  Supercharge your WordPress site with powerful features previously only available to WordPress.com users.
9
 
@@ -62,11 +62,14 @@ Once you've installed Jetpack, your stats will be available via the "Site Stats"
62
 
63
  = How do I contribute to Jetpack? =
64
 
65
- Easy! There are a couple of ways (more coming soon):
66
 
 
67
  * Give us a hand answering questions in our [support forum](http://wordpress.org/support/plugin/jetpack)
68
  * Report bugs, with reproduction steps, or post patches on our [Trac](http://plugins.trac.wordpress.org/newticket?component=jetpack)
69
 
 
 
70
  == Screenshots ==
71
 
72
  1. Stats chart.
@@ -79,17 +82,62 @@ Easy! There are a couple of ways (more coming soon):
79
  8. Mobile Theme
80
 
81
  == Changelog ==
82
- = 2.3.8 =
 
83
  Release Date: May 26, 2016
84
 
85
  * Important security update. Please upgrade immediately.
86
 
87
- = 2.3.7 =
88
  * Bug Fix: Avoid function which isn't always defined.
89
 
90
- = 2.3.6 =
91
  * Important security update. CVE-2014-0173
92
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
93
  = 2.3.5 =
94
  * Enhancement: Added Path support to Publicize.
95
 
@@ -236,7 +284,7 @@ Release Date: May 26, 2016
236
  * Bug Fix: Shortcodes - Slideshow: RTL styling update
237
  * Bug Fix: Tiled Galleries - Fix IE8 display bug where it doesn't honor inline CSS for width on images
238
  * Bug Fix: Tiled Galleries - Remove depreacted hover call, use mouseenter mouseleave instead
239
- * Enhancement: Twitter Timeline Widget: New JavaScript based widget. Old one will discontinue May 7th.
240
 
241
  = 2.2.2 =
242
  * Enhancement: Mobile Theme: Add controls for custom CSS.
3
  Tags: WordPress.com, statistics, stats, views, tweets, twitter, widget, gravatar, hovercards, profile, equations, latex, math, maths, youtube, shortcode, archives, audio, blip, bliptv, dailymotion, digg, flickr, googlevideo, google, googlemaps, kyte, kytetv, livevideo, redlasso, rockyou, rss, scribd, slide, slideshare, soundcloud, vimeo, shortlinks, wp.me, subscriptions, notifications, notes, json, api, rest, mosaic, gallery, slideshow
4
  Requires at least: 3.5
5
  Tested up to: 3.6
6
+ Stable tag: 2.4.5
7
 
8
  Supercharge your WordPress site with powerful features previously only available to WordPress.com users.
9
 
62
 
63
  = How do I contribute to Jetpack? =
64
 
65
+ Easy! There are opportunities for developers at all levels to contribute:
66
 
67
+ * Join our Beta Test group
68
  * Give us a hand answering questions in our [support forum](http://wordpress.org/support/plugin/jetpack)
69
  * Report bugs, with reproduction steps, or post patches on our [Trac](http://plugins.trac.wordpress.org/newticket?component=jetpack)
70
 
71
+ Learn more (and get detailed instructions) in our [contribute guide](http://jetpack.me/contribute/).
72
+
73
  == Screenshots ==
74
 
75
  1. Stats chart.
82
  8. Mobile Theme
83
 
84
  == Changelog ==
85
+
86
+ = 2.4.5 =
87
  Release Date: May 26, 2016
88
 
89
  * Important security update. Please upgrade immediately.
90
 
91
+ = 2.4.4 =
92
  * Bug Fix: Avoid function which isn't always defined.
93
 
94
+ = 2.4.3 =
95
  * Important security update. CVE-2014-0173
96
 
97
+ = 2.4.2 =
98
+ * Enhancement: Converted to module headers to detect Auto-Activating modules.
99
+ * Enhancement: WPCC: Added 'Close' link to deactivate WPCC in the admin nag.
100
+ * Enhancement: JSON API: Add User Nicename to the user data.
101
+ * Bug Fix: Contact Form: Stopped using a short tag.
102
+ * Bug Fix: Changed CSS selector to catch MP6 stylings.
103
+ * Bug Fix: Dropped __FILE__ references in class.jetpack.php in favor of JETPACK__PLUGIN_DIR constant, now code that deactivates the plugin from the connect nag works again.
104
+ * Bug Fix: Random Redirect: Add random-redirect to the plugins overriden list, in case someone is using Matt's Random Redirect plugin.
105
+ * Bug Fix: Tiled Gallery: Revert r757178 relating to tiled gallery defaults.
106
+ * Bug Fix: Return false, not zero, if $GLOBALS['content_width'] isn't defined.
107
+ * Bug Fix: WPCC: Don't call wp_login_url() in the constructor -- if someone is running a custom login page, that can break things if their plugin runs get_permalink as a filter before init.
108
+ * Bug Fix: Tiled Gallery: Add fallback if post_parent == 0 due to infinite_scroll_load_other_plugins_scripts.
109
+ * Bug Fix: Custom CSS: Set the ACE gutter z-index to 1.
110
+ * Bug Fix: Custom Post Types: Switch from wp_redirect() to wp_safe_redirect().
111
+ * Bug Fix: Likes: Set overflow:hidden; on the likes adminbar item.
112
+ * Bug Fix: Mobile Theme: Migrate where/when the custom header stuff is included.
113
+ * Bug Fix: Slideshow Shortcode: Add a height of 410px.
114
+
115
+ = 2.4.1 =
116
+ * Enhancement: Don't auto-activate WPCC.
117
+
118
+ = 2.4 =
119
+ * Enhancement: WordPress.com Connect (WPCC): New Module.
120
+ * Enhancement: Widget Visibility: New Module.
121
+ * Enhancement: Shortcode: Addition of new Twitter Timeline shortcode.
122
+ * Enhancement: Shortcode: Addition of new Presentation shortcode.
123
+ * Enhancement: Shortcode: Addition of new Vine shortcode.
124
+ * Enhancement: Custom Post Types: CPTs are available.
125
+ * Enhancement: Subscriptions: Add 'jetpack_is_post_mailable' filter.
126
+ * Enhancement: OpenGraph: Add Twitter Cards meta tags as well.
127
+ * Enhancement: Custom CSS: Update lessc and scssc preprocessors to 0.4.0 and 0.0.7 respectively.
128
+ * Enhancement: Omnisearch: Add Media results.
129
+ * Enhancement: Likes: Use a protocol-agnostic iframe, instead of forced HTTPS.
130
+ * Enhancement: Top Posts: Increase post limit.
131
+ * Enhancement: Publicize: Updated JS and UI.
132
+ * Enhancement: Photon: New filter to let site admins/owners enable photon for HTTPS urls.
133
+ * Enhancement: New jetpack_get_available_modules filter.
134
+ * Enhancement: Subscriptions: Antispam measures.
135
+ * Bug Fix: Add inline style to keep plugins/themes from inadvertently hiding the Connect box.
136
+ * Bug Fix: Custom CSS: Respect the new wp_revisions_to_keep filter.
137
+ * Bug Fix: Photon: Only hook jetpack_photon_url into the filter if the user has Photon active.
138
+ * Bug Fix: Heartbeat: Used wrong object, occasinally fatal-erroring out for the cron.
139
+ * Bug Fix: Add an empty debug.php file to the /modules/ folder, to solve some update issues where it never got deleted.
140
+
141
  = 2.3.5 =
142
  * Enhancement: Added Path support to Publicize.
143
 
284
  * Bug Fix: Shortcodes - Slideshow: RTL styling update
285
  * Bug Fix: Tiled Galleries - Fix IE8 display bug where it doesn't honor inline CSS for width on images
286
  * Bug Fix: Tiled Galleries - Remove depreacted hover call, use mouseenter mouseleave instead
287
+ * Enhancement: Twitter Timeline Widget: New JavaScript based widget. Old one will discontinue May 7th.
288
 
289
  = 2.2.2 =
290
  * Enhancement: Mobile Theme: Add controls for custom CSS.