ThemeGrill Demo Importer - Version 1.1.0

Version Description

  • Feature - Backbone views interface for demos and previews
  • Feature - Added download button for the preview not installed
  • Feature - Robust quick search view to change in demo interface
  • Feature - Detailed information in popup to showcase plugins, events, etc
  • Refactor - Replace old way to import demo with new wp.updates methods
  • Fix - Menu classes to hide admin menu if no JS using css class hide-if-no-js
  • Fix - Remove the old demo pack if found and to update the new demo packs
Download this release

Release Info

Developer ThemeGrill
Plugin Icon 128x128 ThemeGrill Demo Importer
Version 1.1.0
Comparing to
See all releases

Code changes from version 1.0 to 1.1.0

.stylelintrc ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "rules": {
3
+ "indentation": "tab",
4
+ "color-hex-case": "lower",
5
+ "color-no-invalid-hex": true,
6
+
7
+ "function-calc-no-unspaced-operator": true,
8
+ "function-comma-space-after": "always-single-line",
9
+ "function-comma-space-before": "never",
10
+ "function-name-case": "lower",
11
+ "function-url-quotes": "always",
12
+ "function-whitespace-after": "always",
13
+
14
+ "number-leading-zero": "always",
15
+ "number-no-trailing-zeros": true,
16
+ "length-zero-no-unit": true,
17
+
18
+ "string-no-newline": true,
19
+ "string-quotes": "single",
20
+
21
+ "unit-case": "lower",
22
+ "unit-no-unknown": true,
23
+ "unit-whitelist": ["px", "%", "deg", "ms", "em", "vh", "vw", "rem", "s", "ex", "pt", "cm"],
24
+
25
+ "value-list-comma-space-after": "always-single-line",
26
+ "value-list-comma-space-before": "never",
27
+
28
+ "shorthand-property-no-redundant-values": true,
29
+
30
+ "property-case": "lower",
31
+
32
+ "declaration-block-no-duplicate-properties": [true, { "severity": "warning" } ],
33
+ "declaration-block-no-ignored-properties": [true, { "severity": "warning" } ],
34
+ "declaration-block-trailing-semicolon": "always",
35
+ "declaration-block-single-line-max-declarations": 0,
36
+ "declaration-block-semicolon-space-before": "never",
37
+ "declaration-block-semicolon-space-after": "always-single-line",
38
+ "declaration-block-semicolon-newline-before": "never-multi-line",
39
+ "declaration-block-semicolon-newline-after": "always-multi-line",
40
+
41
+ "block-closing-brace-newline-after": "always",
42
+ "block-closing-brace-newline-before": "always-multi-line",
43
+ "block-no-empty": true,
44
+ "block-opening-brace-newline-after": "always-multi-line",
45
+ "block-opening-brace-space-before": "always",
46
+
47
+ "selector-attribute-brackets-space-inside": "never",
48
+ "selector-attribute-operator-space-after": "never",
49
+ "selector-attribute-operator-space-before": "never",
50
+ "selector-combinator-space-after": "always",
51
+ "selector-combinator-space-before": "always",
52
+ "selector-pseudo-class-case": "lower",
53
+ "selector-pseudo-class-parentheses-space-inside": "always",
54
+ "selector-pseudo-element-case": "lower",
55
+ "selector-pseudo-element-colon-notation": "double",
56
+ "selector-pseudo-element-no-unknown": true,
57
+ "selector-type-case": "lower",
58
+ }
59
+ }
assets/css/demo-importer.css CHANGED
@@ -1 +1 @@
1
- .appearance_page_demo-importer .wp-filter{padding:0 20px}.appearance_page_demo-importer .wp-filter .filter-links li>a:focus{box-shadow:none}.theme-browser .theme .theme-actions span.spinner{display:none}.theme-browser .theme .theme-actions.imported,.theme-browser .theme .theme-actions.importing{opacity:1}.theme-browser .theme .theme-actions.imported .button,.theme-browser .theme .theme-actions.importing .button,.theme-browser .theme:not(.active) .theme-actions .preview{display:none;visibility:hidden}.theme-browser .theme:not(.active) .theme-actions.imported .preview{display:block;visibility:visible}.theme-browser .theme .theme-actions.importing span.spinner.is-active{width:auto;display:block;font-size:12px;padding-right:25px;background-position:right center}@media only screen and (max-width:780px){.theme-browser .theme .theme-actions.imported{opacity:0}}.theme .notice,.theme .notice.is-dismissible{left:0;margin:0;position:absolute;right:0;top:0}.theme .notice-success p::before{color:#79ba49;content:'\f147';margin-right:6px;vertical-align:top;display:inline-block;font:400 20px/1 dashicons;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.tips{cursor:help;text-decoration:none}img.tips{padding:5px 0 0}#tiptip_holder{display:none;position:absolute;top:0;left:0;z-index:9999999}#tiptip_holder.tip_top{padding-bottom:5px}#tiptip_holder.tip_top #tiptip_arrow_inner{margin-top:-7px;margin-left:-6px;border-top-color:#333}#tiptip_holder.tip_bottom{padding-top:5px}#tiptip_holder.tip_bottom #tiptip_arrow_inner{margin-top:-5px;margin-left:-6px;border-bottom-color:#333}#tiptip_holder.tip_right{padding-left:5px}#tiptip_holder.tip_right #tiptip_arrow_inner{margin-top:-6px;margin-left:-5px;border-right-color:#333}#tiptip_holder.tip_left{padding-right:5px}#tiptip_holder.tip_left #tiptip_arrow_inner{margin-top:-6px;margin-left:-7px;border-left-color:#333}#tiptip_content{color:#fff;font-size:.8em;max-width:150px;background:#333;text-align:center;border-radius:3px;padding:.618em 1em;box-shadow:0 1px 3px rgba(0,0,0,.2)}#tiptip_content code{padding:1px;background:#888}#tiptip_arrow,#tiptip_arrow_inner{position:absolute;border-color:transparent;border-style:solid;border-width:6px;height:0;width:0}
1
+ #tiptip_content,table.plugins-list-table .plugin-status{text-align:center}.appearance_page_demo-importer .demo-importer h1{margin-bottom:15px}.appearance_page_demo-importer .demo-importer .wp-filter-search{position:relative;top:-2px;left:20px;margin:0;width:280px;font-size:16px;font-weight:300;line-height:1.5}.appearance_page_demo-importer .demo-installer .wp-filter{padding:0 20px}.appearance_page_demo-importer .demo-installer .wp-filter .filter-links li>a:focus{box-shadow:none}.appearance_page_demo-importer .demo-installer .welcome-panel{margin:0}table.plugins-list-table{margin-bottom:1em}table.plugins-list-table tr:nth-child(2n) td{background:#fcfcfc}table.plugins-list-table th{padding:9px;font-weight:600}table.plugins-list-table td{padding:9px;font-size:1.1em}table.plugins-list-table td mark{background:0 0}table.plugins-list-table td mark.yes{color:#7ad03a}table.plugins-list-table td mark.no{color:#999}table.plugins-list-table td mark.error{color:#a00}.tips{cursor:help;text-decoration:none}img.tips{padding:5px 0 0}#tiptip_holder{display:none;position:absolute;top:0;left:0;z-index:9999999}#tiptip_holder.tip_top{padding-bottom:5px}#tiptip_holder.tip_top #tiptip_arrow_inner{margin-top:-7px;margin-left:-6px;border-top-color:#333}#tiptip_holder.tip_bottom{padding-top:5px}#tiptip_holder.tip_bottom #tiptip_arrow_inner{margin-top:-5px;margin-left:-6px;border-bottom-color:#333}#tiptip_holder.tip_right{padding-left:5px}#tiptip_holder.tip_right #tiptip_arrow_inner{margin-top:-6px;margin-left:-5px;border-right-color:#333}#tiptip_holder.tip_left{padding-right:5px}#tiptip_holder.tip_left #tiptip_arrow_inner{margin-top:-6px;margin-left:-7px;border-left-color:#333}#tiptip_content{color:#fff;font-size:.8em;max-width:150px;background:#333;border-radius:3px;padding:.618em 1em;box-shadow:0 1px 3px rgba(0,0,0,.2)}#tiptip_content code{padding:1px;background:#888}#tiptip_arrow,#tiptip_arrow_inner{position:absolute;border-color:transparent;border-style:solid;border-width:6px;height:0;width:0}
assets/css/demo-importer.scss CHANGED
@@ -1,68 +1,87 @@
1
  /**
2
- * Styling begins.
 
3
  */
4
- .appearance_page_demo-importer .wp-filter {
5
- padding: 0 20px;
6
 
7
- .filter-links li > a:focus {
8
- box-shadow: none;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
  }
10
- }
11
 
12
- .theme-browser .theme .theme-actions span.spinner {
13
- display: none;
14
- }
15
 
16
- .theme-browser .theme .theme-actions.imported,
17
- .theme-browser .theme .theme-actions.importing {
18
- opacity: 1;
19
- }
20
 
21
- .theme-browser .theme .theme-actions.imported .button,
22
- .theme-browser .theme .theme-actions.importing .button,
23
- .theme-browser .theme:not( .active ) .theme-actions .preview {
24
- display: none;
25
- visibility: hidden;
26
  }
27
 
28
- .theme-browser .theme:not( .active ) .theme-actions.imported .preview {
29
- display: block;
30
- visibility: visible;
31
- }
32
 
33
- .theme-browser .theme .theme-actions.importing span.spinner.is-active {
34
- width: auto;
35
- display: block;
36
- font-size: 12px;
37
- padding-right: 25px;
38
- background-position: right center;
39
- }
40
 
41
- @media only screen and (max-width: 780px) {
42
- .theme-browser .theme .theme-actions.imported {
43
- opacity: 0;
44
  }
45
- }
46
 
47
- /* Position admin messages */
48
- .theme .notice,
49
- .theme .notice.is-dismissible {
50
- left: 0;
51
- margin: 0;
52
- position: absolute;
53
- right: 0;
54
- top: 0;
55
- }
56
 
57
- .theme .notice-success p::before {
58
- color: #79ba49;
59
- content: '\f147';
60
- margin-right: 6px;
61
- vertical-align: top;
62
- display: inline-block;
63
- font: normal 20px/1 'dashicons';
64
- -webkit-font-smoothing: antialiased;
65
- -moz-osx-font-smoothing: grayscale;
 
 
 
 
 
 
 
66
  }
67
 
68
  /**
1
  /**
2
+ * demo-importer.scss
3
+ * General ThemeGrill Demo Importer admin styles.
4
  */
 
 
5
 
6
+ /**
7
+ * Imports
8
+ */
9
+ @import 'bourbon';
10
+
11
+ /**
12
+ * Styling begins
13
+ */
14
+ .appearance_page_demo-importer {
15
+ .demo-importer {
16
+ h1 {
17
+ margin-bottom: 15px;
18
+ }
19
+
20
+ .wp-filter-search {
21
+ position: relative;
22
+ top: -2px;
23
+ left: 20px;
24
+ margin: 0;
25
+ width: 280px;
26
+ font-size: 16px;
27
+ font-weight: 300;
28
+ line-height: 1.5;
29
+ }
30
  }
 
31
 
32
+ .demo-installer {
33
+ .wp-filter {
34
+ padding: 0 20px;
35
 
36
+ .filter-links li > a:focus {
37
+ box-shadow: none;
38
+ }
39
+ }
40
 
41
+ .welcome-panel {
42
+ margin: 0;
43
+ }
44
+ }
 
45
  }
46
 
47
+ table.plugins-list-table {
48
+ margin-bottom: 1em;
 
 
49
 
50
+ tr:nth-child( 2n ) {
51
+ td {
52
+ background: #fcfcfc;
53
+ }
54
+ }
 
 
55
 
56
+ th {
57
+ padding: 9px;
58
+ font-weight: 600;
59
  }
 
60
 
61
+ td {
62
+ padding: 9px;
63
+ font-size: 1.1em;
64
+
65
+ mark {
66
+ background: transparent none;
67
+ }
 
 
68
 
69
+ mark.yes {
70
+ color: #7ad03a;
71
+ }
72
+
73
+ mark.no {
74
+ color: #999;
75
+ }
76
+
77
+ mark.error {
78
+ color: #a00;
79
+ }
80
+ }
81
+
82
+ .plugin-status {
83
+ text-align: center;
84
+ }
85
  }
86
 
87
  /**
assets/js/admin/demo-importer.js CHANGED
@@ -1,96 +1,1224 @@
1
- /* global demo_importer_params */
2
- jQuery( function ( $ ) {
3
-
4
- var tg_demo_importer = {
5
- init: function() {
6
- this.uploader();
7
- this.init_tiptip();
8
-
9
- // Trigger importer events.
10
- $( '.theme-actions' ).on( 'click', '.import', this.process_import );
11
- $( '.notice.is-dismissible' ).on( 'click', '.notice-dismiss', this.dismiss_notice );
12
- },
13
- uploader: function() {
14
- var uploadViewToggle = $( '.upload-view-toggle' ),
15
- $body = $( document.body );
16
-
17
- uploadViewToggle.on( 'click', function() {
18
- // Toggle the upload view.
19
- $body.toggleClass( 'show-upload-view' );
20
- // Toggle the `aria-expanded` button attribute.
21
- uploadViewToggle.attr( 'aria-expanded', $body.hasClass( 'show-upload-view' ) );
22
- });
23
- },
24
- init_tiptip: function() {
25
- $( '#tiptip_holder' ).removeAttr( 'style' );
26
- $( '#tiptip_arrow' ).removeAttr( 'style' );
27
- $( '.tips' ).tipTip({ 'attribute': 'data-tip', 'fadeIn': 50, 'fadeOut': 50, 'delay': 200 });
28
- },
29
- process_import: function( e ) {
30
- e.preventDefault();
31
-
32
- var $this_el = $( this );
33
-
34
- if ( ! $this_el.hasClass( 'disabled' ) ) {
35
- if ( window.confirm( demo_importer_params.i18n_import_dummy_data ) ) {
36
-
37
- var data = {
38
- action: 'tg_import_demo_data',
39
- demo_id: $this_el.data( 'demo_id' ),
40
- security: demo_importer_params.import_demo_data_nonce
41
- };
42
-
43
- $.ajax({
44
- url: demo_importer_params.ajax_url,
45
- data: data,
46
- type: 'POST',
47
- beforeSend: function() {
48
- $this_el.parent().addClass( 'importing' );
49
- $this_el.parent().find( '.spinner' ).addClass( 'is-active' );
50
- },
51
- success: function( response ) {
52
- $this_el.closest( '.theme' ).find( '.notice' ).remove();
53
- $this_el.parent().find( '.spinner' ).removeClass( 'is-active' );
54
- $this_el.parent().removeClass( 'importing' ).addClass( 'imported' );
55
-
56
- // Display import message.
57
- if ( true === response.success ) {
58
- $this_el.closest( '.theme' ).append( '<div class="notice notice-success notice-alt"><p>' + response.data.message + '</p></div>' );
59
- } else {
60
- $this_el.closest( '.theme' ).append( '<div class="update-message notice notice-error notice-alt"><p>' + demo_importer_params.i18n_import_data_error + '</p></div>' );
61
- }
62
- },
63
- error: function( jqXHR, textStatus, errorThrown ) {
64
- $this_el.closest( '.theme' ).find( '.notice' ).remove();
65
- $this_el.parent().find( '.spinner' ).removeClass( 'is-active' );
66
- $this_el.parent().removeClass( 'importing' ).addClass( 'imported' );
67
-
68
- // Display error message.
69
- $this_el.closest( '.theme' ).append( '<div class="update-message notice notice-error notice-alt"><p>' + errorThrown + '</p></div>' );
70
- }
71
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
73
 
74
- return false;
 
 
75
  }
76
- },
77
- dismiss_notice: function( e ) {
78
- e.preventDefault();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
 
80
- var $this_el = $( this );
 
 
81
 
82
- if ( $this_el.parent().attr( 'id' ) === 'undefined' ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
83
  return;
84
  }
85
 
86
- $.post( demo_importer_params.ajax_url, {
87
- action: 'tg_dismiss_notice',
88
- notice_id: $this_el.parent().data( 'notice_id' )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
89
  });
90
 
91
- return false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
  }
93
- };
94
 
95
- tg_demo_importer.init();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* global demoImporterLocalizeScript */
2
+ window.wp = window.wp || {};
3
+
4
+ ( function( $ ) {
5
+
6
+ // Set up our namespace...
7
+ var demos, l10n;
8
+ demos = wp.demos = wp.demos || {};
9
+
10
+ // Store the demo data and settings for organized and quick access
11
+ // demos.data.settings, demos.data.demos, demos.data.l10n
12
+ demos.data = demoImporterLocalizeScript;
13
+ l10n = demos.data.l10n;
14
+
15
+ // Shortcut for isPreview check
16
+ demos.isPreview = !! demos.data.settings.isPreview;
17
+
18
+ // Shortcut for isInstall check
19
+ demos.isInstall = !! demos.data.settings.isInstall;
20
+
21
+ // Setup app structure
22
+ _.extend( demos, { model: {}, view: {}, routes: {}, router: {}, template: wp.template });
23
+
24
+ demos.Model = Backbone.Model.extend({
25
+ // Adds attributes to the default data coming through the .org demos api
26
+ // Map `id` to `slug` for shared code
27
+ initialize: function() {
28
+ var description;
29
+
30
+ // If demo is already installed, set an attribute.
31
+ if ( _.indexOf( demos.data.installedDemos, this.get( 'slug' ) ) !== -1 ) {
32
+ this.set({ installed: true });
33
+ }
34
+
35
+ // Set the attributes
36
+ this.set({
37
+ // slug is for installation, id is for existing.
38
+ id: this.get( 'slug' ) || this.get( 'id' )
39
+ });
40
+
41
+ // Map `section.description` to `description`
42
+ // as the API sometimes returns it differently
43
+ if ( this.has( 'sections' ) ) {
44
+ description = this.get( 'sections' ).description;
45
+ this.set({ description: description });
46
+ }
47
+ }
48
+ });
49
+
50
+ // Main view controller for demo importer
51
+ // Unifies and renders all available views
52
+ demos.view.Appearance = wp.Backbone.View.extend({
53
+
54
+ el: '#wpbody-content .wrap .theme-browser',
55
+
56
+ window: $( window ),
57
+ // Pagination instance
58
+ page: 0,
59
+
60
+ // Sets up a throttler for binding to 'scroll'
61
+ initialize: function( options ) {
62
+ // Scroller checks how far the scroll position is
63
+ _.bindAll( this, 'scroller' );
64
+
65
+ this.SearchView = options.SearchView ? options.SearchView : demos.view.Search;
66
+ // Bind to the scroll event and throttle
67
+ // the results from this.scroller
68
+ this.window.bind( 'scroll', _.throttle( this.scroller, 300 ) );
69
+ },
70
+
71
+ // Main render control
72
+ render: function() {
73
+ // Setup the main demo view
74
+ // with the current demo collection
75
+ this.view = new demos.view.Demos({
76
+ collection: this.collection,
77
+ parent: this
78
+ });
79
+
80
+ // Render search form.
81
+ this.search();
82
+
83
+ // Render and append
84
+ this.view.render();
85
+ this.$el.empty().append( this.view.el ).addClass( 'rendered' );
86
+ },
87
+
88
+ // Defines search element container
89
+ searchContainer: $( '#wpbody h1:first' ),
90
+
91
+ // Search input and view
92
+ // for current demo collection
93
+ search: function() {
94
+ var view,
95
+ self = this;
96
+
97
+ // Don't render the search if there is only one demo
98
+ if ( demos.data.demos.length === 1 ) {
99
+ return;
100
+ }
101
+
102
+ view = new this.SearchView({
103
+ collection: self.collection,
104
+ parent: this
105
+ });
106
+
107
+ // Render and append after screen title
108
+ view.render();
109
+ this.searchContainer
110
+ .append( $.parseHTML( '<label class="screen-reader-text" for="wp-filter-search-input">' + l10n.search + '</label>' ) )
111
+ .append( view.el );
112
+ },
113
+
114
+ // Checks when the user gets close to the bottom
115
+ // of the mage and triggers a demo:scroll event
116
+ scroller: function() {
117
+ var self = this,
118
+ bottom, threshold;
119
+
120
+ bottom = this.window.scrollTop() + self.window.height();
121
+ threshold = self.$el.offset().top + self.$el.outerHeight( false ) - self.window.height();
122
+ threshold = Math.round( threshold * 0.9 );
123
+
124
+ if ( bottom > threshold ) {
125
+ this.trigger( 'demo:scroll' );
126
+ }
127
+ },
128
+
129
+ // Remove any lingering tooltips and initialize TipTip
130
+ initTipTip: function() {
131
+ $( '#tiptip_holder' ).removeAttr( 'style' );
132
+ $( '#tiptip_arrow' ).removeAttr( 'style' );
133
+ $( '.tips' ).tipTip({ 'attribute': 'data-tip', 'fadeIn': 50, 'fadeOut': 50, 'delay': 50 });
134
+ }
135
+ });
136
+
137
+ // Set up the Collection for our demo data
138
+ // @has 'id' 'name' 'screenshot' 'author' 'authorURI' 'version' 'active' ...
139
+ demos.Collection = Backbone.Collection.extend({
140
+
141
+ model: demos.Model,
142
+
143
+ // Search terms
144
+ terms: '',
145
+
146
+ // Controls searching on the current theme collection
147
+ // and triggers an update event
148
+ doSearch: function( value ) {
149
+
150
+ // Don't do anything if we've already done this search
151
+ // Useful because the Search handler fires multiple times per keystroke
152
+ if ( this.terms === value ) {
153
+ return;
154
+ }
155
+
156
+ // Updates terms with the value passed
157
+ this.terms = value;
158
+
159
+ // If we have terms, run a search...
160
+ if ( this.terms.length > 0 ) {
161
+ this.search( this.terms );
162
+ }
163
+
164
+ // If search is blank, show all demos
165
+ // Useful for resetting the views when you clean the input
166
+ if ( this.terms === '' ) {
167
+ this.reset( demos.data.demos );
168
+ $( 'body' ).removeClass( 'no-results' );
169
+ }
170
+
171
+ // Trigger a 'demos:update' event
172
+ this.trigger( 'demos:update' );
173
+ },
174
+
175
+ // Performs a search within the collection
176
+ // @uses RegExp
177
+ search: function( term ) {
178
+ var match, results, haystack, name, description, author;
179
+
180
+ // Start with a full collection
181
+ this.reset( demos.data.demos, { silent: true } );
182
+
183
+ // Escape the term string for RegExp meta characters
184
+ term = term.replace( /[-\/\\^$*+?.()|[\]{}]/g, '\\$&' );
185
+
186
+ // Consider spaces as word delimiters and match the whole string
187
+ // so matching terms can be combined
188
+ term = term.replace( / /g, ')(?=.*' );
189
+ match = new RegExp( '^(?=.*' + term + ').+', 'i' );
190
+
191
+ // Find results
192
+ // _.filter and .test
193
+ results = this.filter( function( data ) {
194
+ name = data.get( 'name' ).replace( /(<([^>]+)>)/ig, '' );
195
+ description = data.get( 'description' ).replace( /(<([^>]+)>)/ig, '' );
196
+ author = data.get( 'author' ).replace( /(<([^>]+)>)/ig, '' );
197
+
198
+ haystack = _.union( [ name, data.get( 'id' ), description, author, data.get( 'tags' ) ] );
199
+
200
+ if ( match.test( data.get( 'author' ) ) && term.length > 2 ) {
201
+ data.set( 'displayAuthor', true );
202
+ }
203
+
204
+ return match.test( haystack );
205
+ });
206
+
207
+ if ( results.length === 0 ) {
208
+ this.trigger( 'query:empty' );
209
+ } else {
210
+ $( 'body' ).removeClass( 'no-results' );
211
+ }
212
+
213
+ this.reset( results );
214
+ },
215
+
216
+ // Paginates the collection with a helper method
217
+ // that slices the collection
218
+ paginate: function( instance ) {
219
+ var collection = this;
220
+ instance = instance || 0;
221
+
222
+ // Demos per instance are set at 20
223
+ collection = _( collection.rest( 20 * instance ) );
224
+ collection = _( collection.first( 20 ) );
225
+
226
+ return collection;
227
+ }
228
+ });
229
+
230
+ // This is the view that controls each demo item
231
+ // that will be displayed on the screen
232
+ demos.view.Demo = wp.Backbone.View.extend({
233
+
234
+ // Wrap demo data on a div.theme element
235
+ className: 'theme',
236
+
237
+ // Reflects which demo view we have
238
+ // 'grid' (default) or 'detail'
239
+ state: 'grid',
240
+
241
+ // The HTML template for each element to be rendered
242
+ html: demos.template( demos.isPreview ? 'demo-preview' : 'demo' ),
243
+
244
+ events: {
245
+ 'click': 'expand',
246
+ 'keydown': 'expand',
247
+ 'touchend': 'expand',
248
+ 'keyup': 'addFocus',
249
+ 'touchmove': 'preventExpand',
250
+ 'click .demo-import': 'importDemo'
251
+ },
252
+
253
+ touchDrag: false,
254
+
255
+ initialize: function() {
256
+ this.model.on( 'change', this.render, this );
257
+ },
258
+
259
+ render: function() {
260
+ var data = this.model.toJSON();
261
+
262
+ // Render demos using the html template
263
+ this.$el.html( this.html( data ) ).attr({
264
+ tabindex: 0,
265
+ 'aria-describedby' : data.id + '-action ' + data.id + '-name',
266
+ 'data-slug': data.id
267
+ });
268
+
269
+ // Renders active demo styles
270
+ this.activeDemo();
271
+
272
+ if ( this.model.get( 'displayAuthor' ) ) {
273
+ this.$el.addClass( 'display-author' );
274
+ }
275
+ },
276
+
277
+ // Adds a class to the currently active demo
278
+ // and to the overlay in detailed view mode
279
+ activeDemo: function() {
280
+ if ( this.model.get( 'active' ) ) {
281
+ this.$el.addClass( 'active' );
282
+ }
283
+ },
284
+
285
+ // Add class of focus to the demo we are focused on.
286
+ addFocus: function() {
287
+ var $demoToFocus = ( $( ':focus' ).hasClass( 'theme' ) ) ? $( ':focus' ) : $(':focus').parents('.theme');
288
+
289
+ $('.theme.focus').removeClass('focus');
290
+ $demoToFocus.addClass('focus');
291
+ },
292
+
293
+ // Single theme overlay screen
294
+ // It's shown when clicking a theme
295
+ expand: function( event ) {
296
+ var self = this;
297
+
298
+ // Prevent the modal.
299
+ if ( demos.isPreview ) {
300
+ return;
301
+ }
302
+
303
+ event = event || window.event;
304
+
305
+ // 'enter' and 'space' keys expand the details view when a theme is :focused
306
+ if ( event.type === 'keydown' && ( event.which !== 13 && event.which !== 32 ) ) {
307
+ return;
308
+ }
309
+
310
+ // Bail if the user scrolled on a touch device
311
+ if ( this.touchDrag === true ) {
312
+ return this.touchDrag = false;
313
+ }
314
+
315
+ // Prevent the modal from showing when the user clicks
316
+ // one of the direct action buttons
317
+ if ( $( event.target ).is( '.theme-actions a' ) ) {
318
+ return;
319
+ }
320
+
321
+ // Prevent the modal from showing when the user clicks one of the direct action buttons.
322
+ if ( $( event.target ).is( '.theme-actions a, .update-message, .button-link, .notice-dismiss' ) ) {
323
+ return;
324
+ }
325
+
326
+ // Set focused demo to current element
327
+ demos.focusedDemo = this.$el;
328
+
329
+ this.trigger( 'demo:expand', self.model.cid );
330
+ },
331
+
332
+ preventExpand: function() {
333
+ this.touchDrag = true;
334
+ },
335
+
336
+ importDemo: function() {
337
+ var _this = this,
338
+ $target = $( event.target );
339
+ event.preventDefault();
340
+
341
+ if ( $target.hasClass( 'disabled' ) ) {
342
+ return;
343
+ }
344
+
345
+ // Confirmation dialog for importing a demo.
346
+ if ( ! window.confirm( wp.demos.data.settings.confirmImport ) ) {
347
+ return;
348
+ }
349
+
350
+ $( document ).on( 'wp-demo-import-success', function( event, response ) {
351
+ if ( _this.model.get( 'id' ) === response.slug ) {
352
+ _this.model.set( { 'imported': true } );
353
+ }
354
+ } );
355
+
356
+ wp.updates.importDemo( {
357
+ slug: $target.data( 'slug' )
358
+ } );
359
+ }
360
+ });
361
+
362
+ // Demo Details view
363
+ // Set ups a modal overlay with the expanded demo data
364
+ demos.view.Details = wp.Backbone.View.extend({
365
+
366
+ // Wrap theme data on a div.theme element
367
+ className: 'theme-overlay',
368
+
369
+ events: {
370
+ 'click': 'collapse',
371
+ 'click .delete-demo': 'deleteDemo',
372
+ 'click .left': 'previousDemo',
373
+ 'click .right': 'nextDemo',
374
+ 'click .demo-import': 'importDemo'
375
+ },
376
+
377
+ // The HTML template for the theme overlay
378
+ html: demos.template( 'demo-single' ),
379
+
380
+ render: function() {
381
+ var data = this.model.toJSON();
382
+ this.$el.html( this.html( data ) );
383
+ // Renders active theme styles
384
+ this.activeDemo();
385
+ // Set up navigation events
386
+ this.navigation();
387
+ // Checks screenshot size
388
+ this.screenshotCheck( this.$el );
389
+ // Contain "tabbing" inside the overlay
390
+ this.containFocus( this.$el );
391
+ },
392
+
393
+ // Adds a class to the currently active theme
394
+ // and to the overlay in detailed view mode
395
+ activeDemo: function() {
396
+ // Check the model has the active property
397
+ this.$el.toggleClass( 'active', this.model.get( 'active' ) );
398
+ },
399
+
400
+ // Set initial focus and constrain tabbing within the theme browser modal.
401
+ containFocus: function( $el ) {
402
+
403
+ // Set initial focus on the primary action control.
404
+ _.delay( function() {
405
+ $( '.theme-wrap a.button-primary:visible' ).focus();
406
+ }, 100 );
407
+
408
+ // Constrain tabbing within the modal.
409
+ $el.on( 'keydown.wp-themes', function( event ) {
410
+ var $firstFocusable = $el.find( '.theme-header button:not(.disabled)' ).first(),
411
+ $lastFocusable = $el.find( '.theme-actions a:visible' ).last();
412
+
413
+ // Check for the Tab key.
414
+ if ( 9 === event.which ) {
415
+ if ( $firstFocusable[0] === event.target && event.shiftKey ) {
416
+ $lastFocusable.focus();
417
+ event.preventDefault();
418
+ } else if ( $lastFocusable[0] === event.target && ! event.shiftKey ) {
419
+ $firstFocusable.focus();
420
+ event.preventDefault();
421
+ }
422
+ }
423
+ });
424
+ },
425
+
426
+ // Single demo overlay screen
427
+ // It's shown when clicking a demo
428
+ collapse: function( event ) {
429
+ var self = this,
430
+ scroll;
431
+
432
+ event = event || window.event;
433
+
434
+ // Prevent collapsing detailed view when there is only one demo available
435
+ if ( demos.data.demos.length === 1 ) {
436
+ return;
437
+ }
438
+
439
+ // Detect if the click is inside the overlay
440
+ // and don't close it unless the target was
441
+ // the div.back button
442
+ if ( $( event.target ).is( '.theme-backdrop' ) || $( event.target ).is( '.close' ) || event.keyCode === 27 ) {
443
+
444
+ // Add a temporary closing class while overlay fades out
445
+ $( 'body' ).addClass( 'closing-overlay' );
446
+
447
+ // With a quick fade out animation
448
+ this.$el.fadeOut( 130, function() {
449
+ // Clicking outside the modal box closes the overlay
450
+ $( 'body' ).removeClass( 'closing-overlay' );
451
+ // Handle event cleanup
452
+ self.closeOverlay();
453
+
454
+ // Get scroll position to avoid jumping to the top
455
+ scroll = document.body.scrollTop;
456
+
457
+ // Clean the url structure
458
+ demos.router.navigate( demos.router.baseUrl( '' ) );
459
+
460
+ // Restore scroll position
461
+ document.body.scrollTop = scroll;
462
+
463
+ // Return focus to the demo div
464
+ if ( demos.focusedDemo ) {
465
+ demos.focusedDemo.focus();
466
  }
467
+ });
468
+ }
469
+ },
470
+
471
+ // Handles .disabled classes for next/previous buttons
472
+ navigation: function() {
473
+
474
+ // Disable Left/Right when at the start or end of the collection
475
+ if ( this.model.cid === this.model.collection.at(0).cid ) {
476
+ this.$el.find( '.left' )
477
+ .addClass( 'disabled' )
478
+ .prop( 'disabled', true );
479
+ }
480
+ if ( this.model.cid === this.model.collection.at( this.model.collection.length - 1 ).cid ) {
481
+ this.$el.find( '.right' )
482
+ .addClass( 'disabled' )
483
+ .prop( 'disabled', true );
484
+ }
485
+ },
486
+
487
+ // Performs the actions to effectively close
488
+ // the demo details overlay
489
+ closeOverlay: function() {
490
+ $( 'body' ).removeClass( 'modal-open' );
491
+ this.remove();
492
+ this.unbind();
493
+ this.trigger( 'demo:collapse' );
494
+ },
495
+
496
+ importDemo: function() {
497
+ var _this = this,
498
+ $target = $( event.target );
499
+ event.preventDefault();
500
+
501
+ if ( $target.hasClass( 'disabled' ) ) {
502
+ return;
503
+ }
504
+
505
+ // Confirmation dialog for importing a demo.
506
+ if ( ! window.confirm( wp.demos.data.settings.confirmImport ) ) {
507
+ return;
508
+ }
509
 
510
+ $( document ).on( 'wp-demo-import-success', function( event, response ) {
511
+ if ( _this.model.get( 'id' ) === response.slug ) {
512
+ _this.model.set( { 'imported': true } );
513
  }
514
+ } );
515
+
516
+ // Handle a demo queue job.
517
+ $( document ).on( 'wp-updates-queue-job', function( event, job ) {
518
+ if ( 'import-demo' === job.action ) {
519
+ wp.updates.importDemo( job.data );
520
+ }
521
+ } );
522
+
523
+ wp.updates.importDemo( {
524
+ slug: $target.data( 'slug' )
525
+ } );
526
+ },
527
+
528
+ deleteDemo: function( event ) {
529
+ var _this = this,
530
+ _collection = this.model.collection,
531
+ _demos = demos;
532
+ event.preventDefault();
533
+
534
+ // Confirmation dialog for deleting a demo.
535
+ if ( ! window.confirm( wp.demos.data.settings.confirmDelete ) ) {
536
+ return;
537
+ }
538
+
539
+ wp.updates.maybeRequestFilesystemCredentials( event );
540
+
541
+ $( document ).one( 'wp-demo-delete-success', function( event, response ) {
542
+ _this.$el.find( '.close' ).trigger( 'click' );
543
+ $( '[data-slug="' + response.slug + '"' ).css( { backgroundColor:'#faafaa' } ).fadeOut( 350, function() {
544
+ $( this ).remove();
545
+ _demos.data.demos = _.without( _demos.data.demos, _.findWhere( _demos.data.demos, { id: response.slug } ) );
546
+
547
+ $( '.wp-filter-search' ).val( '' );
548
+ _collection.doSearch( '' );
549
+ _collection.remove( _this.model );
550
+ _collection.trigger( 'demos:update' );
551
+ } );
552
+ } );
553
+
554
+ wp.updates.deleteDemo( {
555
+ slug: this.model.get( 'id' )
556
+ } );
557
+ },
558
+
559
+ nextDemo: function() {
560
+ var self = this;
561
+ self.trigger( 'demo:next', self.model.cid );
562
+ return false;
563
+ },
564
+
565
+ previousDemo: function() {
566
+ var self = this;
567
+ self.trigger( 'demo:previous', self.model.cid );
568
+ return false;
569
+ },
570
+
571
+ // Checks if the theme screenshot is the old 300px width version
572
+ // and adds a corresponding class if it's true
573
+ screenshotCheck: function( el ) {
574
+ var screenshot, image;
575
+
576
+ screenshot = el.find( '.screenshot img' );
577
+ image = new Image();
578
+ image.src = screenshot.attr( 'src' );
579
+
580
+ // Width check
581
+ if ( image.width && image.width <= 300 ) {
582
+ el.addClass( 'small-screenshot' );
583
+ }
584
+ }
585
+ });
586
+
587
+ // Controls the rendering of div.themes,
588
+ // a wrapper that will hold all the theme elements
589
+ demos.view.Demos = wp.Backbone.View.extend({
590
+
591
+ className: 'themes wp-clearfix',
592
+ $overlay: $( 'div.theme-overlay' ),
593
 
594
+ // Number to keep track of scroll position
595
+ // while in theme-overlay mode
596
+ index: 0,
597
 
598
+ // The demo count element
599
+ count: $( '.wrap .demo-count' ),
600
+
601
+ // The live demos count
602
+ liveDemoCount: 0,
603
+
604
+ initialize: function( options ) {
605
+ var self = this;
606
+
607
+ // Set up parent
608
+ this.parent = options.parent;
609
+
610
+ // Move the imported demo to the beginning of the collection
611
+ self.importedDemo();
612
+
613
+ // Set current view to [grid]
614
+ this.setView( 'grid' );
615
+
616
+ // When the collection is updated by user input...
617
+ this.listenTo( self.collection, 'demos:update', function() {
618
+ self.parent.page = 0;
619
+ self.importedDemo();
620
+ self.render( this );
621
+ self.parent.initTipTip();
622
+ } );
623
+
624
+ // Update demo count to full result set when available.
625
+ this.listenTo( self.collection, 'query:success', function( count ) {
626
+ if ( _.isNumber( count ) ) {
627
+ self.count.text( count );
628
+ self.announceSearchResults( count );
629
+ } else {
630
+ self.count.text( self.collection.length );
631
+ self.announceSearchResults( self.collection.length );
632
+ }
633
+ });
634
+
635
+ this.listenTo( self.collection, 'query:empty', function() {
636
+ $( 'body' ).addClass( 'no-results' );
637
+ });
638
+
639
+ this.listenTo( this.parent, 'demo:scroll', function() {
640
+ self.renderDemos( self.parent.page );
641
+ });
642
+
643
+ this.listenTo( this.parent, 'demo:close', function() {
644
+ if ( self.overlay ) {
645
+ self.overlay.closeOverlay();
646
+ }
647
+ } );
648
+
649
+ // Bind keyboard events.
650
+ $( 'body' ).on( 'keyup', function( event ) {
651
+ if ( ! self.overlay ) {
652
+ return;
653
+ }
654
+
655
+ // Bail if the filesystem credentials dialog is shown.
656
+ if ( $( '#request-filesystem-credentials-dialog' ).is( ':visible' ) ) {
657
  return;
658
  }
659
 
660
+ // Pressing the right arrow key fires a demo:next event
661
+ if ( event.keyCode === 39 ) {
662
+ self.overlay.nextDemo();
663
+ }
664
+
665
+ // Pressing the left arrow key fires a demo:previous event
666
+ if ( event.keyCode === 37 ) {
667
+ self.overlay.previousDemo();
668
+ }
669
+
670
+ // Pressing the escape key fires a demo:collapse event
671
+ if ( event.keyCode === 27 ) {
672
+ self.overlay.collapse( event );
673
+ }
674
+ });
675
+ },
676
+
677
+ // Manages rendering of demo pages
678
+ // and keeping demo count in sync
679
+ render: function() {
680
+ // Clear the DOM, please
681
+ this.$el.empty();
682
+
683
+ // If the user doesn't have switch capabilities
684
+ // or there is only one demo in the collection
685
+ // render the detailed view of the active demo
686
+ if ( ! demos.isPreview && demos.data.demos.length === 1 ) {
687
+
688
+ // Constructs the view
689
+ this.singleDemo = new demos.view.Details({
690
+ model: this.collection.models[0]
691
  });
692
 
693
+ // Render and apply a 'single-theme' class to our container
694
+ this.singleDemo.render();
695
+ this.$el.addClass( 'single-theme' );
696
+ this.$el.append( this.singleDemo.el );
697
+ }
698
+
699
+ // Generate the demos
700
+ // Using page instance
701
+ // While checking the collection has items
702
+ if ( this.options.collection.size() > 0 ) {
703
+ this.renderDemos( this.parent.page );
704
+ }
705
+
706
+ // Display a live demo count for the collection
707
+ this.liveDemoCount = this.collection.count ? this.collection.count : this.collection.length;
708
+ this.count.text( this.liveDemoCount );
709
+ },
710
+
711
+ // Iterates through each instance of the collection
712
+ // and renders each theme module
713
+ renderDemos: function( page ) {
714
+ var self = this;
715
+
716
+ self.instance = self.collection.paginate( page );
717
+
718
+ // If we have no more demos bail
719
+ if ( self.instance.size() === 0 ) {
720
+ // Fire a no-more-demos event.
721
+ this.parent.trigger( 'demo:end' );
722
+ return;
723
+ }
724
+
725
+ // Loop through the demos and setup each demo view
726
+ self.instance.each( function( demo ) {
727
+ self.demo = new demos.view.Demo({
728
+ model: demo,
729
+ parent: self
730
+ });
731
+
732
+ // Render the views...
733
+ self.demo.render();
734
+ // and append them to div.themes
735
+ self.$el.append( self.demo.el );
736
+
737
+ // Binds to demo:expand to show the modal box
738
+ // with the demo details
739
+ self.listenTo( self.demo, 'demo:expand', self.expand, self );
740
+ });
741
+
742
+ // 'Add new demo' element shown at the end of the grid
743
+ if ( ! demos.isPreview && demos.isInstall && demos.data.settings.canInstall ) {
744
+ this.$el.append( '<div class="theme add-new-theme"><a href="' + demos.data.settings.installURI + '"><div class="theme-screenshot"><span></span></div><h2 class="theme-name">' + l10n.addNew + '</h2></a></div>' );
745
+ }
746
+
747
+ this.parent.page++;
748
+ },
749
+
750
+ // Grabs imported demo and puts it at the beginning of the collection
751
+ importedDemo: function() {
752
+ var self = this,
753
+ current;
754
+
755
+ current = self.collection.findWhere({ active: true });
756
+
757
+ // Move the imported demo to the beginning of the collection
758
+ if ( current ) {
759
+ self.collection.remove( current );
760
+ self.collection.add( current, { at:0 } );
761
+ }
762
+ },
763
+
764
+ // Sets current view
765
+ setView: function( view ) {
766
+ return view;
767
+ },
768
+
769
+ // Renders the overlay with the DemoDetails view
770
+ // Uses the current model data
771
+ expand: function( id ) {
772
+ var self = this, $card, $modal;
773
+
774
+ // Set the current demo model
775
+ this.model = self.collection.get( id );
776
+
777
+ // Trigger a route update for the current model
778
+ demos.router.navigate( demos.router.baseUrl( demos.router.demoPath + this.model.id ) );
779
+
780
+ // Sets this.view to 'detail'
781
+ this.setView( 'detail' );
782
+ $( 'body' ).addClass( 'modal-open' );
783
+
784
+ // Set up the demo details view
785
+ this.overlay = new demos.view.Details({
786
+ model: self.model
787
+ });
788
+
789
+ this.overlay.render();
790
+
791
+ if ( this.model.get( 'hasUpdate' ) ) {
792
+ $card = $( '[data-slug="' + this.model.id + '"]' );
793
+ $modal = $( this.overlay.el );
794
+
795
+ if ( $card.find( '.updating-message' ).length ) {
796
+ $modal.find( '.notice-warning h3' ).remove();
797
+ $modal.find( '.notice-warning' )
798
+ .removeClass( 'notice-large' )
799
+ .addClass( 'updating-message' )
800
+ .find( 'p' ).text( wp.updates.l10n.updating );
801
+ } else if ( $card.find( '.notice-error' ).length ) {
802
+ $modal.find( '.notice-warning' ).remove();
803
+ }
804
  }
 
805
 
806
+ this.$overlay.html( this.overlay.el );
807
+
808
+ // Bind to demo:next and demo:previous
809
+ // triggered by the arrow keys
810
+ //
811
+ // Keep track of the current model so we
812
+ // can infer an index position
813
+ this.listenTo( this.overlay, 'demo:next', function() {
814
+ // Renders the next demo on the overlay
815
+ self.next( [ self.model.cid ] );
816
+
817
+ })
818
+ .listenTo( this.overlay, 'demo:previous', function() {
819
+ // Renders the previous demo on the overlay
820
+ self.previous( [ self.model.cid ] );
821
+ });
822
+ },
823
+
824
+ // This method renders the next demo on the overlay modal
825
+ // based on the current position in the collection
826
+ // @params [model cid]
827
+ next: function( args ) {
828
+ var self = this,
829
+ model, nextModel;
830
+
831
+ // Get the current demo
832
+ model = self.collection.get( args[0] );
833
+ // Find the next model within the collection
834
+ nextModel = self.collection.at( self.collection.indexOf( model ) + 1 );
835
+
836
+ // Sanity check which also serves as a boundary test
837
+ if ( nextModel !== undefined ) {
838
+
839
+ // We have a new demo...
840
+ // Close the overlay
841
+ this.overlay.closeOverlay();
842
+
843
+ // Trigger a route update for the current model
844
+ self.demo.trigger( 'demo:expand', nextModel.cid );
845
+ }
846
+ },
847
+
848
+ // This method renders the previous demo on the overlay modal
849
+ // based on the current position in the collection
850
+ // @params [model cid]
851
+ previous: function( args ) {
852
+ var self = this,
853
+ model, previousModel;
854
+
855
+ // Get the current demo
856
+ model = self.collection.get( args[0] );
857
+ // Find the previous model within the collection
858
+ previousModel = self.collection.at( self.collection.indexOf( model ) - 1 );
859
+
860
+ if ( previousModel !== undefined ) {
861
+
862
+ // We have a new demo...
863
+ // Close the overlay
864
+ this.overlay.closeOverlay();
865
+
866
+ // Trigger a route update for the current model
867
+ self.demo.trigger( 'demo:expand', previousModel.cid );
868
+ }
869
+ },
870
+
871
+ // Dispatch audible search results feedback message
872
+ announceSearchResults: function( count ) {
873
+ if ( 0 === count ) {
874
+ wp.a11y.speak( l10n.noDemosFound );
875
+ } else {
876
+ wp.a11y.speak( l10n.demosFound.replace( '%d', count ) );
877
+ }
878
+ }
879
  });
880
+
881
+ // Search input view controller.
882
+ demos.view.Search = wp.Backbone.View.extend({
883
+
884
+ tagName: 'input',
885
+ className: 'wp-filter-search',
886
+ id: 'wp-filter-search-input',
887
+ searching: false,
888
+
889
+ attributes: {
890
+ placeholder: l10n.searchPlaceholder,
891
+ type: 'search',
892
+ 'aria-describedby': 'live-search-desc'
893
+ },
894
+
895
+ events: {
896
+ 'input': 'search',
897
+ 'keyup': 'search',
898
+ 'blur': 'pushState'
899
+ },
900
+
901
+ initialize: function( options ) {
902
+
903
+ this.parent = options.parent;
904
+
905
+ this.listenTo( this.parent, 'demo:close', function() {
906
+ this.searching = false;
907
+ } );
908
+ },
909
+
910
+ search: function( event ) {
911
+ // Clear on escape.
912
+ if ( event.type === 'keyup' && event.which === 27 ) {
913
+ event.target.value = '';
914
+ }
915
+
916
+ /**
917
+ * Since doSearch is debounced, it will only run when user input comes to a rest
918
+ */
919
+ this.doSearch( event );
920
+ },
921
+
922
+ // Runs a search on the demo collection.
923
+ doSearch: _.debounce( function( event ) {
924
+ var options = {};
925
+
926
+ this.collection.doSearch( event.target.value );
927
+
928
+ // if search is initiated and key is not return
929
+ if ( this.searching && event.which !== 13 ) {
930
+ options.replace = true;
931
+ } else {
932
+ this.searching = true;
933
+ }
934
+
935
+ // Update the URL hash
936
+ if ( event.target.value ) {
937
+ demos.router.navigate( demos.router.baseUrl( demos.router.searchPath + event.target.value ), options );
938
+ } else {
939
+ demos.router.navigate( demos.router.baseUrl( '' ) );
940
+ }
941
+ }, 500 ),
942
+
943
+ pushState: function( event ) {
944
+ var url = demos.router.baseUrl( '' );
945
+
946
+ if ( event.target.value ) {
947
+ url = demos.router.baseUrl( demos.router.searchPath + event.target.value );
948
+ }
949
+
950
+ this.searching = false;
951
+ demos.router.navigate( url );
952
+ }
953
+ });
954
+
955
+ // Sets up the routes events for relevant url queries
956
+ // Listens to [demo] and [search] params
957
+ demos.Router = Backbone.Router.extend({
958
+
959
+ routes: {
960
+ 'themes.php?page=demo-importer&demo=:slug': 'demo',
961
+ 'themes.php?page=demo-importer&search=:query': 'search',
962
+ 'themes.php?page=demo-importer&s=:query': 'search',
963
+ 'themes.php?page=demo-importer': 'demos',
964
+ '': 'demos'
965
+ },
966
+
967
+ baseUrl: function( url ) {
968
+ return 'themes.php?page=demo-importer' + url;
969
+ },
970
+
971
+ demoPath: '&demo=',
972
+ searchPath: '&search=',
973
+
974
+ search: function( query ) {
975
+ $( '.wp-filter-search' ).val( query );
976
+ },
977
+
978
+ demos: function() {
979
+ $( '.wp-filter-search' ).val( '' );
980
+ },
981
+
982
+ navigate: function() {
983
+ if ( Backbone.history._hasPushState ) {
984
+ Backbone.Router.prototype.navigate.apply( this, arguments );
985
+ }
986
+ }
987
+ });
988
+
989
+ // Execute and setup the application
990
+ demos.Run = {
991
+ init: function() {
992
+ // Initializes the blog's demo library view
993
+ // Create a new collection with data
994
+ this.demos = new demos.Collection( demos.data.demos );
995
+
996
+ // Set up the view
997
+ this.view = new demos.view.Appearance({
998
+ collection: this.demos
999
+ });
1000
+
1001
+ this.render();
1002
+ },
1003
+
1004
+ render: function() {
1005
+
1006
+ // Render results
1007
+ this.view.render();
1008
+ this.view.initTipTip();
1009
+ this.routes();
1010
+
1011
+ Backbone.history.start({
1012
+ root: demos.data.settings.adminUrl,
1013
+ pushState: true,
1014
+ hashChange: false
1015
+ });
1016
+ },
1017
+
1018
+ routes: function() {
1019
+ var self = this;
1020
+ // Bind to our global thx object
1021
+ // so that the object is available to sub-views
1022
+ demos.router = new demos.Router();
1023
+
1024
+ // Handles demo details route event
1025
+ demos.router.on( 'route:demo', function( slug ) {
1026
+ self.view.view.expand( slug );
1027
+ });
1028
+
1029
+ demos.router.on( 'route:demos', function() {
1030
+ self.demos.doSearch( '' );
1031
+ self.view.trigger( 'demo:close' );
1032
+ });
1033
+
1034
+ // Handles search route event
1035
+ demos.router.on( 'route:search', function() {
1036
+ $( '.wp-filter-search' ).trigger( 'keyup' );
1037
+ });
1038
+
1039
+ this.extraRoutes();
1040
+ },
1041
+
1042
+ extraRoutes: function() {
1043
+ return false;
1044
+ }
1045
+ };
1046
+
1047
+ demos.view.Installer = demos.view.Appearance.extend({
1048
+
1049
+ el: '#wpbody-content .wrap',
1050
+
1051
+ // Initial render method
1052
+ render: function() {
1053
+ this.search();
1054
+ this.uploader();
1055
+
1056
+ // Setup the main demo view
1057
+ // with the current demo collection
1058
+ this.view = new demos.view.Demos({
1059
+ collection: this.collection,
1060
+ parent: this
1061
+ });
1062
+
1063
+ // Render and append
1064
+ this.$el.find( '.themes' ).remove();
1065
+ this.view.render();
1066
+ this.$el.find( '.theme-browser' ).append( this.view.el ).addClass( 'rendered' );
1067
+ },
1068
+
1069
+ // Overwrite search container class to append search
1070
+ // in new location
1071
+ searchContainer: $( '.wp-filter .search-form' ),
1072
+
1073
+ /*
1074
+ * When users press the "Upload Theme" button, show the upload form in place.
1075
+ */
1076
+ uploader: function() {
1077
+ var uploadViewToggle = $( '.upload-view-toggle' ),
1078
+ $body = $( document.body );
1079
+
1080
+ uploadViewToggle.on( 'click', function() {
1081
+ // Toggle the upload view.
1082
+ $body.toggleClass( 'show-upload-view' );
1083
+ // Toggle the `aria-expanded` button attribute.
1084
+ uploadViewToggle.attr( 'aria-expanded', $body.hasClass( 'show-upload-view' ) );
1085
+ });
1086
+ },
1087
+
1088
+ clearSearch: function() {
1089
+ $( '#wp-filter-search-input').val( '' );
1090
+ }
1091
+ });
1092
+
1093
+ demos.InstallerRouter = Backbone.Router.extend({
1094
+
1095
+ routes: {
1096
+ 'themes.php?page=demo-importer&browse=uploads&demo=:slug': 'demo',
1097
+ 'themes.php?page=demo-importer&browse=:sort&search=:query': 'search',
1098
+ 'themes.php?page=demo-importer&browse=:sort&s=:query': 'search',
1099
+ 'themes.php?page=demo-importer&browse=welcome': 'sort',
1100
+ 'themes.php?page=demo-importer&browse=:sort': 'demos',
1101
+ 'themes.php?page=demo-importer': 'sort'
1102
+ },
1103
+
1104
+ browse: function() {
1105
+ return demos.isPreview ? 'preview' : 'uploads';
1106
+ },
1107
+
1108
+ baseUrl: function( url ) {
1109
+ return 'themes.php?page=demo-importer&browse=' + this.browse() + url;
1110
+ },
1111
+
1112
+ demoPath: '&demo=',
1113
+ searchPath: '&search=',
1114
+
1115
+ search: function( sort, query ) {
1116
+ $( '.wp-filter-search' ).val( query );
1117
+ },
1118
+
1119
+ demos: function() {
1120
+ $( '.wp-filter-search' ).val( '' );
1121
+ },
1122
+
1123
+ navigate: function() {
1124
+ if ( Backbone.history._hasPushState ) {
1125
+ Backbone.Router.prototype.navigate.apply( this, arguments );
1126
+ }
1127
+ }
1128
+ });
1129
+
1130
+ demos.RunInstaller = {
1131
+
1132
+ init: function() {
1133
+ // Initializes the blog's demo library view
1134
+ // Create a new collection with data
1135
+ this.demos = new demos.Collection( demos.data.demos );
1136
+
1137
+ // Set up the view
1138
+ this.view = new demos.view.Installer({
1139
+ collection: this.demos
1140
+ });
1141
+
1142
+ this.render();
1143
+ },
1144
+
1145
+ render: function() {
1146
+
1147
+ // Render results
1148
+ this.view.render();
1149
+ this.view.initTipTip();
1150
+ this.routes();
1151
+
1152
+ Backbone.history.start({
1153
+ root: demos.data.settings.adminUrl,
1154
+ pushState: true,
1155
+ hashChange: false
1156
+ });
1157
+ },
1158
+
1159
+ routes: function() {
1160
+ var self = this;
1161
+ // Bind to our global thx object
1162
+ // so that the object is available to sub-views
1163
+ demos.router = new demos.InstallerRouter();
1164
+
1165
+ // Handles demo details route event
1166
+ demos.router.on( 'route:demo', function( slug ) {
1167
+ self.view.view.expand( slug );
1168
+ });
1169
+
1170
+ demos.router.on( 'route:demos', function() {
1171
+ self.demos.doSearch( '' );
1172
+ self.view.trigger( 'demo:close' );
1173
+ });
1174
+
1175
+ // Handles sorting / browsing routes
1176
+ // Also handles the root URL triggering a sort request
1177
+ // for `welcome`, the default view
1178
+ demos.router.on( 'route:sort', function( sort ) {
1179
+ if ( ! sort || 'welcome' === sort ) {
1180
+ $( '.wp-filter-search' ).hide();
1181
+ }
1182
+ });
1183
+
1184
+ // The `search` route event. The router populates the input field.
1185
+ demos.router.on( 'route:search', function() {
1186
+ $( '.wp-filter-search' ).focus().trigger( 'keyup' );
1187
+ });
1188
+
1189
+ this.extraRoutes();
1190
+ },
1191
+
1192
+ extraRoutes: function() {
1193
+ return false;
1194
+ }
1195
+ };
1196
+
1197
+ // Ready...
1198
+ $( document ).ready( function() {
1199
+ if ( demos.isInstall ) {
1200
+ demos.RunInstaller.init();
1201
+ } else {
1202
+ demos.Run.init();
1203
+ }
1204
+
1205
+ // Dismissible notice.
1206
+ $( '.notice.is-dismissible' ).on( 'click', '.notice-dismiss', function( event ) {
1207
+ var $this_el = $( this );
1208
+
1209
+ event.preventDefault();
1210
+
1211
+ if ( $this_el.parent().attr( 'id' ) === 'undefined' ) {
1212
+ return;
1213
+ }
1214
+
1215
+ $.post( demos.data.settings.ajaxUrl, {
1216
+ action: 'dismiss-notice',
1217
+ notice_id: $this_el.parent().data( 'notice_id' )
1218
+ });
1219
+
1220
+ return false;
1221
+ } );
1222
+ });
1223
+
1224
+ })( jQuery );
assets/js/admin/demo-importer.min.js CHANGED
@@ -1 +1 @@
1
- jQuery(function(a){var b={init:function(){this.uploader(),this.init_tiptip(),a(".theme-actions").on("click",".import",this.process_import),a(".notice.is-dismissible").on("click",".notice-dismiss",this.dismiss_notice)},uploader:function(){var b=a(".upload-view-toggle"),c=a(document.body);b.on("click",function(){c.toggleClass("show-upload-view"),b.attr("aria-expanded",c.hasClass("show-upload-view"))})},init_tiptip:function(){a("#tiptip_holder").removeAttr("style"),a("#tiptip_arrow").removeAttr("style"),a(".tips").tipTip({attribute:"data-tip",fadeIn:50,fadeOut:50,delay:200})},process_import:function(b){b.preventDefault();var c=a(this);if(!c.hasClass("disabled")){if(window.confirm(demo_importer_params.i18n_import_dummy_data)){var d={action:"tg_import_demo_data",demo_id:c.data("demo_id"),security:demo_importer_params.import_demo_data_nonce};a.ajax({url:demo_importer_params.ajax_url,data:d,type:"POST",beforeSend:function(){c.parent().addClass("importing"),c.parent().find(".spinner").addClass("is-active")},success:function(a){c.closest(".theme").find(".notice").remove(),c.parent().find(".spinner").removeClass("is-active"),c.parent().removeClass("importing").addClass("imported"),!0===a.success?c.closest(".theme").append('<div class="notice notice-success notice-alt"><p>'+a.data.message+"</p></div>"):c.closest(".theme").append('<div class="update-message notice notice-error notice-alt"><p>'+demo_importer_params.i18n_import_data_error+"</p></div>")},error:function(a,b,d){c.closest(".theme").find(".notice").remove(),c.parent().find(".spinner").removeClass("is-active"),c.parent().removeClass("importing").addClass("imported"),c.closest(".theme").append('<div class="update-message notice notice-error notice-alt"><p>'+d+"</p></div>")}})}return!1}},dismiss_notice:function(b){b.preventDefault();var c=a(this);if("undefined"!==c.parent().attr("id"))return a.post(demo_importer_params.ajax_url,{action:"tg_dismiss_notice",notice_id:c.parent().data("notice_id")}),!1}};b.init()});
1
+ window.wp=window.wp||{},function(a){var b,c;b=wp.demos=wp.demos||{},b.data=demoImporterLocalizeScript,c=b.data.l10n,b.isPreview=!!b.data.settings.isPreview,b.isInstall=!!b.data.settings.isInstall,_.extend(b,{model:{},view:{},routes:{},router:{},template:wp.template}),b.Model=Backbone.Model.extend({initialize:function(){var a;_.indexOf(b.data.installedDemos,this.get("slug"))!==-1&&this.set({installed:!0}),this.set({id:this.get("slug")||this.get("id")}),this.has("sections")&&(a=this.get("sections").description,this.set({description:a}))}}),b.view.Appearance=wp.Backbone.View.extend({el:"#wpbody-content .wrap .theme-browser",window:a(window),page:0,initialize:function(a){_.bindAll(this,"scroller"),this.SearchView=a.SearchView?a.SearchView:b.view.Search,this.window.bind("scroll",_.throttle(this.scroller,300))},render:function(){this.view=new b.view.Demos({collection:this.collection,parent:this}),this.search(),this.view.render(),this.$el.empty().append(this.view.el).addClass("rendered")},searchContainer:a("#wpbody h1:first"),search:function(){var d,e=this;1!==b.data.demos.length&&(d=new this.SearchView({collection:e.collection,parent:this}),d.render(),this.searchContainer.append(a.parseHTML('<label class="screen-reader-text" for="wp-filter-search-input">'+c.search+"</label>")).append(d.el))},scroller:function(){var a,b,c=this;a=this.window.scrollTop()+c.window.height(),b=c.$el.offset().top+c.$el.outerHeight(!1)-c.window.height(),b=Math.round(.9*b),a>b&&this.trigger("demo:scroll")},initTipTip:function(){a("#tiptip_holder").removeAttr("style"),a("#tiptip_arrow").removeAttr("style"),a(".tips").tipTip({attribute:"data-tip",fadeIn:50,fadeOut:50,delay:50})}}),b.Collection=Backbone.Collection.extend({model:b.Model,terms:"",doSearch:function(c){this.terms!==c&&(this.terms=c,this.terms.length>0&&this.search(this.terms),""===this.terms&&(this.reset(b.data.demos),a("body").removeClass("no-results")),this.trigger("demos:update"))},search:function(c){var d,e,f,g,h,i;this.reset(b.data.demos,{silent:!0}),c=c.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&"),c=c.replace(/ /g,")(?=.*"),d=new RegExp("^(?=.*"+c+").+","i"),e=this.filter(function(a){return g=a.get("name").replace(/(<([^>]+)>)/gi,""),h=a.get("description").replace(/(<([^>]+)>)/gi,""),i=a.get("author").replace(/(<([^>]+)>)/gi,""),f=_.union([g,a.get("id"),h,i,a.get("tags")]),d.test(a.get("author"))&&c.length>2&&a.set("displayAuthor",!0),d.test(f)}),0===e.length?this.trigger("query:empty"):a("body").removeClass("no-results"),this.reset(e)},paginate:function(a){var b=this;return a=a||0,b=_(b.rest(20*a)),b=_(b.first(20))}}),b.view.Demo=wp.Backbone.View.extend({className:"theme",state:"grid",html:b.template(b.isPreview?"demo-preview":"demo"),events:{click:"expand",keydown:"expand",touchend:"expand",keyup:"addFocus",touchmove:"preventExpand","click .demo-import":"importDemo"},touchDrag:!1,initialize:function(){this.model.on("change",this.render,this)},render:function(){var a=this.model.toJSON();this.$el.html(this.html(a)).attr({tabindex:0,"aria-describedby":a.id+"-action "+a.id+"-name","data-slug":a.id}),this.activeDemo(),this.model.get("displayAuthor")&&this.$el.addClass("display-author")},activeDemo:function(){this.model.get("active")&&this.$el.addClass("active")},addFocus:function(){var b=a(":focus").hasClass("theme")?a(":focus"):a(":focus").parents(".theme");a(".theme.focus").removeClass("focus"),b.addClass("focus")},expand:function(c){var d=this;if(!b.isPreview&&(c=c||window.event,"keydown"!==c.type||13===c.which||32===c.which))return this.touchDrag===!0?this.touchDrag=!1:void(a(c.target).is(".theme-actions a")||a(c.target).is(".theme-actions a, .update-message, .button-link, .notice-dismiss")||(b.focusedDemo=this.$el,this.trigger("demo:expand",d.model.cid)))},preventExpand:function(){this.touchDrag=!0},importDemo:function(){var b=this,c=a(event.target);event.preventDefault(),c.hasClass("disabled")||window.confirm(wp.demos.data.settings.confirmImport)&&(a(document).on("wp-demo-import-success",function(a,c){b.model.get("id")===c.slug&&b.model.set({imported:!0})}),wp.updates.importDemo({slug:c.data("slug")}))}}),b.view.Details=wp.Backbone.View.extend({className:"theme-overlay",events:{click:"collapse","click .delete-demo":"deleteDemo","click .left":"previousDemo","click .right":"nextDemo","click .demo-import":"importDemo"},html:b.template("demo-single"),render:function(){var a=this.model.toJSON();this.$el.html(this.html(a)),this.activeDemo(),this.navigation(),this.screenshotCheck(this.$el),this.containFocus(this.$el)},activeDemo:function(){this.$el.toggleClass("active",this.model.get("active"))},containFocus:function(b){_.delay(function(){a(".theme-wrap a.button-primary:visible").focus()},100),b.on("keydown.wp-themes",function(a){var c=b.find(".theme-header button:not(.disabled)").first(),d=b.find(".theme-actions a:visible").last();9===a.which&&(c[0]===a.target&&a.shiftKey?(d.focus(),a.preventDefault()):d[0]!==a.target||a.shiftKey||(c.focus(),a.preventDefault()))})},collapse:function(c){var d,e=this;c=c||window.event,1!==b.data.demos.length&&(a(c.target).is(".theme-backdrop")||a(c.target).is(".close")||27===c.keyCode)&&(a("body").addClass("closing-overlay"),this.$el.fadeOut(130,function(){a("body").removeClass("closing-overlay"),e.closeOverlay(),d=document.body.scrollTop,b.router.navigate(b.router.baseUrl("")),document.body.scrollTop=d,b.focusedDemo&&b.focusedDemo.focus()}))},navigation:function(){this.model.cid===this.model.collection.at(0).cid&&this.$el.find(".left").addClass("disabled").prop("disabled",!0),this.model.cid===this.model.collection.at(this.model.collection.length-1).cid&&this.$el.find(".right").addClass("disabled").prop("disabled",!0)},closeOverlay:function(){a("body").removeClass("modal-open"),this.remove(),this.unbind(),this.trigger("demo:collapse")},importDemo:function(){var b=this,c=a(event.target);event.preventDefault(),c.hasClass("disabled")||window.confirm(wp.demos.data.settings.confirmImport)&&(a(document).on("wp-demo-import-success",function(a,c){b.model.get("id")===c.slug&&b.model.set({imported:!0})}),a(document).on("wp-updates-queue-job",function(a,b){"import-demo"===b.action&&wp.updates.importDemo(b.data)}),wp.updates.importDemo({slug:c.data("slug")}))},deleteDemo:function(c){var d=this,e=this.model.collection,f=b;c.preventDefault(),window.confirm(wp.demos.data.settings.confirmDelete)&&(wp.updates.maybeRequestFilesystemCredentials(c),a(document).one("wp-demo-delete-success",function(b,c){d.$el.find(".close").trigger("click"),a('[data-slug="'+c.slug+'"').css({backgroundColor:"#faafaa"}).fadeOut(350,function(){a(this).remove(),f.data.demos=_.without(f.data.demos,_.findWhere(f.data.demos,{id:c.slug})),a(".wp-filter-search").val(""),e.doSearch(""),e.remove(d.model),e.trigger("demos:update")})}),wp.updates.deleteDemo({slug:this.model.get("id")}))},nextDemo:function(){var a=this;return a.trigger("demo:next",a.model.cid),!1},previousDemo:function(){var a=this;return a.trigger("demo:previous",a.model.cid),!1},screenshotCheck:function(a){var b,c;b=a.find(".screenshot img"),c=new Image,c.src=b.attr("src"),c.width&&c.width<=300&&a.addClass("small-screenshot")}}),b.view.Demos=wp.Backbone.View.extend({className:"themes wp-clearfix",$overlay:a("div.theme-overlay"),index:0,count:a(".wrap .demo-count"),liveDemoCount:0,initialize:function(b){var c=this;this.parent=b.parent,c.importedDemo(),this.setView("grid"),this.listenTo(c.collection,"demos:update",function(){c.parent.page=0,c.importedDemo(),c.render(this),c.parent.initTipTip()}),this.listenTo(c.collection,"query:success",function(a){_.isNumber(a)?(c.count.text(a),c.announceSearchResults(a)):(c.count.text(c.collection.length),c.announceSearchResults(c.collection.length))}),this.listenTo(c.collection,"query:empty",function(){a("body").addClass("no-results")}),this.listenTo(this.parent,"demo:scroll",function(){c.renderDemos(c.parent.page)}),this.listenTo(this.parent,"demo:close",function(){c.overlay&&c.overlay.closeOverlay()}),a("body").on("keyup",function(b){c.overlay&&(a("#request-filesystem-credentials-dialog").is(":visible")||(39===b.keyCode&&c.overlay.nextDemo(),37===b.keyCode&&c.overlay.previousDemo(),27===b.keyCode&&c.overlay.collapse(b)))})},render:function(){this.$el.empty(),b.isPreview||1!==b.data.demos.length||(this.singleDemo=new b.view.Details({model:this.collection.models[0]}),this.singleDemo.render(),this.$el.addClass("single-theme"),this.$el.append(this.singleDemo.el)),this.options.collection.size()>0&&this.renderDemos(this.parent.page),this.liveDemoCount=this.collection.count?this.collection.count:this.collection.length,this.count.text(this.liveDemoCount)},renderDemos:function(a){var d=this;return d.instance=d.collection.paginate(a),0===d.instance.size()?void this.parent.trigger("demo:end"):(d.instance.each(function(a){d.demo=new b.view.Demo({model:a,parent:d}),d.demo.render(),d.$el.append(d.demo.el),d.listenTo(d.demo,"demo:expand",d.expand,d)}),!b.isPreview&&b.isInstall&&b.data.settings.canInstall&&this.$el.append('<div class="theme add-new-theme"><a href="'+b.data.settings.installURI+'"><div class="theme-screenshot"><span></span></div><h2 class="theme-name">'+c.addNew+"</h2></a></div>"),void this.parent.page++)},importedDemo:function(){var a,b=this;a=b.collection.findWhere({active:!0}),a&&(b.collection.remove(a),b.collection.add(a,{at:0}))},setView:function(a){return a},expand:function(c){var d,e,f=this;this.model=f.collection.get(c),b.router.navigate(b.router.baseUrl(b.router.demoPath+this.model.id)),this.setView("detail"),a("body").addClass("modal-open"),this.overlay=new b.view.Details({model:f.model}),this.overlay.render(),this.model.get("hasUpdate")&&(d=a('[data-slug="'+this.model.id+'"]'),e=a(this.overlay.el),d.find(".updating-message").length?(e.find(".notice-warning h3").remove(),e.find(".notice-warning").removeClass("notice-large").addClass("updating-message").find("p").text(wp.updates.l10n.updating)):d.find(".notice-error").length&&e.find(".notice-warning").remove()),this.$overlay.html(this.overlay.el),this.listenTo(this.overlay,"demo:next",function(){f.next([f.model.cid])}).listenTo(this.overlay,"demo:previous",function(){f.previous([f.model.cid])})},next:function(a){var b,c,d=this;b=d.collection.get(a[0]),c=d.collection.at(d.collection.indexOf(b)+1),void 0!==c&&(this.overlay.closeOverlay(),d.demo.trigger("demo:expand",c.cid))},previous:function(a){var b,c,d=this;b=d.collection.get(a[0]),c=d.collection.at(d.collection.indexOf(b)-1),void 0!==c&&(this.overlay.closeOverlay(),d.demo.trigger("demo:expand",c.cid))},announceSearchResults:function(a){0===a?wp.a11y.speak(c.noDemosFound):wp.a11y.speak(c.demosFound.replace("%d",a))}}),b.view.Search=wp.Backbone.View.extend({tagName:"input",className:"wp-filter-search",id:"wp-filter-search-input",searching:!1,attributes:{placeholder:c.searchPlaceholder,type:"search","aria-describedby":"live-search-desc"},events:{input:"search",keyup:"search",blur:"pushState"},initialize:function(a){this.parent=a.parent,this.listenTo(this.parent,"demo:close",function(){this.searching=!1})},search:function(a){"keyup"===a.type&&27===a.which&&(a.target.value=""),this.doSearch(a)},doSearch:_.debounce(function(a){var c={};this.collection.doSearch(a.target.value),this.searching&&13!==a.which?c.replace=!0:this.searching=!0,a.target.value?b.router.navigate(b.router.baseUrl(b.router.searchPath+a.target.value),c):b.router.navigate(b.router.baseUrl(""))},500),pushState:function(a){var c=b.router.baseUrl("");a.target.value&&(c=b.router.baseUrl(b.router.searchPath+a.target.value)),this.searching=!1,b.router.navigate(c)}}),b.Router=Backbone.Router.extend({routes:{"themes.php?page=demo-importer&demo=:slug":"demo","themes.php?page=demo-importer&search=:query":"search","themes.php?page=demo-importer&s=:query":"search","themes.php?page=demo-importer":"demos","":"demos"},baseUrl:function(a){return"themes.php?page=demo-importer"+a},demoPath:"&demo=",searchPath:"&search=",search:function(b){a(".wp-filter-search").val(b)},demos:function(){a(".wp-filter-search").val("")},navigate:function(){Backbone.history._hasPushState&&Backbone.Router.prototype.navigate.apply(this,arguments)}}),b.Run={init:function(){this.demos=new b.Collection(b.data.demos),this.view=new b.view.Appearance({collection:this.demos}),this.render()},render:function(){this.view.render(),this.view.initTipTip(),this.routes(),Backbone.history.start({root:b.data.settings.adminUrl,pushState:!0,hashChange:!1})},routes:function(){var c=this;b.router=new b.Router,b.router.on("route:demo",function(a){c.view.view.expand(a)}),b.router.on("route:demos",function(){c.demos.doSearch(""),c.view.trigger("demo:close")}),b.router.on("route:search",function(){a(".wp-filter-search").trigger("keyup")}),this.extraRoutes()},extraRoutes:function(){return!1}},b.view.Installer=b.view.Appearance.extend({el:"#wpbody-content .wrap",render:function(){this.search(),this.uploader(),this.view=new b.view.Demos({collection:this.collection,parent:this}),this.$el.find(".themes").remove(),this.view.render(),this.$el.find(".theme-browser").append(this.view.el).addClass("rendered")},searchContainer:a(".wp-filter .search-form"),uploader:function(){var b=a(".upload-view-toggle"),c=a(document.body);b.on("click",function(){c.toggleClass("show-upload-view"),b.attr("aria-expanded",c.hasClass("show-upload-view"))})},clearSearch:function(){a("#wp-filter-search-input").val("")}}),b.InstallerRouter=Backbone.Router.extend({routes:{"themes.php?page=demo-importer&browse=uploads&demo=:slug":"demo","themes.php?page=demo-importer&browse=:sort&search=:query":"search","themes.php?page=demo-importer&browse=:sort&s=:query":"search","themes.php?page=demo-importer&browse=welcome":"sort","themes.php?page=demo-importer&browse=:sort":"demos","themes.php?page=demo-importer":"sort"},browse:function(){return b.isPreview?"preview":"uploads"},baseUrl:function(a){return"themes.php?page=demo-importer&browse="+this.browse()+a},demoPath:"&demo=",searchPath:"&search=",search:function(b,c){a(".wp-filter-search").val(c)},demos:function(){a(".wp-filter-search").val("")},navigate:function(){Backbone.history._hasPushState&&Backbone.Router.prototype.navigate.apply(this,arguments)}}),b.RunInstaller={init:function(){this.demos=new b.Collection(b.data.demos),this.view=new b.view.Installer({collection:this.demos}),this.render()},render:function(){this.view.render(),this.view.initTipTip(),this.routes(),Backbone.history.start({root:b.data.settings.adminUrl,pushState:!0,hashChange:!1})},routes:function(){var c=this;b.router=new b.InstallerRouter,b.router.on("route:demo",function(a){c.view.view.expand(a)}),b.router.on("route:demos",function(){c.demos.doSearch(""),c.view.trigger("demo:close")}),b.router.on("route:sort",function(b){b&&"welcome"!==b||a(".wp-filter-search").hide()}),b.router.on("route:search",function(){a(".wp-filter-search").focus().trigger("keyup")}),this.extraRoutes()},extraRoutes:function(){return!1}},a(document).ready(function(){b.isInstall?b.RunInstaller.init():b.Run.init(),a(".notice.is-dismissible").on("click",".notice-dismiss",function(c){var d=a(this);if(c.preventDefault(),"undefined"!==d.parent().attr("id"))return a.post(b.data.settings.ajaxUrl,{action:"dismiss-notice",notice_id:d.parent().data("notice_id")}),!1})})}(jQuery);
assets/js/admin/demo-updates.js ADDED
@@ -0,0 +1,305 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ( function( $, wp, settings ) {
2
+ var $document = $( document );
3
+
4
+ wp = wp || {};
5
+
6
+ /**
7
+ * The WP Updates object.
8
+ *
9
+ * @type {object}
10
+ */
11
+ wp.updates = wp.updates || {};
12
+
13
+ /**
14
+ * Localized strings.
15
+ *
16
+ * @type {object}
17
+ */
18
+ wp.updates.l10n = _.extend( wp.updates.l10n, settings.l10n || {} );
19
+
20
+ /**
21
+ * Sends an Ajax request to the server to import a demo.
22
+ *
23
+ * @param {object} args
24
+ * @param {string} args.slug Demo ID.
25
+ * @param {importDemoSuccess=} args.success Optional. Success callback. Default: wp.updates.importDemoSuccess
26
+ * @param {importDemoError=} args.error Optional. Error callback. Default: wp.updates.importDemoError
27
+ * @return {$.promise} A jQuery promise that represents the request,
28
+ * decorated with an abort() method.
29
+ */
30
+ wp.updates.importDemo = function( args ) {
31
+ var $message = $( '.demo-import[data-slug="' + args.slug + '"]' );
32
+
33
+ args = _.extend( {
34
+ success: wp.updates.importDemoSuccess,
35
+ error: wp.updates.importDemoError
36
+ }, args );
37
+
38
+ $message.addClass( 'updating-message' );
39
+ $message.parents( '.theme' ).addClass( 'focus' );
40
+ if ( $message.html() !== wp.updates.l10n.importing ) {
41
+ $message.data( 'originaltext', $message.html() );
42
+ }
43
+
44
+ $message
45
+ .text( wp.updates.l10n.importing )
46
+ .attr( 'aria-label', wp.updates.l10n.demoImportingLabel.replace( '%s', $message.data( 'name' ) ) );
47
+ wp.a11y.speak( wp.updates.l10n.importingMsg, 'polite' );
48
+
49
+ // Remove previous error messages, if any.
50
+ $( '.theme-info .theme-description, [data-slug="' + args.slug + '"]' ).removeClass( 'demo-import-failed' ).find( '.notice.notice-error' ).remove();
51
+
52
+ $document.trigger( 'wp-demo-importing', args );
53
+
54
+ return wp.updates.ajax( 'import-demo', args );
55
+ };
56
+
57
+ /**
58
+ * Updates the UI appropriately after a successful demo import.
59
+ *
60
+ * @typedef {object} importDemoSuccess
61
+ * @param {object} response Response from the server.
62
+ * @param {string} response.slug Slug of the demo that was imported.
63
+ * @param {string} response.previewUrl URL to preview the just imported demo.
64
+ */
65
+ wp.updates.importDemoSuccess = function( response ) {
66
+ var $card = $( '.theme-overlay, [data-slug=' + response.slug + ']' ),
67
+ $message;
68
+
69
+ $document.trigger( 'wp-demo-import-success', response );
70
+
71
+ $message = $card.find( '.button-primary' )
72
+ .removeClass( 'updating-message' )
73
+ .addClass( 'updated-message disabled' )
74
+ .attr( 'aria-label', wp.updates.l10n.demoImportedLabel.replace( '%s', response.demoName ) )
75
+ .text( wp.updates.l10n.imported );
76
+
77
+ wp.a11y.speak( wp.updates.l10n.importedMsg, 'polite' );
78
+
79
+ setTimeout( function() {
80
+
81
+ if ( response.previewUrl ) {
82
+
83
+ // Remove the 'Preview' button.
84
+ $message.siblings( '.demo-preview' ).remove();
85
+
86
+ // Transform the 'Import' button into an 'Live Preview' button.
87
+ $message
88
+ .attr( 'target', '_blank' )
89
+ .attr( 'href', response.previewUrl )
90
+ .removeClass( 'demo-import updated-message disabled' )
91
+ .addClass( 'live-preview' )
92
+ .attr( 'aria-label', wp.updates.l10n.livePreviewLabel.replace( '%s', response.demoName ) )
93
+ .text( wp.updates.l10n.livePreview );
94
+ }
95
+ }, 1000 );
96
+ };
97
+
98
+ /**
99
+ * Updates the UI appropriately after a failed demo import.
100
+ *
101
+ * @typedef {object} importDemoError
102
+ * @param {object} response Response from the server.
103
+ * @param {string} response.slug Slug of the demo to be imported.
104
+ * @param {string} response.errorCode Error code for the error that occurred.
105
+ * @param {string} response.errorMessage The error that occurred.
106
+ */
107
+ wp.updates.importDemoError = function( response ) {
108
+ var $card, $button,
109
+ errorMessage = wp.updates.l10n.importFailed.replace( '%s', response.errorMessage ),
110
+ $message = wp.updates.adminNotice( {
111
+ className: 'update-message notice-error notice-alt',
112
+ message: errorMessage
113
+ } );
114
+
115
+ if ( ! wp.updates.isValidResponse( response, 'import' ) ) {
116
+ return;
117
+ }
118
+
119
+ if ( $document.find( 'body' ).hasClass( 'modal-open' ) || $document.find( '.themes' ).hasClass( 'single-theme' ) ) {
120
+ $button = $( '.demo-import[data-slug="' + response.slug + '"]' );
121
+ $card = $( '.theme-info .theme-description' ).prepend( $message );
122
+ } else {
123
+ $card = $( '[data-slug="' + response.slug + '"]' ).removeClass( 'focus' ).addClass( 'demo-import-failed' ).append( $message );
124
+ $button = $card.find( '.demo-import' );
125
+ }
126
+
127
+ $button
128
+ .removeClass( 'updating-message' )
129
+ .attr( 'aria-label', wp.updates.l10n.demoImportFailedLabel.replace( '%s', $button.data( 'name' ) ) )
130
+ .text( wp.updates.l10n.importFailedShort );
131
+
132
+ wp.a11y.speak( errorMessage, 'assertive' );
133
+
134
+ $document.trigger( 'wp-demo-import-error', response );
135
+ };
136
+
137
+ /**
138
+ * Sends an Ajax request to the server to delete a demo.
139
+ *
140
+ * @param {object} args
141
+ * @param {string} args.slug Demo ID.
142
+ * @param {deleteDemoSuccess=} args.success Optional. Success callback. Default: wp.updates.deleteDemoSuccess
143
+ * @param {deleteDemoError=} args.error Optional. Error callback. Default: wp.updates.deleteDemoError
144
+ * @return {$.promise} A jQuery promise that represents the request,
145
+ * decorated with an abort() method.
146
+ */
147
+ wp.updates.deleteDemo = function( args ) {
148
+ var $button = $( '.theme-actions .delete-demo' );
149
+
150
+ args = _.extend( {
151
+ success: wp.updates.deleteDemoSuccess,
152
+ error: wp.updates.deleteDemoError
153
+ }, args );
154
+
155
+ if ( $button && $button.html() !== wp.updates.l10n.deleting ) {
156
+ $button
157
+ .data( 'originaltext', $button.html() )
158
+ .text( wp.updates.l10n.deleting );
159
+ }
160
+
161
+ wp.a11y.speak( wp.updates.l10n.deleting, 'polite' );
162
+
163
+ // Remove previous error messages, if any.
164
+ $( '.theme-info .update-message' ).remove();
165
+
166
+ $document.trigger( 'wp-demo-deleting', args );
167
+
168
+ return wp.updates.ajax( 'delete-demo', args );
169
+ };
170
+
171
+ /**
172
+ * Updates the UI appropriately after a successful demo deletion.
173
+ *
174
+ * @typedef {object} deleteDemoSuccess
175
+ * @param {object} response Response from the server.
176
+ * @param {string} response.slug Slug of the demo that was deleted.
177
+ */
178
+ wp.updates.deleteDemoSuccess = function( response ) {
179
+ wp.a11y.speak( wp.updates.l10n.deleted, 'polite' );
180
+
181
+ $document.trigger( 'wp-demo-delete-success', response );
182
+ };
183
+
184
+ /**
185
+ * Updates the UI appropriately after a failed demo deletion.
186
+ *
187
+ * @typedef {object} deleteDemoError
188
+ * @param {object} response Response from the server.
189
+ * @param {string} response.slug Slug of the demo to be deleted.
190
+ * @param {string} response.errorCode Error code for the error that occurred.
191
+ * @param {string} response.errorMessage The error that occurred.
192
+ */
193
+ wp.updates.deleteDemoError = function( response ) {
194
+ var $button = $( '.theme-actions .delete-demo' ),
195
+ errorMessage = wp.updates.l10n.deleteFailed.replace( '%s', response.errorMessage ),
196
+ $message = wp.updates.adminNotice( {
197
+ className: 'update-message notice-error notice-alt',
198
+ message: errorMessage
199
+ } );
200
+
201
+ if ( wp.updates.maybeHandleCredentialError( response, 'delete-demo' ) ) {
202
+ return;
203
+ }
204
+
205
+ $( '.theme-info .theme-description' ).before( $message );
206
+
207
+ $button.html( $button.data( 'originaltext' ) );
208
+
209
+ wp.a11y.speak( errorMessage, 'assertive' );
210
+
211
+ $document.trigger( 'wp-demo-delete-error', response );
212
+ };
213
+
214
+ /**
215
+ * Validates an AJAX response to ensure it's a proper object.
216
+ *
217
+ * If the response deems to be invalid, an admin notice is being displayed.
218
+ *
219
+ * @param {(object|string)} response Response from the server.
220
+ * @param {function=} response.always Optional. Callback for when the Deferred is resolved or rejected.
221
+ * @param {string=} response.statusText Optional. Status message corresponding to the status code.
222
+ * @param {string=} response.responseText Optional. Request response as text.
223
+ * @param {string} action Type of action the response is referring to. Can be 'delete',
224
+ * 'update' or 'install'.
225
+ */
226
+ wp.updates.isValidResponse = function( response, action ) {
227
+ var error = wp.updates.l10n.unknownError,
228
+ errorMessage;
229
+
230
+ // Make sure the response is a valid data object and not a Promise object.
231
+ if ( _.isObject( response ) && ! _.isFunction( response.always ) ) {
232
+ return true;
233
+ }
234
+
235
+ if ( _.isString( response ) && '-1' === response ) {
236
+ error = wp.updates.l10n.nonceError;
237
+ } else if ( _.isString( response ) ) {
238
+ error = response;
239
+ } else if ( 'undefined' !== typeof response.readyState && 0 === response.readyState ) {
240
+ error = wp.updates.l10n.connectionError;
241
+ } else if ( _.isString( response.statusText ) ) {
242
+ error = response.statusText + ' ' + wp.updates.l10n.statusTextLink;
243
+ }
244
+
245
+ switch ( action ) {
246
+ case 'import':
247
+ errorMessage = wp.updates.l10n.importFailed;
248
+ break;
249
+ }
250
+
251
+ errorMessage = errorMessage.replace( '%s', error );
252
+
253
+ // Add admin notice.
254
+ wp.updates.addAdminNotice( {
255
+ id: 'unknown_error',
256
+ className: 'notice-error is-dismissible',
257
+ message: _.unescape( errorMessage )
258
+ } );
259
+
260
+ // Change buttons of all running updates.
261
+ $( '.button.updating-message' )
262
+ .removeClass( 'updating-message' )
263
+ .removeAttr( 'aria-label' )
264
+ .text( wp.updates.l10n.updateFailedShort );
265
+
266
+ wp.a11y.speak( errorMessage, 'assertive' );
267
+
268
+ return false;
269
+ };
270
+
271
+ /**
272
+ * Pulls available jobs from the queue and runs them.
273
+ * @see https://core.trac.wordpress.org/ticket/39364
274
+ */
275
+ wp.updates.queueChecker = function() {
276
+ var job;
277
+
278
+ if ( wp.updates.ajaxLocked || ! wp.updates.queue.length ) {
279
+ return;
280
+ }
281
+
282
+ job = wp.updates.queue.shift();
283
+
284
+ job = wp.updates.queue.shift();
285
+
286
+ // Handle a queue job.
287
+ switch ( job.action ) {
288
+ case 'import-demo':
289
+ wp.updates.importDemo( job.data );
290
+ break;
291
+
292
+ case 'delete-demo':
293
+ wp.updates.deleteDemo( job.data );
294
+ break;
295
+
296
+ default:
297
+ break;
298
+
299
+ }
300
+
301
+ // Handle a queue job.
302
+ $document.trigger( 'wp-updates-queue-job', job );
303
+ };
304
+
305
+ })( jQuery, window.wp, window._demoUpdatesSettings );
assets/js/admin/demo-updates.min.js ADDED
@@ -0,0 +1 @@
 
1
+ !function(a,b,c){var d=a(document);b=b||{},b.updates=b.updates||{},b.updates.l10n=_.extend(b.updates.l10n,c.l10n||{}),b.updates.importDemo=function(c){var e=a('.demo-import[data-slug="'+c.slug+'"]');return c=_.extend({success:b.updates.importDemoSuccess,error:b.updates.importDemoError},c),e.addClass("updating-message"),e.parents(".theme").addClass("focus"),e.html()!==b.updates.l10n.importing&&e.data("originaltext",e.html()),e.text(b.updates.l10n.importing).attr("aria-label",b.updates.l10n.demoImportingLabel.replace("%s",e.data("name"))),b.a11y.speak(b.updates.l10n.importingMsg,"polite"),a('.theme-info .theme-description, [data-slug="'+c.slug+'"]').removeClass("demo-import-failed").find(".notice.notice-error").remove(),d.trigger("wp-demo-importing",c),b.updates.ajax("import-demo",c)},b.updates.importDemoSuccess=function(c){var e,f=a(".theme-overlay, [data-slug="+c.slug+"]");d.trigger("wp-demo-import-success",c),e=f.find(".button-primary").removeClass("updating-message").addClass("updated-message disabled").attr("aria-label",b.updates.l10n.demoImportedLabel.replace("%s",c.demoName)).text(b.updates.l10n.imported),b.a11y.speak(b.updates.l10n.importedMsg,"polite"),setTimeout(function(){c.previewUrl&&(e.siblings(".demo-preview").remove(),e.attr("target","_blank").attr("href",c.previewUrl).removeClass("demo-import updated-message disabled").addClass("live-preview").attr("aria-label",b.updates.l10n.livePreviewLabel.replace("%s",c.demoName)).text(b.updates.l10n.livePreview))},1e3)},b.updates.importDemoError=function(c){var e,f,g=b.updates.l10n.importFailed.replace("%s",c.errorMessage),h=b.updates.adminNotice({className:"update-message notice-error notice-alt",message:g});b.updates.isValidResponse(c,"import")&&(d.find("body").hasClass("modal-open")||d.find(".themes").hasClass("single-theme")?(f=a('.demo-import[data-slug="'+c.slug+'"]'),e=a(".theme-info .theme-description").prepend(h)):(e=a('[data-slug="'+c.slug+'"]').removeClass("focus").addClass("demo-import-failed").append(h),f=e.find(".demo-import")),f.removeClass("updating-message").attr("aria-label",b.updates.l10n.demoImportFailedLabel.replace("%s",f.data("name"))).text(b.updates.l10n.importFailedShort),b.a11y.speak(g,"assertive"),d.trigger("wp-demo-import-error",c))},b.updates.deleteDemo=function(c){var e=a(".theme-actions .delete-demo");return c=_.extend({success:b.updates.deleteDemoSuccess,error:b.updates.deleteDemoError},c),e&&e.html()!==b.updates.l10n.deleting&&e.data("originaltext",e.html()).text(b.updates.l10n.deleting),b.a11y.speak(b.updates.l10n.deleting,"polite"),a(".theme-info .update-message").remove(),d.trigger("wp-demo-deleting",c),b.updates.ajax("delete-demo",c)},b.updates.deleteDemoSuccess=function(a){b.a11y.speak(b.updates.l10n.deleted,"polite"),d.trigger("wp-demo-delete-success",a)},b.updates.deleteDemoError=function(c){var e=a(".theme-actions .delete-demo"),f=b.updates.l10n.deleteFailed.replace("%s",c.errorMessage),g=b.updates.adminNotice({className:"update-message notice-error notice-alt",message:f});b.updates.maybeHandleCredentialError(c,"delete-demo")||(a(".theme-info .theme-description").before(g),e.html(e.data("originaltext")),b.a11y.speak(f,"assertive"),d.trigger("wp-demo-delete-error",c))},b.updates.isValidResponse=function(c,d){var e,f=b.updates.l10n.unknownError;if(_.isObject(c)&&!_.isFunction(c.always))return!0;switch(_.isString(c)&&"-1"===c?f=b.updates.l10n.nonceError:_.isString(c)?f=c:"undefined"!=typeof c.readyState&&0===c.readyState?f=b.updates.l10n.connectionError:_.isString(c.statusText)&&(f=c.statusText+" "+b.updates.l10n.statusTextLink),d){case"import":e=b.updates.l10n.importFailed}return e=e.replace("%s",f),b.updates.addAdminNotice({id:"unknown_error",className:"notice-error is-dismissible",message:_.unescape(e)}),a(".button.updating-message").removeClass("updating-message").removeAttr("aria-label").text(b.updates.l10n.updateFailedShort),b.a11y.speak(e,"assertive"),!1},b.updates.queueChecker=function(){var a;if(!b.updates.ajaxLocked&&b.updates.queue.length){switch(a=b.updates.queue.shift(),a=b.updates.queue.shift(),a.action){case"import-demo":b.updates.importDemo(a.data);break;case"delete-demo":b.updates.deleteDemo(a.data)}d.trigger("wp-updates-queue-job",a)}}}(jQuery,window.wp,window._demoUpdatesSettings);
composer.lock ADDED
@@ -0,0 +1,295 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "_readme": [
3
+ "This file locks the dependencies of your project to a known state",
4
+ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
5
+ "This file is @generated automatically"
6
+ ],
7
+ "hash": "dc8868b0f068d03c4a1ea5221933732b",
8
+ "content-hash": "e902d62f93fd8f9f14910ae4a1e8a26f",
9
+ "packages": [
10
+ {
11
+ "name": "composer/installers",
12
+ "version": "v1.2.0",
13
+ "source": {
14
+ "type": "git",
15
+ "url": "https://github.com/composer/installers.git",
16
+ "reference": "d78064c68299743e0161004f2de3a0204e33b804"
17
+ },
18
+ "dist": {
19
+ "type": "zip",
20
+ "url": "https://api.github.com/repos/composer/installers/zipball/d78064c68299743e0161004f2de3a0204e33b804",
21
+ "reference": "d78064c68299743e0161004f2de3a0204e33b804",
22
+ "shasum": ""
23
+ },
24
+ "require": {
25
+ "composer-plugin-api": "^1.0"
26
+ },
27
+ "replace": {
28
+ "roundcube/plugin-installer": "*",
29
+ "shama/baton": "*"
30
+ },
31
+ "require-dev": {
32
+ "composer/composer": "1.0.*@dev",
33
+ "phpunit/phpunit": "4.1.*"
34
+ },
35
+ "type": "composer-plugin",
36
+ "extra": {
37
+ "class": "Composer\\Installers\\Plugin",
38
+ "branch-alias": {
39
+ "dev-master": "1.0-dev"
40
+ }
41
+ },
42
+ "autoload": {
43
+ "psr-4": {
44
+ "Composer\\Installers\\": "src/Composer/Installers"
45
+ }
46
+ },
47
+ "notification-url": "https://packagist.org/downloads/",
48
+ "license": [
49
+ "MIT"
50
+ ],
51
+ "authors": [
52
+ {
53
+ "name": "Kyle Robinson Young",
54
+ "email": "kyle@dontkry.com",
55
+ "homepage": "https://github.com/shama"
56
+ }
57
+ ],
58
+ "description": "A multi-framework Composer library installer",
59
+ "homepage": "https://composer.github.io/installers/",
60
+ "keywords": [
61
+ "Craft",
62
+ "Dolibarr",
63
+ "Hurad",
64
+ "ImageCMS",
65
+ "MODX Evo",
66
+ "Mautic",
67
+ "OXID",
68
+ "Plentymarkets",
69
+ "RadPHP",
70
+ "SMF",
71
+ "Thelia",
72
+ "WolfCMS",
73
+ "agl",
74
+ "aimeos",
75
+ "annotatecms",
76
+ "attogram",
77
+ "bitrix",
78
+ "cakephp",
79
+ "chef",
80
+ "cockpit",
81
+ "codeigniter",
82
+ "concrete5",
83
+ "croogo",
84
+ "dokuwiki",
85
+ "drupal",
86
+ "elgg",
87
+ "expressionengine",
88
+ "fuelphp",
89
+ "grav",
90
+ "installer",
91
+ "joomla",
92
+ "kohana",
93
+ "laravel",
94
+ "lithium",
95
+ "magento",
96
+ "mako",
97
+ "mediawiki",
98
+ "modulework",
99
+ "moodle",
100
+ "phpbb",
101
+ "piwik",
102
+ "ppi",
103
+ "puppet",
104
+ "reindex",
105
+ "roundcube",
106
+ "shopware",
107
+ "silverstripe",
108
+ "symfony",
109
+ "typo3",
110
+ "wordpress",
111
+ "yawik",
112
+ "zend",
113
+ "zikula"
114
+ ],
115
+ "time": "2016-08-13 20:53:52"
116
+ }
117
+ ],
118
+ "packages-dev": [
119
+ {
120
+ "name": "simplyadmire/composer-plugins",
121
+ "version": "dev-master",
122
+ "source": {
123
+ "type": "git",
124
+ "url": "https://github.com/SimplyAdmire/ComposerPlugins.git",
125
+ "reference": "d8380f670694c1c2330b22591ca74adc82cffe19"
126
+ },
127
+ "dist": {
128
+ "type": "zip",
129
+ "url": "https://api.github.com/repos/SimplyAdmire/ComposerPlugins/zipball/d8380f670694c1c2330b22591ca74adc82cffe19",
130
+ "reference": "d8380f670694c1c2330b22591ca74adc82cffe19",
131
+ "shasum": ""
132
+ },
133
+ "require": {
134
+ "composer-plugin-api": "^1.0",
135
+ "squizlabs/php_codesniffer": "*"
136
+ },
137
+ "type": "composer-plugin",
138
+ "extra": {
139
+ "class": [
140
+ "SimplyAdmire\\ComposerPlugins\\PhpCodesnifferStandardInstallerPlugin"
141
+ ]
142
+ },
143
+ "autoload": {
144
+ "psr-0": {
145
+ "SimplyAdmire\\ComposerPlugins": ""
146
+ }
147
+ },
148
+ "notification-url": "https://packagist.org/downloads/",
149
+ "license": [
150
+ "LGPL-3.0+"
151
+ ],
152
+ "authors": [
153
+ {
154
+ "name": "Rens Admiraal",
155
+ "email": "rens@simplyadmire.com",
156
+ "role": "lead"
157
+ }
158
+ ],
159
+ "description": "Composer plugin for installing PHP_CodeSniffer standards",
160
+ "keywords": [
161
+ "PHP_CodeSniffer",
162
+ "TYPO3 CMS",
163
+ "TYPO3 Flow",
164
+ "TYPO3 Neos",
165
+ "phpcs",
166
+ "standards",
167
+ "typo3"
168
+ ],
169
+ "time": "2016-05-12 11:58:38"
170
+ },
171
+ {
172
+ "name": "squizlabs/php_codesniffer",
173
+ "version": "2.7.0",
174
+ "source": {
175
+ "type": "git",
176
+ "url": "https://github.com/squizlabs/PHP_CodeSniffer.git",
177
+ "reference": "571e27b6348e5b3a637b2abc82ac0d01e6d7bbed"
178
+ },
179
+ "dist": {
180
+ "type": "zip",
181
+ "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/571e27b6348e5b3a637b2abc82ac0d01e6d7bbed",
182
+ "reference": "571e27b6348e5b3a637b2abc82ac0d01e6d7bbed",
183
+ "shasum": ""
184
+ },
185
+ "require": {
186
+ "ext-simplexml": "*",
187
+ "ext-tokenizer": "*",
188
+ "ext-xmlwriter": "*",
189
+ "php": ">=5.1.2"
190
+ },
191
+ "require-dev": {
192
+ "phpunit/phpunit": "~4.0"
193
+ },
194
+ "bin": [
195
+ "scripts/phpcs",
196
+ "scripts/phpcbf"
197
+ ],
198
+ "type": "library",
199
+ "extra": {
200
+ "branch-alias": {
201
+ "dev-master": "2.x-dev"
202
+ }
203
+ },
204
+ "autoload": {
205
+ "classmap": [
206
+ "CodeSniffer.php",
207
+ "CodeSniffer/CLI.php",
208
+ "CodeSniffer/Exception.php",
209
+ "CodeSniffer/File.php",
210
+ "CodeSniffer/Fixer.php",
211
+ "CodeSniffer/Report.php",
212
+ "CodeSniffer/Reporting.php",
213
+ "CodeSniffer/Sniff.php",
214
+ "CodeSniffer/Tokens.php",
215
+ "CodeSniffer/Reports/",
216
+ "CodeSniffer/Tokenizers/",
217
+ "CodeSniffer/DocGenerators/",
218
+ "CodeSniffer/Standards/AbstractPatternSniff.php",
219
+ "CodeSniffer/Standards/AbstractScopeSniff.php",
220
+ "CodeSniffer/Standards/AbstractVariableSniff.php",
221
+ "CodeSniffer/Standards/IncorrectPatternException.php",
222
+ "CodeSniffer/Standards/Generic/Sniffs/",
223
+ "CodeSniffer/Standards/MySource/Sniffs/",
224
+ "CodeSniffer/Standards/PEAR/Sniffs/",
225
+ "CodeSniffer/Standards/PSR1/Sniffs/",
226
+ "CodeSniffer/Standards/PSR2/Sniffs/",
227
+ "CodeSniffer/Standards/Squiz/Sniffs/",
228
+ "CodeSniffer/Standards/Zend/Sniffs/"
229
+ ]
230
+ },
231
+ "notification-url": "https://packagist.org/downloads/",
232
+ "license": [
233
+ "BSD-3-Clause"
234
+ ],
235
+ "authors": [
236
+ {
237
+ "name": "Greg Sherwood",
238
+ "role": "lead"
239
+ }
240
+ ],
241
+ "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.",
242
+ "homepage": "http://www.squizlabs.com/php-codesniffer",
243
+ "keywords": [
244
+ "phpcs",
245
+ "standards"
246
+ ],
247
+ "time": "2016-09-01 23:53:02"
248
+ },
249
+ {
250
+ "name": "wp-coding-standards/wpcs",
251
+ "version": "0.10.0",
252
+ "source": {
253
+ "type": "git",
254
+ "url": "https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards.git",
255
+ "reference": "b39490465f6fd7375743a395019cd597e12119c9"
256
+ },
257
+ "dist": {
258
+ "type": "zip",
259
+ "url": "https://api.github.com/repos/WordPress-Coding-Standards/WordPress-Coding-Standards/zipball/b39490465f6fd7375743a395019cd597e12119c9",
260
+ "reference": "b39490465f6fd7375743a395019cd597e12119c9",
261
+ "shasum": ""
262
+ },
263
+ "require": {
264
+ "squizlabs/php_codesniffer": "^2.6"
265
+ },
266
+ "type": "library",
267
+ "notification-url": "https://packagist.org/downloads/",
268
+ "license": [
269
+ "MIT"
270
+ ],
271
+ "authors": [
272
+ {
273
+ "name": "Contributors",
274
+ "homepage": "https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards/graphs/contributors"
275
+ }
276
+ ],
277
+ "description": "PHP_CodeSniffer rules (sniffs) to enforce WordPress coding conventions",
278
+ "keywords": [
279
+ "phpcs",
280
+ "standards",
281
+ "wordpress"
282
+ ],
283
+ "time": "2016-08-29 20:04:47"
284
+ }
285
+ ],
286
+ "aliases": [],
287
+ "minimum-stability": "stable",
288
+ "stability-flags": {
289
+ "simplyadmire/composer-plugins": 20
290
+ },
291
+ "prefer-stable": false,
292
+ "prefer-lowest": false,
293
+ "platform": [],
294
+ "platform-dev": []
295
+ }
includes/class-demo-importer.php CHANGED
@@ -30,6 +30,12 @@ class TG_Demo_Importer {
30
  */
31
  public $demo_packages;
32
 
 
 
 
 
 
 
33
  /**
34
  * Constructor.
35
  */
@@ -39,17 +45,13 @@ class TG_Demo_Importer {
39
 
40
  // Add Demo Importer menu.
41
  if ( apply_filters( 'themegrill_show_demo_importer_page', true ) ) {
42
- add_action( 'admin_menu', array( $this, 'demo_importer_menu' ) );
 
43
  }
44
 
45
- // Add Demo Importer filterable content.
46
- add_action( 'themegrill_demo_importer_welcome', array( $this, 'welcome_panel' ) );
47
- add_action( 'themegrill_demo_importer_uploaded', array( $this, 'output_uploaded' ) );
48
- add_action( 'themegrill_demo_importer_previews', array( $this, 'output_previews' ) );
49
-
50
- // AJAX Events to dismiss notice and import demo data.
51
- add_action( 'wp_ajax_tg_dismiss_notice', array( $this, 'dismissible_notice' ) );
52
- add_action( 'wp_ajax_tg_import_demo_data', array( $this, 'import_demo_data' ) );
53
 
54
  // Update custom nav menu items and siteorigin panel data.
55
  add_action( 'themegrill_ajax_demo_imported', array( $this, 'update_nav_menu_items' ) );
@@ -131,11 +133,32 @@ class TG_Demo_Importer {
131
  /**
132
  * Add menu item.
133
  */
134
- public function demo_importer_menu() {
135
  $page = add_theme_page( __( 'Demo Importer', 'themegrill-demo-importer' ), __( 'Demo Importer', 'themegrill-demo-importer' ), 'switch_themes', 'demo-importer', array( $this, 'demo_importer' ) );
136
  add_action( 'admin_print_styles-' . $page, array( $this, 'enqueue_styles' ) );
137
  }
138
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
139
  /**
140
  * Enqueue styles.
141
  */
@@ -143,55 +166,221 @@ class TG_Demo_Importer {
143
  $suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
144
  $assets_path = tg_get_demo_importer_assets_path();
145
 
 
 
 
146
  // Register Scripts
147
  wp_register_script( 'jquery-tiptip', $assets_path . 'js/jquery-tiptip/jquery.tipTip' . $suffix . '.js', array( 'jquery' ), '1.3', true );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
148
 
149
  // Enqueue Scripts
150
- wp_enqueue_style( 'tg-demo-importer', $assets_path . 'css/demo-importer.css', array() );
151
- wp_enqueue_script( 'tg-demo-importer', $assets_path . 'js/admin/demo-importer' . $suffix . '.js', array( 'jquery', 'jquery-tiptip' ), '1.0.0' );
152
-
153
- wp_localize_script( 'tg-demo-importer', 'demo_importer_params', array(
154
- 'ajax_url' => admin_url( 'admin-ajax.php' ),
155
- 'import_demo_data_nonce' => wp_create_nonce( 'import-demo-data' ),
156
- 'i18n_import_data_error' => esc_js( __( 'Importing Failed. Try again!', 'themegrill-demo-importer' ) ),
157
- 'i18n_import_dummy_data' => esc_js( __( 'Importing demo content will replicate the live demo and overwrites your current customizer, widgets and other settings. It might take few minutes to complete the demo import. Are you sure you want to import this demo?', 'themegrill-demo-importer' ) ),
 
 
 
 
 
 
 
 
 
 
 
 
 
158
  ) );
159
  }
160
 
161
  /**
162
- * Demo Importer page output.
 
163
  */
164
- public function demo_importer() {
165
- global $current_tab;
166
-
167
- $current_tab = empty( $_GET['tab'] ) ? 'welcome' : sanitize_title( $_GET['tab'] );
168
-
169
- if ( isset( $_GET['action'] ) && 'upload-demo' === $_GET['action'] ) {
170
- $this->upload_demo_pack();
171
- } else {
172
- include_once( dirname( __FILE__ ) . '/includes/admin/views/html-admin-page-importer.php' );
173
  }
 
 
174
  }
175
 
176
  /**
177
- * Output welcome panel page.
178
  */
179
- public function welcome_panel() {
180
- include_once( dirname( __FILE__ ) . '/includes/admin/views/html-admin-page-importer-welcome.php' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
181
  }
182
 
183
  /**
184
- * Output demo uploaded page.
 
 
 
185
  */
186
- public function output_uploaded() {
187
- include_once( dirname( __FILE__ ) . '/includes/admin/views/html-admin-page-importer-uploaded.php' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
188
  }
189
 
190
  /**
191
- * Output demo previews page.
192
  */
193
- public function output_previews() {
194
- include_once( dirname( __FILE__ ) . '/includes/admin/views/html-admin-page-importer-previews.php' );
 
 
 
 
 
 
 
195
  }
196
 
197
  /**
@@ -226,9 +415,9 @@ class TG_Demo_Importer {
226
  }
227
 
228
  /**
229
- * AJAX Dismissible notice.
230
  */
231
- public function dismissible_notice() {
232
  if ( ! current_user_can( 'manage_options' ) ) {
233
  die( -1 );
234
  }
@@ -243,52 +432,65 @@ class TG_Demo_Importer {
243
  }
244
 
245
  /**
246
- * AJAX Import demo/dummy data.
247
  */
248
- public function import_demo_data() {
249
- ob_start();
 
 
 
 
 
 
 
 
250
 
251
- check_ajax_referer( 'import-demo-data', 'security' );
 
 
 
 
 
252
 
253
  if ( ! defined( 'WP_LOAD_IMPORTERS' ) ) {
254
  define( 'WP_LOAD_IMPORTERS', true );
255
  }
256
 
257
  if ( ! current_user_can( 'manage_options' ) ) {
258
- die( -1 );
 
259
  }
260
 
261
- $demo_id = sanitize_text_field( stripslashes( $_POST['demo_id'] ) );
262
- $demo_data = isset( $this->demo_config[ $demo_id ] ) ? $this->demo_config[ $demo_id ] : array();
263
 
264
  do_action( 'themegrill_ajax_before_demo_import' );
265
 
266
  if ( ! empty( $demo_data ) ) {
267
- $this->import_dummy_xml( $demo_id, $demo_data );
268
- $this->import_core_options( $demo_id, $demo_data );
269
- $this->import_customizer_data( $demo_id, $demo_data );
270
- $this->import_widget_settings( $demo_id, $demo_data );
271
 
272
- update_option( 'themegrill_demo_imported_id', $demo_id );
 
273
 
274
- do_action( 'themegrill_ajax_demo_imported', $demo_id, $demo_data );
275
-
276
- wp_send_json_success( array(
277
- 'demo_id' => $demo_id,
278
- 'message' => __( 'Successfully Imported', 'themegrill-demo-importer' ),
279
- ) );
280
  }
281
 
282
- die();
 
 
 
283
  }
284
 
285
  /**
286
  * Import dummy content from a XML file.
287
  * @param string $demo_id
288
  * @param array $demo_data
 
289
  * @return bool
290
  */
291
- public function import_dummy_xml( $demo_id, $demo_data ) {
292
  $import_file = $this->import_file_path( $demo_id, 'dummy-data.xml' );
293
 
294
  // Load Importer API
@@ -320,8 +522,8 @@ class TG_Demo_Importer {
320
 
321
  flush_rewrite_rules();
322
  } else {
323
- wp_send_json_error( array( 'message' => __( 'The XML file containing the dummy content is not available.', 'themegrill-demo-importer' ) ) );
324
- exit;
325
  }
326
 
327
  return true;
@@ -370,9 +572,10 @@ class TG_Demo_Importer {
370
  * Import customizer data from a DAT file.
371
  * @param string $demo_id
372
  * @param array $demo_data
 
373
  * @return bool
374
  */
375
- public function import_customizer_data( $demo_id, $demo_data ) {
376
  $import_file = $this->import_file_path( $demo_id, 'dummy-customizer.dat' );
377
 
378
  if ( is_file( $import_file ) ) {
@@ -381,6 +584,9 @@ class TG_Demo_Importer {
381
  if ( is_wp_error( $results ) ) {
382
  return false;
383
  }
 
 
 
384
  }
385
 
386
  return true;
@@ -390,9 +596,10 @@ class TG_Demo_Importer {
390
  * Import widgets settings from WIE or JSON file.
391
  * @param string $demo_id
392
  * @param array $demo_data
 
393
  * @return bool
394
  */
395
- public function import_widget_settings( $demo_id, $demo_data ) {
396
  $import_file = $this->import_file_path( $demo_id, 'dummy-widgets.wie' );
397
 
398
  if ( is_file( $import_file ) ) {
@@ -401,6 +608,9 @@ class TG_Demo_Importer {
401
  if ( is_wp_error( $results ) ) {
402
  return false;
403
  }
 
 
 
404
  }
405
 
406
  return true;
30
  */
31
  public $demo_packages;
32
 
33
+ /**
34
+ * Demo installer.
35
+ * @var bool
36
+ */
37
+ public $demo_install = true;
38
+
39
  /**
40
  * Constructor.
41
  */
45
 
46
  // Add Demo Importer menu.
47
  if ( apply_filters( 'themegrill_show_demo_importer_page', true ) ) {
48
+ add_action( 'admin_menu', array( $this, 'add_admin_menu' ) );
49
+ add_action( 'admin_head', array( $this, 'add_menu_classes' ) );
50
  }
51
 
52
+ // AJAX Events to import demo and dismiss notice.
53
+ add_action( 'wp_ajax_import-demo', array( $this, 'ajax_import_demo' ) );
54
+ add_action( 'wp_ajax_dismiss-notice', array( $this, 'ajax_dismiss_notice' ) );
 
 
 
 
 
55
 
56
  // Update custom nav menu items and siteorigin panel data.
57
  add_action( 'themegrill_ajax_demo_imported', array( $this, 'update_nav_menu_items' ) );
133
  /**
134
  * Add menu item.
135
  */
136
+ public function add_admin_menu() {
137
  $page = add_theme_page( __( 'Demo Importer', 'themegrill-demo-importer' ), __( 'Demo Importer', 'themegrill-demo-importer' ), 'switch_themes', 'demo-importer', array( $this, 'demo_importer' ) );
138
  add_action( 'admin_print_styles-' . $page, array( $this, 'enqueue_styles' ) );
139
  }
140
 
141
+ /**
142
+ * Adds the class to the menu.
143
+ */
144
+ public function add_menu_classes() {
145
+ global $submenu;
146
+
147
+ if ( isset( $submenu['themes.php'] ) ) {
148
+ $submenu_class = $this->demo_install ? 'demo-installer hide-if-no-js' : 'demo-importer';
149
+
150
+ // Add menu classes if user has access.
151
+ if ( apply_filters( 'themegrill_demo_importer_include_class_in_menu', true ) ) {
152
+ foreach ( $submenu['themes.php'] as $order => $menu_item ) {
153
+ if ( 0 === strpos( $menu_item[0], _x( 'Demo Importer', 'Admin menu name', 'themegrill-demo-importer' ) ) ) {
154
+ $submenu['themes.php'][ $order ][4] = empty( $menu_item[4] ) ? $submenu_class : $menu_item[4] . ' ' . $submenu_class;
155
+ break;
156
+ }
157
+ }
158
+ }
159
+ }
160
+ }
161
+
162
  /**
163
  * Enqueue styles.
164
  */
166
  $suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
167
  $assets_path = tg_get_demo_importer_assets_path();
168
 
169
+ // Enqueue Styles
170
+ wp_enqueue_style( 'tg-demo-importer', $assets_path . 'css/demo-importer.css', array() );
171
+
172
  // Register Scripts
173
  wp_register_script( 'jquery-tiptip', $assets_path . 'js/jquery-tiptip/jquery.tipTip' . $suffix . '.js', array( 'jquery' ), '1.3', true );
174
+ wp_register_script( 'tg-demo-updates', $assets_path . 'js/admin/demo-updates' . $suffix . '.js', array( 'jquery', 'updates' ), '1.1.0', true );
175
+ wp_localize_script( 'tg-demo-updates', '_demoUpdatesSettings', array(
176
+ 'l10n' => array(
177
+ 'importing' => __( 'Importing...', 'themegrill-demo-importer' ),
178
+ 'demoImportingLabel' => _x( 'Importing %s...', 'demo', 'themegrill-demo-importer' ), // no ellipsis
179
+ 'importingMsg' => __( 'Importing... please wait.', 'themegrill-demo-importer' ),
180
+ 'importedMsg' => __( 'Import completed successfully.', 'themegrill-demo-importer' ),
181
+ 'importFailedShort' => __( 'Import Failed!', 'themegrill-demo-importer' ),
182
+ 'importFailed' => __( 'Import failed: %s', 'themegrill-demo-importer' ),
183
+ 'demoImportedLabel' => _x( '%s imported!', 'demo', 'themegrill-demo-importer' ),
184
+ 'demoImportFailedLabel' => _x( '%s import failed', 'demo', 'themegrill-demo-importer' ),
185
+ 'livePreview' => __( 'Live Preview', 'themegrill-demo-importer' ),
186
+ 'livePreviewLabel' => _x( 'Live Preview %s', 'demo', 'themegrill-demo-importer' ),
187
+ 'imported' => __( 'Imported!', 'themegrill-demo-importer' ),
188
+ 'statusTextLink' => '<a href="https://docs.themegrill.com/knowledgebase/demo-import-process-failed/" target="_blank">' . __( 'Try this solution!', 'themegrill-demo-importer' ) . '</a>',
189
+ )
190
+ ) );
191
 
192
  // Enqueue Scripts
193
+ wp_enqueue_script( 'tg-demo-importer', $assets_path . 'js/admin/demo-importer' . $suffix . '.js', array( 'jquery', 'jquery-tiptip', 'wp-backbone', 'wp-a11y', 'tg-demo-updates' ), '1.1.0', true );
194
+ wp_localize_script( 'tg-demo-importer', 'demoImporterLocalizeScript', array(
195
+ 'demos' => $this->is_preview() ? $this->prepare_previews_for_js( $this->demo_packages ) : $this->prepare_demos_for_js( $this->demo_config ),
196
+ 'settings' => array(
197
+ 'isPreview' => $this->is_preview(),
198
+ 'isInstall' => $this->demo_install,
199
+ 'canInstall' => current_user_can( 'upload_files' ),
200
+ 'installURI' => current_user_can( 'upload_files' ) ? self_admin_url( 'themes.php?page=demo-importer&browse=preview' ) : null,
201
+ 'confirmDelete' => __( "Are you sure you want to delete this demo?\n\nClick 'Cancel' to go back, 'OK' to confirm the delete.", 'themegrill-demo-importer' ),
202
+ 'confirmImport' => __( 'Importing demo content will replicate the live demo and overwrites your current customizer, widgets and other settings. It might take few minutes to complete the demo import. Are you sure you want to import this demo?', 'themegrill-demo-importer' ),
203
+ 'ajaxUrl' => admin_url( 'admin-ajax.php' ),
204
+ 'adminUrl' => parse_url( self_admin_url(), PHP_URL_PATH ),
205
+ ),
206
+ 'l10n' => array(
207
+ 'addNew' => __( 'Add New Demo', 'themegrill-demo-importer' ),
208
+ 'search' => __( 'Search Demos', 'themegrill-demo-importer' ),
209
+ 'searchPlaceholder' => __( 'Search demos...', 'themegrill-demo-importer' ), // placeholder (no ellipsis)
210
+ 'demosFound' => __( 'Number of Demos found: %d', 'themegrill-demo-importer' ),
211
+ 'noDemosFound' => __( 'No demos found. Try a different search.', 'themegrill-demo-importer' ),
212
+ ),
213
+ 'installedDemos' => array_keys( $this->demo_config ),
214
  ) );
215
  }
216
 
217
  /**
218
+ * Check for preview filter.
219
+ * @return bool
220
  */
221
+ public function is_preview() {
222
+ if ( $this->demo_install && isset( $_GET['browse'] ) ) {
223
+ return 'preview' === $_GET['browse'] ? true : false;
 
 
 
 
 
 
224
  }
225
+
226
+ return false;
227
  }
228
 
229
  /**
230
+ * Prepare previews for JavaScript.
231
  */
232
+ private function prepare_previews_for_js( $demos = null ) {
233
+ $prepared_demos = array();
234
+ $current_template = get_option( 'template' );
235
+ $demo_assets_path = tg_get_demo_importer_assets_path();
236
+ $demo_imported_id = get_option( 'themegrill_demo_imported_id' );
237
+
238
+ /**
239
+ * Filters demo data before it is prepared for JavaScript.
240
+ *
241
+ * @param array $prepared_demos An associative array of demo data. Default empty array.
242
+ * @param null|array $demos An array of demo config to prepare, if any.
243
+ * @param string $demo_imported_id The current demo imported id.
244
+ */
245
+ $prepared_demos = (array) apply_filters( 'themegrill_demo_importer_pre_prepare_demos_for_js', array(), $demos, $demo_imported_id );
246
+
247
+ if ( ! empty( $prepared_demos ) ) {
248
+ return $prepared_demos;
249
+ }
250
+
251
+ if ( ! empty( $demos ) ) {
252
+ foreach ( $demos as $demo_id => $demo_data ) {
253
+ $author = isset( $demo_data['author'] ) ? $demo_data['author'] : __( 'ThemeGrill', 'themegrill-demo-importer' );
254
+ $download_url = isset( $demo_data['download'] ) ? $demo_data['download'] : "https://github.com/themegrill/themegrill-demo-pack/raw/master/packages/{$current_template}/{$demo_id}.zip";
255
+
256
+ // Check if demo is installed.
257
+ $installed = false;
258
+ if ( in_array( $demo_id, array_keys( $this->demo_config ) ) ) {
259
+ $installed = true;
260
+ }
261
+
262
+ // Prepare all demos.
263
+ $prepared_demos[ $demo_id ] = array(
264
+ 'id' => $demo_id,
265
+ 'name' => $demo_data['name'],
266
+ 'author' => $author,
267
+ 'installed' => $installed,
268
+ 'screenshot' => "{$demo_assets_path}images/{$current_template}/{$demo_id}.jpg",
269
+ 'description' => isset( $demo_data['description'] ) ? $demo_data['description'] : '',
270
+ 'actions' => array(
271
+ 'preview_url' => $demo_data['preview'],
272
+ 'download_url' => $download_url,
273
+ ),
274
+ );
275
+ }
276
+ }
277
+
278
+ /**
279
+ * Filters the demos prepared for JavaScript.
280
+ *
281
+ * Could be useful for changing the order, which is by name by default.
282
+ *
283
+ * @param array $prepared_demos Array of demos.
284
+ */
285
+ $prepared_demos = apply_filters( 'themegrill_demo_importer_prepare_demos_for_js', $prepared_demos );
286
+ $prepared_demos = array_values( $prepared_demos );
287
+ return array_filter( $prepared_demos );
288
  }
289
 
290
  /**
291
+ * Prepare demos for JavaScript.
292
+ *
293
+ * @param array $demos Demo config array.
294
+ * @return array An associative array of demo data, sorted by name.
295
  */
296
+ private function prepare_demos_for_js( $demos = null ) {
297
+ $prepared_demos = array();
298
+ $current_template = get_option( 'template' );
299
+ $demo_imported_id = get_option( 'themegrill_demo_imported_id' );
300
+
301
+ /**
302
+ * Filters demo data before it is prepared for JavaScript.
303
+ *
304
+ * @param array $prepared_demos An associative array of demo data. Default empty array.
305
+ * @param null|array $demos An array of demo config to prepare, if any.
306
+ * @param string $demo_imported_id The current demo imported id.
307
+ */
308
+ $prepared_demos = (array) apply_filters( 'themegrill_demo_importer_pre_prepare_demos_for_js', array(), $demos, $demo_imported_id );
309
+
310
+ if ( ! empty( $prepared_demos ) ) {
311
+ return $prepared_demos;
312
+ }
313
+
314
+ // Make sure the imported demo is listed first.
315
+ if ( isset( $demos[ $demo_imported_id ] ) ) {
316
+ $prepared_demos[ $demo_imported_id ] = array();
317
+ }
318
+
319
+ if ( ! empty( $demos ) ) {
320
+ foreach ( $demos as $demo_id => $demo_data ) {
321
+ $demo_notices = array();
322
+ $encoded_slug = urlencode( $demo_id );
323
+ $plugins_list = isset( $demo_data['plugins_list'] ) ? $demo_data['plugins_list'] : array();
324
+
325
+ // Plugins status.
326
+ foreach ( $plugins_list as $plugin => $plugin_data ) {
327
+ $plugins_list[ $plugin ]['is_active'] = is_plugin_active( $plugin_data['slug'] );
328
+ }
329
+
330
+ // Add demo notices.
331
+ if ( isset( $demo_data['template'] ) && $current_template !== $demo_data['template'] ) {
332
+ $demo_notices['required_theme'] = true;
333
+ } elseif ( wp_list_filter( $plugins_list, array( 'required' => true, 'is_active' => false ) ) ) {
334
+ $demo_notices['required_plugins'] = true;
335
+ }
336
+
337
+ // Prepare all demos.
338
+ $prepared_demos[ $demo_id ] = array(
339
+ 'id' => $demo_id,
340
+ 'name' => $demo_data['name'],
341
+ 'theme' => $demo_data['theme'],
342
+ 'package' => $demo_data['demo_pack'],
343
+ 'screenshot' => $this->import_file_url( $demo_id, 'screenshot.jpg' ),
344
+ 'description' => isset( $demo_data['description'] ) ? $demo_data['description'] : '',
345
+ 'author' => isset( $demo_data['author'] ) ? $demo_data['author'] : __( 'ThemeGrill', 'themegrill-demo-importer' ),
346
+ 'authorAndUri' => '<a href="http://themegrill.com" target="_blank">ThemeGrill</a>',
347
+ 'version' => isset( $demo_data['version'] ) ? $demo_data['version'] : '1.1.0',
348
+ 'active' => $demo_id === $demo_imported_id,
349
+ 'hasNotice' => $demo_notices,
350
+ 'plugins' => $plugins_list,
351
+ 'actions' => array(
352
+ 'preview' => home_url( '/' ),
353
+ 'demo_url' => $demo_data['demo_url'],
354
+ 'delete' => current_user_can( 'upload_files' ) ? wp_nonce_url( admin_url( 'themes.php?page=demo-importer&browse=uploads&action=delete&amp;demo_pack=' . urlencode( $demo_id ) ), 'delete-demo_' . $demo_id ) : null,
355
+ ),
356
+ );
357
+ }
358
+ }
359
+
360
+ /**
361
+ * Filters the demos prepared for JavaScript.
362
+ *
363
+ * Could be useful for changing the order, which is by name by default.
364
+ *
365
+ * @param array $prepared_demos Array of demos.
366
+ */
367
+ $prepared_demos = apply_filters( 'themegrill_demo_importer_prepare_demos_for_js', $prepared_demos );
368
+ $prepared_demos = array_values( $prepared_demos );
369
+ return array_filter( $prepared_demos );
370
  }
371
 
372
  /**
373
+ * Demo Importer page output.
374
  */
375
+ public function demo_importer() {
376
+ $demos = $this->prepare_demos_for_js( $this->demo_config );
377
+
378
+ if ( isset( $_GET['action'] ) && 'upload-demo' === $_GET['action'] ) {
379
+ $this->upload_demo_pack();
380
+ } else {
381
+ $suffix = $this->demo_install ? 'installer' : 'importer';
382
+ include_once( dirname( __FILE__ ) . "/includes/admin/views/html-admin-page-{$suffix}.php" );
383
+ }
384
  }
385
 
386
  /**
415
  }
416
 
417
  /**
418
+ * Ajax handler for dismissing notice.
419
  */
420
+ public function ajax_dismiss_notice() {
421
  if ( ! current_user_can( 'manage_options' ) ) {
422
  die( -1 );
423
  }
432
  }
433
 
434
  /**
435
+ * Ajax handler for importing a demo.
436
  */
437
+ public function ajax_import_demo() {
438
+ check_ajax_referer( 'updates' );
439
+
440
+ if ( empty( $_POST['slug'] ) ) {
441
+ wp_send_json_error( array(
442
+ 'slug' => '',
443
+ 'errorCode' => 'no_demo_specified',
444
+ 'errorMessage' => __( 'No demo specified.', 'themegrill-demo-importer' ),
445
+ ) );
446
+ }
447
 
448
+ $slug = sanitize_key( wp_unslash( $_POST['slug'] ) );
449
+
450
+ $status = array(
451
+ 'import' => 'demo',
452
+ 'slug' => $slug,
453
+ );
454
 
455
  if ( ! defined( 'WP_LOAD_IMPORTERS' ) ) {
456
  define( 'WP_LOAD_IMPORTERS', true );
457
  }
458
 
459
  if ( ! current_user_can( 'manage_options' ) ) {
460
+ $status['errorMessage'] = __( 'Sorry, you are not allowed to import.', 'themegrill-demo-importer' );
461
+ wp_send_json_error( $status );
462
  }
463
 
464
+ $demo_data = isset( $this->demo_config[ $slug ] ) ? $this->demo_config[ $slug ] : array();
 
465
 
466
  do_action( 'themegrill_ajax_before_demo_import' );
467
 
468
  if ( ! empty( $demo_data ) ) {
469
+ $this->import_dummy_xml( $slug, $demo_data, $status );
470
+ $this->import_core_options( $slug, $demo_data );
471
+ $this->import_customizer_data( $slug, $demo_data, $status );
472
+ $this->import_widget_settings( $slug, $demo_data, $status );
473
 
474
+ // Update imported demo ID.
475
+ update_option( 'themegrill_demo_imported_id', $slug );
476
 
477
+ do_action( 'themegrill_ajax_demo_imported', $slug, $demo_data );
 
 
 
 
 
478
  }
479
 
480
+ $status['demoName'] = $demo_data['name'];
481
+ $status['previewUrl'] = get_home_url( '/' );
482
+
483
+ wp_send_json_success( $status );
484
  }
485
 
486
  /**
487
  * Import dummy content from a XML file.
488
  * @param string $demo_id
489
  * @param array $demo_data
490
+ * @param array $status
491
  * @return bool
492
  */
493
+ public function import_dummy_xml( $demo_id, $demo_data, $status ) {
494
  $import_file = $this->import_file_path( $demo_id, 'dummy-data.xml' );
495
 
496
  // Load Importer API
522
 
523
  flush_rewrite_rules();
524
  } else {
525
+ $status['errorMessage'] = __( 'The XML file dummy content is missing.', 'themegrill-demo-importer' );
526
+ wp_send_json_error( $status );
527
  }
528
 
529
  return true;
572
  * Import customizer data from a DAT file.
573
  * @param string $demo_id
574
  * @param array $demo_data
575
+ * @param array $status
576
  * @return bool
577
  */
578
+ public function import_customizer_data( $demo_id, $demo_data, $status ) {
579
  $import_file = $this->import_file_path( $demo_id, 'dummy-customizer.dat' );
580
 
581
  if ( is_file( $import_file ) ) {
584
  if ( is_wp_error( $results ) ) {
585
  return false;
586
  }
587
+ } else {
588
+ $status['errorMessage'] = __( 'The DAT file customizer data is missing.', 'themegrill-demo-importer' );
589
+ wp_send_json_error( $status );
590
  }
591
 
592
  return true;
596
  * Import widgets settings from WIE or JSON file.
597
  * @param string $demo_id
598
  * @param array $demo_data
599
+ * @param array $status
600
  * @return bool
601
  */
602
+ public function import_widget_settings( $demo_id, $demo_data, $status ) {
603
  $import_file = $this->import_file_path( $demo_id, 'dummy-widgets.wie' );
604
 
605
  if ( is_file( $import_file ) ) {
608
  if ( is_wp_error( $results ) ) {
609
  return false;
610
  }
611
+ } else {
612
+ $status['errorMessage'] = __( 'The WIE file widget content is missing.', 'themegrill-demo-importer' );
613
+ wp_send_json_error( $status );
614
  }
615
 
616
  return true;
includes/functions-demo-update.php ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Demo Importer Updates.
4
+ *
5
+ * Backward compatibility for demo configs.
6
+ *
7
+ * @author ThemeGrill
8
+ * @category Admin
9
+ * @package Importer/Functions
10
+ * @version 1.1.0
11
+ */
12
+
13
+ if ( ! defined( 'ABSPATH' ) ) {
14
+ exit;
15
+ }
16
+
17
+ /**
18
+ * Update demo importer config.
19
+ *
20
+ * @since 1.1.0
21
+ *
22
+ * @param array $demo_config
23
+ * @return array
24
+ */
25
+ function tg_update_demo_importer_config( $demo_config ) {
26
+ if ( ! empty( $demo_config ) ) {
27
+ foreach ( $demo_config as $demo_id => $demo_data ) {
28
+
29
+ // Set theme name, if not found.
30
+ if ( ! isset( $demo_data['theme'] ) ) {
31
+ $demo_config[ $demo_id ]['theme'] = current( explode( ' ', $demo_data['name'] ) );
32
+ }
33
+
34
+ // BW Compat plugins list.
35
+ if ( ! empty( $demo_data['plugins_list'] ) ) {
36
+ foreach ( $demo_data['plugins_list'] as $plugin_type => $plugins ) {
37
+ if ( ! in_array( $plugin_type, array( 'required', 'recommended' ) ) ) {
38
+ continue;
39
+ }
40
+
41
+ // Format values base on plugin type.
42
+ switch ( $plugin_type ) {
43
+ case 'required':
44
+ foreach ( $plugins as $plugins_key => $plugins_data ) {
45
+ $demo_data['plugins_list'][ $plugins_key ] = $plugins_data;
46
+ $demo_data['plugins_list'][ $plugins_key ]['required'] = true;
47
+ }
48
+ break;
49
+ case 'recommended':
50
+ foreach ( $plugins as $plugins_key => $plugins_data ) {
51
+ $demo_data['plugins_list'][ $plugins_key ] = $plugins_data;
52
+ $demo_data['plugins_list'][ $plugins_key ]['required'] = false;
53
+ }
54
+ break;
55
+ }
56
+
57
+ // Remove the old plugins list.
58
+ unset( $demo_data['plugins_list'][ $plugin_type ] );
59
+ }
60
+
61
+ // Update plugin lists data.
62
+ $demo_config[ $demo_id ]['plugins_list'] = $demo_data['plugins_list'];
63
+ }
64
+ }
65
+ }
66
+
67
+ return $demo_config;
68
+ }
69
+ add_filter( 'themegrill_demo_importer_config', 'tg_update_demo_importer_config', 99 );
includes/includes/admin/class-demo-installer-skin.php CHANGED
@@ -44,11 +44,11 @@ class TG_Demo_Installer_Skin extends WP_Upgrader_Skin {
44
  $from = isset( $_GET['from'] ) ? wp_unslash( $_GET['from'] ) : 'demos';
45
 
46
  if ( 'web' == $this->type ) {
47
- $install_actions['demos_page'] = '<a href="' . admin_url( 'themes.php?page=demo-importer&tab=uploaded' ) . '" target="_parent">' . __( 'Return to Demo Importer', 'themegrill-demo-importer' ) . '</a>';
48
  } elseif ( 'upload' == $this->type && 'demos' == $from ) {
49
- $install_actions['demos_page'] = '<a href="' . admin_url( 'themes.php?page=demo-importer&tab=uploaded' ) . '">' . __( 'Return to Demo Importer', 'themegrill-demo-importer' ) . '</a>';
50
  } else {
51
- $install_actions['demos_page'] = '<a href="' . admin_url( 'themes.php?page=demo-importer&tab=uploaded' ) . '" target="_parent">' . __( 'Return to Demos page', 'themegrill-demo-importer' ) . '</a>';
52
  }
53
 
54
  /**
44
  $from = isset( $_GET['from'] ) ? wp_unslash( $_GET['from'] ) : 'demos';
45
 
46
  if ( 'web' == $this->type ) {
47
+ $install_actions['demos_page'] = '<a href="' . admin_url( 'themes.php?page=demo-importer&browse=uploads' ) . '" target="_parent">' . __( 'Return to Demo Importer', 'themegrill-demo-importer' ) . '</a>';
48
  } elseif ( 'upload' == $this->type && 'demos' == $from ) {
49
+ $install_actions['demos_page'] = '<a href="' . admin_url( 'themes.php?page=demo-importer&browse=uploads' ) . '">' . __( 'Return to Demo Importer', 'themegrill-demo-importer' ) . '</a>';
50
  } else {
51
+ $install_actions['demos_page'] = '<a href="' . admin_url( 'themes.php?page=demo-importer&browse=uploads' ) . '" target="_parent">' . __( 'Return to Demos page', 'themegrill-demo-importer' ) . '</a>';
52
  }
53
 
54
  /**
includes/includes/admin/class-demo-upgrader.php CHANGED
@@ -40,6 +40,8 @@ class TG_Demo_Upgrader extends WP_Upgrader {
40
  $this->strings['no_package'] = __( 'Install package not available.', 'themegrill-demo-importer' );
41
  $this->strings['downloading_package'] = __( 'Downloading install package from <span class="code">%s</span>&#8230;', 'themegrill-demo-importer' );
42
  $this->strings['unpack_package'] = __( 'Unpacking the package&#8230;', 'themegrill-demo-importer' );
 
 
43
  $this->strings['installing_package'] = __( 'Installing the demo&#8230;', 'themegrill-demo-importer' );
44
  $this->strings['no_files'] = __( 'The demo contains no files.', 'themegrill-demo-importer' );
45
  $this->strings['process_failed'] = __( 'Demo install failed.', 'themegrill-demo-importer' );
@@ -79,7 +81,7 @@ class TG_Demo_Upgrader extends WP_Upgrader {
79
  $this->run( array(
80
  'package' => $package,
81
  'destination' => $upload_dir['basedir'] . '/tg-demo-pack',
82
- 'clear_destination' => false, // Do not overwrite files.
83
  'protect_destination' => true,
84
  'clear_working' => true,
85
  'hook_extra' => array(
40
  $this->strings['no_package'] = __( 'Install package not available.', 'themegrill-demo-importer' );
41
  $this->strings['downloading_package'] = __( 'Downloading install package from <span class="code">%s</span>&#8230;', 'themegrill-demo-importer' );
42
  $this->strings['unpack_package'] = __( 'Unpacking the package&#8230;', 'themegrill-demo-importer' );
43
+ $this->strings['remove_old'] = __( 'Removing the old version of the demo&#8230;', 'themegrill-demo-importer' );
44
+ $this->strings['remove_old_failed'] = __( 'Could not remove the old demo.', 'themegrill-demo-importer' );
45
  $this->strings['installing_package'] = __( 'Installing the demo&#8230;', 'themegrill-demo-importer' );
46
  $this->strings['no_files'] = __( 'The demo contains no files.', 'themegrill-demo-importer' );
47
  $this->strings['process_failed'] = __( 'Demo install failed.', 'themegrill-demo-importer' );
81
  $this->run( array(
82
  'package' => $package,
83
  'destination' => $upload_dir['basedir'] . '/tg-demo-pack',
84
+ 'clear_destination' => true, // Do overwrite files.
85
  'protect_destination' => true,
86
  'clear_working' => true,
87
  'hook_extra' => array(
includes/includes/admin/views/html-admin-page-importer-previews.php DELETED
@@ -1,40 +0,0 @@
1
- <?php
2
- /**
3
- * Admin View: Page - Demo Previews
4
- */
5
-
6
- if ( ! defined( 'ABSPATH' ) ) {
7
- exit;
8
- }
9
-
10
- global $current_tab;
11
-
12
- $template = get_option( 'template' );
13
- $assets_path = tg_get_demo_importer_assets_path();
14
-
15
- ?>
16
- <h2 class="screen-reader-text hide-if-no-js"><?php _e( 'Theme demos list', 'themegrill-demo-importer' ); ?></h2>
17
-
18
- <div class="theme-browser content-filterable">
19
- <div class="themes wp-clearfix">
20
- <?php foreach ( $this->demo_packages as $pack_id => $pack_data ) : ?>
21
- <div class="theme active" tabindex="0">
22
- <?php if ( $screenshot = "{$assets_path}images/{$template}/{$pack_id}.jpg" ) : ?>
23
- <div class="theme-screenshot">
24
- <?php if ( file_is_displayable_image( $screenshot ) ) : ?>
25
- <img src="<?php echo esc_url( $screenshot ); ?>" alt="" />
26
- <?php endif; ?>
27
- </div>
28
- <?php else : ?>
29
- <div class="theme-screenshot blank"></div>
30
- <?php endif; ?>
31
-
32
- <h2 class="theme-name" id="demo-name"><?php echo esc_html( $pack_data['name'] ); ?></h2>
33
-
34
- <div class="theme-actions">
35
- <a class="button button-primary live-preview" target="_blank" href="<?php echo esc_url( $pack_data['preview'] ); ?>"><?php _e( 'Live Preview', 'themegrill-demo-importer' ); ?></a>
36
- </div>
37
- </div>
38
- <?php endforeach; ?>
39
- </div>
40
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/includes/admin/views/html-admin-page-importer-uploaded.php DELETED
@@ -1,72 +0,0 @@
1
- <?php
2
- /**
3
- * Admin View: Page - Demo Uploaded
4
- */
5
-
6
- if ( ! defined( 'ABSPATH' ) ) {
7
- exit;
8
- }
9
-
10
- global $current_tab;
11
-
12
- $template = get_option( 'template' );
13
- $demo_imported_id = get_option( 'themegrill_demo_imported_id' );
14
-
15
- ?>
16
- <h2 class="screen-reader-text hide-if-no-js"><?php _e( 'Available demos list', 'themegrill-demo-importer' ); ?></h2>
17
-
18
- <div class="theme-browser content-filterable">
19
- <div class="themes wp-clearfix">
20
- <?php foreach ( $this->demo_config as $demo_id => $demo_data ) : ?>
21
- <div class="theme<?php if ( $demo_id == $demo_imported_id ) echo ' active'; ?>" tabindex="0">
22
- <?php if ( $screenshot = $this->import_file_url( $demo_id, 'screenshot.jpg' ) ) : ?>
23
- <div class="theme-screenshot">
24
- <?php if ( file_is_displayable_image( $screenshot ) ) : ?>
25
- <img src="<?php echo esc_url( $screenshot ); ?>" alt="" />
26
- <?php endif; ?>
27
- </div>
28
- <?php else : ?>
29
- <div class="theme-screenshot blank"></div>
30
- <?php endif; ?>
31
-
32
- <?php if ( ! empty( $demo_data['plugins_list'] ) ) : ?>
33
- <div class="notice inline notice-<?php echo isset( $demo_data['notice_type'] ) ? esc_attr( $demo_data['notice_type'] ) : 'info'; ?> notice-alt">
34
- <?php if ( ! empty( $demo_data['plugins_list']['required'] ) && $plugins_required = tg_get_plugins_links( $demo_data['plugins_list']['required'] ) ) : ?>
35
- <p><?php printf( __( '<strong>Required Plugins:</strong> %s', 'themegrill-demo-importer' ), $plugins_required ); ?></p>
36
- <?php endif; ?>
37
- <?php if ( ! empty( $demo_data['plugins_list']['recommended'] ) && $plugins_recommended = tg_get_plugins_links( $demo_data['plugins_list']['recommended'] ) ) : ?>
38
- <p><?php printf( __( '<strong>Recommended Plugins:</strong> %s', 'themegrill-demo-importer' ), $plugins_recommended ); ?></p>
39
- <?php endif; ?>
40
- </div>
41
- <?php endif; ?>
42
-
43
- <?php if ( $demo_id == $demo_imported_id ) { ?>
44
- <h2 class="theme-name" id="demo-name"><?php
45
- /* translators: %s: demo name */
46
- printf( __( '<span>Imported:</span> %s', 'themegrill-demo-importer' ), esc_html( $demo_data['name'] ) );
47
- ?></h2>
48
- <?php } else { ?>
49
- <h2 class="theme-name" id="demo-name"><?php echo esc_html( $demo_data['name'] ); ?></h2>
50
- <?php } ?>
51
- <div class="theme-actions">
52
- <?php if ( $demo_id !== $demo_imported_id ) : ?>
53
- <?php if ( isset( $demo_data['template'] ) && $template !== $demo_data['template'] ) : ?>
54
- <a class="button button-secondary tips import disabled" href="#" data-demo_id="<?php echo $demo_id; ?>" data-tip="<?php printf( esc_attr( 'Required %s theme must be activated to import this demo.', 'themegrill-demo-importer' ), wp_get_theme()->get( 'Name' ) ); ?>"><?php _e( 'Import', 'themegrill-demo-importer' ); ?></a>
55
- <?php elseif ( ! empty( $demo_data['plugins_list'] ) ) : ?>
56
- <?php if ( ! empty( $demo_data['plugins_list']['required'] ) && tg_is_plugins_active( $demo_data['plugins_list']['required'] ) ) : ?>
57
- <a class="button button-secondary tips import disabled" href="#" data-demo_id="<?php echo $demo_id; ?>" data-tip="<?php esc_attr_e( 'Required Plugin must be activated to import this demo.', 'themegrill-demo-importer' ); ?>"><?php _e( 'Import', 'themegrill-demo-importer' ); ?></a>
58
- <?php else : ?>
59
- <a class="button button-secondary import plugins-ready" href="#" data-demo_id="<?php echo $demo_id; ?>"><?php _e( 'Import', 'themegrill-demo-importer' ); ?></a>
60
- <?php endif; ?>
61
- <?php else : ?>
62
- <a class="button button-secondary import no-plugins-needed" href="#" data-demo_id="<?php echo $demo_id; ?>"><?php _e( 'Import', 'themegrill-demo-importer' ); ?></a>
63
- <?php endif; ?>
64
- <a class="button button-primary live-preview" target="_blank" href="<?php echo esc_url( $demo_data['demo_url'] ); ?>"><?php _e( 'Live Preview', 'themegrill-demo-importer' ); ?></a>
65
- <?php endif; ?>
66
- <a class="button button-primary preview" target="_blank" href="<?php echo esc_url( home_url( '/' ) ); ?>"><?php _e( 'Preview', 'themegrill-demo-importer' ); ?></a>
67
- <span class="spinner"><?php _e( 'Please Wait&hellip;', 'themegrill-demo-importer' ); ?></span>
68
- </div>
69
- </div>
70
- <?php endforeach; ?>
71
- </div>
72
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/includes/admin/views/html-admin-page-importer-welcome.php DELETED
@@ -1,29 +0,0 @@
1
- <?php
2
- /**
3
- * Admin View: Page - Welcome
4
- */
5
-
6
- if ( ! defined( 'ABSPATH' ) ) {
7
- exit;
8
- }
9
-
10
- ?>
11
- <div class="themegrill-demo-BlankState">
12
- <div id="welcome-panel" class="welcome-panel">
13
- <div class="welcome-panel-content">
14
- <h2><?php _e( 'Welcome to ThemeGrill Demo Importer!', 'themegrill-demo-importer' ); ?></h2>
15
- <h3><?php _e( 'Get Started','themegrill-demo-importer' ); ?></h3>
16
- <div class="welcome-panel-column-container">
17
- <div class="welcome-panel-column">
18
- <ul>
19
- <li><?php printf( __( '1. Visit <a href="%s" target="_blank"><strong>this page</strong></a> and download demo zip file.','themegrill-demo-importer' ),esc_url( 'http://themegrill.com/theme-demo-file-downloads/' ) ); ?></li>
20
- <li><?php _e( '2. Click <strong>Upload Demo</strong> button on the top of this Page.','themegrill-demo-importer' ); ?></li>
21
- <li><?php _e( '3. Browse the demo zip file and click <strong>Install Now</strong>.','themegrill-demo-importer' ); ?></li>
22
- <li><?php _e( '4. Go to <strong>Available Demos</strong> tab.','themegrill-demo-importer' ); ?></li>
23
- <li><?php _e( '5. Click <strong>Import</strong> button and wait for few minutes. Done!','themegrill-demo-importer' ); ?></li>
24
- </ul>
25
- </div>
26
- </div>
27
- </div>
28
- </div>
29
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/includes/admin/views/html-admin-page-importer.php CHANGED
@@ -7,21 +7,16 @@ if ( ! defined( 'ABSPATH' ) ) {
7
  exit;
8
  }
9
 
10
- $demo_imported_id = get_option( 'themegrill_demo_imported_id' );
11
- $demo_filter_links = apply_filters( 'themegrill_demo_importer_filter_links_array', array(
12
- 'welcome' => __( 'Welcome', 'themegrill-demo-importer' ),
13
- 'uploaded' => __( 'Available Demos', 'themegrill-demo-importer' ),
14
- 'previews' => __( 'Theme Demos', 'themegrill-demo-importer' ),
15
- ) );
16
 
17
  ?>
18
  <div class="wrap demo-importer">
19
- <h1><?php
20
- esc_html_e( 'Demo Importer', 'themegrill-demo-importer' );
21
- if ( current_user_can( 'upload_files' ) ) {
22
- echo ' <button type="button" class="upload-view-toggle page-title-action hide-if-no-js tg-demo-upload" aria-expanded="false">' . __( 'Upload Demo', 'themegrill-demo-importer' ) . '</button>';
23
- }
24
- ?></h1>
25
  <?php if ( ! get_option( 'themegrill_demo_imported_notice_dismiss' ) && in_array( $demo_imported_id, array_keys( $this->demo_config ) ) ) : ?>
26
  <div id="message" class="notice notice-info is-dismissible" data-notice_id="demo-importer">
27
  <p><?php printf( __( '<strong>Notice</strong> &#8211; If you want to completely remove a demo installation after importing it, you can use a plugin like %1$sWordPress Reset%2$s.', 'themegrill-demo-importer' ), '<a target="_blank" href="' . esc_url( 'https://wordpress.org/plugins/wordpress-reset/' ) . '">', '</a>' ); ?></p>
@@ -30,34 +25,224 @@ $demo_filter_links = apply_filters( 'themegrill_demo_importer_filter_links_array
30
  <div class="error hide-if-js">
31
  <p><?php _e( 'The Demo Importer screen requires JavaScript.', 'themegrill-demo-importer' ); ?></p>
32
  </div>
33
- <div class="upload-theme">
34
- <p class="install-help"><?php _e( 'If you have a demo pack in a .zip format, you may install it by uploading it here.', 'themegrill-demo-importer' ); ?></p>
35
- <form method="post" enctype="multipart/form-data" class="wp-upload-form" action="<?php echo self_admin_url( 'themes.php?page=demo-importer&action=upload-demo' ); ?>">
36
- <?php wp_nonce_field( 'demo-upload' ); ?>
37
- <label class="screen-reader-text" for="demozip"><?php _e( 'Demo zip file', 'themegrill-demo-importer' ); ?></label>
38
- <input type="file" id="demozip" name="demozip" />
39
- <?php submit_button( __( 'Install Now', 'themegrill-demo-importer' ), 'button', 'install-demo-submit', false ); ?>
40
- </form>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
  </div>
42
 
43
- <h2 class="screen-reader-text hide-if-no-js"><?php _e( 'Filter demos list', 'themegrill-demo-importer' ); ?></h2>
 
 
 
44
 
45
- <div class="wp-filter hide-if-no-js">
46
- <div class="filter-count">
47
- <span class="count demo-count"><?php echo 'previews' == $current_tab ? count( $this->demo_packages ) : count( $this->demo_config ); ?></span>
 
 
 
 
48
  </div>
 
 
 
 
 
 
 
 
49
 
50
- <ul class="filter-links">
51
- <?php
52
- foreach ( $demo_filter_links as $name => $label ) {
53
- if ( ( empty( $this->demo_config ) && 'uploaded' == $name ) || ( empty( $this->demo_packages ) && 'previews' == $name ) ) {
54
- continue;
55
- }
56
- echo '<li><a href="' . admin_url( 'themes.php?page=demo-importer&tab=' . $name ) . '" class="demo-tab ' . ( $current_tab == $name ? 'current' : '' ) . '">' . $label . '</a></li>';
57
- }
58
- do_action( 'themegrill_demo_importer_filter_links' );
59
- ?>
60
- </ul>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
  </div>
62
- <?php do_action( 'themegrill_demo_importer_' . $current_tab ); ?>
63
- </div>
 
 
 
7
  exit;
8
  }
9
 
10
+ $demo_imported_id = get_option( 'themegrill_demo_imported_id' );
 
 
 
 
 
11
 
12
  ?>
13
  <div class="wrap demo-importer">
14
+ <h1><?php esc_html_e( 'Demo Importer', 'themegrill-demo-importer' ); ?>
15
+ <span class="title-count demo-count"><?php echo count( $this->demo_config ); ?></span>
16
+ <?php if ( apply_filters( 'themegrill_demo_importer_new_demos', false ) ) : ?>
17
+ <a href="<?php echo esc_url( 'https://themegrill.com/upcoming-new-demos' ); ?>" class="page-title-action" target="_blank"><?php esc_html_e( 'New Demos', 'themegrill-demo-importer' ); ?></a>
18
+ <?php endif; ?>
19
+ </h1>
20
  <?php if ( ! get_option( 'themegrill_demo_imported_notice_dismiss' ) && in_array( $demo_imported_id, array_keys( $this->demo_config ) ) ) : ?>
21
  <div id="message" class="notice notice-info is-dismissible" data-notice_id="demo-importer">
22
  <p><?php printf( __( '<strong>Notice</strong> &#8211; If you want to completely remove a demo installation after importing it, you can use a plugin like %1$sWordPress Reset%2$s.', 'themegrill-demo-importer' ), '<a target="_blank" href="' . esc_url( 'https://wordpress.org/plugins/wordpress-reset/' ) . '">', '</a>' ); ?></p>
25
  <div class="error hide-if-js">
26
  <p><?php _e( 'The Demo Importer screen requires JavaScript.', 'themegrill-demo-importer' ); ?></p>
27
  </div>
28
+
29
+ <div class="theme-browser">
30
+ <div class="themes wp-clearfix">
31
+ <?php foreach ( $demos as $demo ) : ?>
32
+ <div class="theme<?php if ( $demo['active'] ) echo ' active'; ?>" tabindex="0" aria-describedby="<?php echo esc_attr( $demo['id'] . '-action ' . $demo['id'] . '-name' ); ?>">
33
+ <?php if ( $demo['screenshot'] ) : ?>
34
+ <div class="theme-screenshot">
35
+ <img src="<?php echo esc_url( $demo['screenshot'] ); ?>" alt="" />
36
+ </div>
37
+ <?php else : ?>
38
+ <div class="theme-screenshot blank"></div>
39
+ <?php endif; ?>
40
+
41
+ <span class="more-details" id="<?php echo esc_attr( $demo['id'] . '-action' ); ?>"><?php esc_html_e( 'Demo Details', 'themegrill-demo-importer' ); ?></span>
42
+ <div class="theme-author"><?php
43
+ /* translators: %s: Demo author name */
44
+ printf( __( 'By %s', 'themegrill-demo-importer' ), $demo['author'] );
45
+ ?></div>
46
+
47
+ <?php if ( $demo['active'] ) { ?>
48
+ <h2 class="theme-name" id="demo-name"><?php
49
+ /* translators: %s: Demo name */
50
+ printf( __( '<span>Imported:</span> %s', 'themegrill-demo-importer' ), esc_html( $demo['name'] ) );
51
+ ?></h2>
52
+ <?php } else { ?>
53
+ <h2 class="theme-name" id="<?php echo esc_attr( $demo['id'] . '-name' ); ?>"><?php echo esc_html( $demo['name'] ); ?></h2>
54
+ <?php } ?>
55
+
56
+ <div class="theme-actions">
57
+ <?php if ( $demo['active'] ) : ?>
58
+ <a class="button button-primary live-preview" target="_blank" href="<?php echo esc_url( $demo['actions']['preview'] ); ?>"><?php _e( 'Live Preview', 'themegrill-demo-importer' ); ?></a>
59
+ <?php else : ?>
60
+ <?php if ( ! empty( $demo['hasNotice'] ) ) : ?>
61
+ <?php if ( isset( $demo['hasNotice']['required_theme'] ) ) : ?>
62
+ <a class="button button-primary hide-if-no-js tips demo-import disabled" href="#" data-name=<?php echo esc_attr( $demo['name'] );?>" data-slug="<?php echo esc_attr( $demo['id'] ); ?>" data-tip="<?php echo esc_attr( sprintf( __( 'Required %s theme must be activated to import this demo.', 'themegrill-demo-importer' ), $demo['theme'] ) ); ?>"><?php _e( 'Import', 'themegrill-demo-importer' ); ?></a>
63
+ <?php elseif ( isset( $demo['hasNotice']['required_plugins'] ) ) : ?>
64
+ <a class="button button-primary hide-if-no-js tips demo-import disabled" href="#" data-name=<?php echo esc_attr( $demo['name'] );?>" data-slug="<?php echo esc_attr( $demo['id'] ); ?>" data-tip="<?php echo esc_attr( 'Required Plugin must be activated to import this demo.', 'themegrill-demo-importer' ); ?>"><?php _e( 'Import', 'themegrill-demo-importer' ); ?></a>
65
+ <?php endif; ?>
66
+ <?php else : ?>
67
+ <?php
68
+ /* translators: %s: Demo name */
69
+ $aria_label = sprintf( _x( 'Import %s', 'demo', 'themegrill-demo-importer' ), esc_attr( $demo['name'] ) );
70
+ ?>
71
+ <a class="button button-primary hide-if-no-js import" href="#" data-name=<?php echo esc_attr( $demo['name'] );?>" data-slug="<?php echo esc_attr( $demo['id'] ); ?>" aria-label="<?php echo $aria_label; ?>"><?php _e( 'Import', 'themegrill-demo-importer' ); ?></a>
72
+ <?php endif; ?>
73
+ <a class="button button-secondary demo-preview" target="_blank" href="<?php echo esc_url( $demo['actions']['demo_url'] ); ?>"><?php _e( 'Preview', 'themegrill-demo-importer' ); ?></a>
74
+ <?php endif; ?>
75
+ </div>
76
+ </div>
77
+ <?php endforeach; ?>
78
+ </div>
79
+ </div>
80
+ <div class="theme-overlay"></div>
81
+ <p class="no-themes"><?php _e( 'No demos found. Try a different search.', 'themegrill-demo-importer' ); ?></p>
82
+ </div>
83
+
84
+ <script id="tmpl-demo" type="text/template">
85
+ <# if ( data.screenshot ) { #>
86
+ <div class="theme-screenshot">
87
+ <img src="{{ data.screenshot }}" alt="" />
88
+ </div>
89
+ <# } else { #>
90
+ <div class="theme-screenshot blank"></div>
91
+ <# } #>
92
+
93
+ <span class="more-details" id="{{ data.id }}-action"><?php _e( 'Demo Details', 'themegrill-demo-importer' ); ?></span>
94
+ <div class="theme-author"><?php
95
+ /* translators: %s: Demo author name */
96
+ printf( __( 'By %s', 'themegrill-demo-importer' ), '{{{ data.author }}}' );
97
+ ?></div>
98
+
99
+ <# if ( data.active ) { #>
100
+ <h2 class="theme-name" id="{{ data.id }}-name"><?php
101
+ /* translators: %s: Demo name */
102
+ printf( __( '<span>Imported:</span> %s', 'themegrill-demo-importer' ), '{{{ data.name }}}' );
103
+ ?></h2>
104
+ <# } else { #>
105
+ <h2 class="theme-name" id="{{ data.id }}-name">{{{ data.name }}}</h2>
106
+ <# } #>
107
+
108
+ <div class="theme-actions">
109
+ <# if ( data.active ) { #>
110
+ <a class="button button-primary live-preview" target="_blank" href="{{{ data.actions.preview }}}"><?php _e( 'Live Preview', 'themegrill-demo-importer' ); ?></a>
111
+ <# } else { #>
112
+ <# if ( ! _.isEmpty( data.hasNotice ) ) { #>
113
+ <# if ( data.hasNotice['required_theme'] ) { #>
114
+ <a class="button button-primary hide-if-no-js tips demo-import disabled" href="#" data-name="{{ data.name }}" data-slug="{{ data.id }}" data-tip="<?php echo esc_attr( sprintf( __( 'Required %s theme must be activated to import this demo.', 'themegrill-demo-importer' ), '{{{ data.theme }}}' ) ); ?>"><?php _e( 'Import', 'themegrill-demo-importer' ); ?></a>
115
+ <# } else if ( data.hasNotice['required_plugins'] ) { #>
116
+ <a class="button button-primary hide-if-no-js tips demo-import disabled" href="#" data-name="{{ data.name }}" data-slug="{{ data.id }}" data-tip="<?php echo esc_attr( 'Required Plugin must be activated to import this demo.', 'themegrill-demo-importer' ); ?>"><?php _e( 'Import', 'themegrill-demo-importer' ); ?></a>
117
+ <# } #>
118
+ <# } else { #>
119
+ <?php
120
+ /* translators: %s: Demo name */
121
+ $aria_label = sprintf( _x( 'Import %s', 'demo', 'themegrill-demo-importer' ), '{{ data.name }}' );
122
+ ?>
123
+ <a class="button button-primary hide-if-no-js demo-import" href="#" data-name="{{ data.name }}" data-slug="{{ data.id }}" aria-label="<?php echo $aria_label; ?>"><?php _e( 'Import', 'themegrill-demo-importer' ); ?></a>
124
+ <# } #>
125
+ <a class="button button-secondary demo-preview" target="_blank" href="{{{ data.actions.demo_url }}}"><?php _e( 'Preview', 'themegrill-demo-importer' ); ?></a>
126
+ <# } #>
127
  </div>
128
 
129
+ <# if ( data.imported ) { #>
130
+ <div class="notice notice-success notice-alt"><p><?php _ex( 'Imported', 'demo', 'themegrill-demo-importer' ); ?></p></div>
131
+ <# } #>
132
+ </script>
133
 
134
+ <script id="tmpl-demo-single" type="text/template">
135
+ <div class="theme-backdrop"></div>
136
+ <div class="theme-wrap wp-clearfix">
137
+ <div class="theme-header">
138
+ <button class="left dashicons dashicons-no"><span class="screen-reader-text"><?php _e( 'Show previous demo', 'themegrill-demo-importer' ); ?></span></button>
139
+ <button class="right dashicons dashicons-no"><span class="screen-reader-text"><?php _e( 'Show next demo', 'themegrill-demo-importer' ); ?></span></button>
140
+ <button class="close dashicons dashicons-no"><span class="screen-reader-text"><?php _e( 'Close details dialog', 'themegrill-demo-importer' ); ?></span></button>
141
  </div>
142
+ <div class="theme-about wp-clearfix">
143
+ <div class="theme-screenshots">
144
+ <# if ( data.screenshot ) { #>
145
+ <div class="screenshot"><img src="{{ data.screenshot }}" alt="" /></div>
146
+ <# } else { #>
147
+ <div class="screenshot blank"></div>
148
+ <# } #>
149
+ </div>
150
 
151
+ <div class="theme-info">
152
+ <# if ( data.active ) { #>
153
+ <span class="current-label"><?php _e( 'Imported Demo', 'themegrill-demo-importer' ); ?></span>
154
+ <# } #>
155
+ <h2 class="theme-name">{{{ data.name }}}<span class="theme-version"><?php printf( __( 'Version: %s', 'themegrill-demo-importer' ), '{{ data.version }}' ); ?></span></h2>
156
+ <p class="theme-author"><?php printf( __( 'By %s', 'themegrill-demo-importer' ), '{{{ data.authorAndUri }}}' ); ?></p>
157
+
158
+ <# if ( ! _.isEmpty( data.hasNotice ) ) { #>
159
+ <div class="notice demo-message notice-warning notice-alt">
160
+ <# if ( data.hasNotice['required_theme'] ) { #>
161
+ <p class="demo-notice"><?php printf( esc_html__( 'Required %s theme must be activated to import this demo.', 'themegrill-demo-importer' ), '<strong>{{{ data.theme }}}</strong>' ); ?></p>
162
+ <# } else if ( data.hasNotice['required_plugins'] ) { #>
163
+ <p class="demo-notice"><?php _e( 'Required Plugin must be activated to import this demo.', 'themegrill-demo-importer' ); ?></p>
164
+ <# } #>
165
+ </div>
166
+ <# } #>
167
+ <p class="theme-description">{{{ data.description }}}</p>
168
+
169
+ <h3 class="plugins-info"><?php _e( 'Plugins Information', 'themegrill-demo-importer' ); ?></h3>
170
+
171
+ <table class="plugins-list-table widefat">
172
+ <thead>
173
+ <tr>
174
+ <th class="plugin-name"><?php esc_html_e( 'Plugin Name', 'themegrill-demo-importer' ); ?></th>
175
+ <th class="plugin-type"><?php esc_html_e( 'Type', 'themegrill-demo-importer' ); ?></th>
176
+ <th class="plugin-status"><?php esc_html_e( 'Status', 'themegrill-demo-importer' ); ?></th>
177
+ </tr>
178
+ </thead>
179
+ <tbody>
180
+ <# if ( ! _.isEmpty( data.plugins ) ) { #>
181
+ <# _.each( data.plugins, function( plugin, slug ) { #>
182
+ <tr>
183
+ <td class="plugin-name">
184
+ <# if ( plugin.link ) { #>
185
+ <a href="{{{ plugin.link }}}" target="_blank">{{{ plugin.name }}}</a>
186
+ <# } else { #>
187
+ <a href="<?php echo esc_url( admin_url( 'plugin-install.php?tab=search&type=term&s=' ) ); ?>{{ slug }}" target="_blank">{{ plugin.name }}</a>
188
+ <# } #>
189
+ </td>
190
+ <td class="plugin-type">
191
+ <# if ( plugin.required ) { #>
192
+ <span class="required"><?php esc_html_e( 'Required', 'themegrill-demo-importer' ); ?></span>
193
+ <# } else { #>
194
+ <span class="recommended"><?php esc_html_e( 'Recommended', 'themegrill-demo-importer' ); ?></span>
195
+ <# } #>
196
+ </td>
197
+ <td class="plugin-status">
198
+ <# if ( plugin.is_active ) { #>
199
+ <mark class="yes"><span class="dashicons dashicons-yes"></span></mark>
200
+ <# } else { #>
201
+ <mark class="error"><span class="dashicons dashicons-no-alt"></span></mark>
202
+ <# } #>
203
+ </td>
204
+ </tr>
205
+ <# }); #>
206
+ <# } else { #>
207
+ <tr>
208
+ <td class="plugins-list-table-blank-state" colspan="3"><p><?php _e( 'No plugins are needed to import this demo.', 'themegrill-demo-importer' ); ?></p></td>
209
+ </tr>
210
+ <# } #>
211
+ </tbody>
212
+ </table>
213
+
214
+ <# if ( data.tags ) { #>
215
+ <p class="theme-tags"><span><?php _e( 'Tags:', 'themegrill-demo-importer' ); ?></span> {{{ data.tags }}}</p>
216
+ <# } #>
217
+ </div>
218
+ </div>
219
+
220
+ <div class="theme-actions">
221
+ <div class="active-theme">
222
+ <a href="{{{ data.actions.preview }}}" class="button button-primary live-preview" target="_blank"><?php _e( 'Live Preview', 'themegrill-demo-importer' ); ?></a>
223
+ </div>
224
+ <div class="inactive-theme">
225
+ <?php
226
+ /* translators: %s: Demo name */
227
+ $aria_label = sprintf( _x( 'Import %s', 'demo', 'themegrill-demo-importer' ), '{{ data.name }}' );
228
+ ?>
229
+ <# if ( _.isEmpty( data.hasNotice ) ) { #>
230
+ <# if ( data.imported ) { #>
231
+ <a href="{{{ data.actions.preview }}}" class="button button-primary live-preview" target="_blank"><?php _e( 'Live Preview', 'themegrill-demo-importer' ); ?></a>
232
+ <# } else { #>
233
+ <a class="button button-primary hide-if-no-js demo-import" href="#" data-name="{{ data.name }}" data-slug="{{ data.id }}" aria-label="<?php echo $aria_label; ?>"><?php _e( 'Import', 'themegrill-demo-importer' ); ?></a>
234
+ <# } #>
235
+ <# } #>
236
+ <a class="button button-secondary demo-preview" target="_blank" href="{{{ data.actions.demo_url }}}"><?php _e( 'Preview', 'themegrill-demo-importer' ); ?></a>
237
+ </div>
238
+
239
+ <# if ( data.package && data.actions['delete'] ) { #>
240
+ <a href="{{{ data.actions['delete'] }}}" class="button delete-theme delete-demo"><?php _e( 'Delete', 'themegrill-demo-importer' ); ?></a>
241
+ <# } #>
242
+ </div>
243
  </div>
244
+ </script>
245
+
246
+ <?php
247
+ wp_print_request_filesystem_credentials_modal();
248
+ wp_print_admin_notice_templates();
includes/includes/admin/views/html-admin-page-installer-preview.php ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Admin View: Page - Demo Preview
4
+ */
5
+
6
+ if ( ! defined( 'ABSPATH' ) ) {
7
+ exit;
8
+ }
9
+
10
+ $previews = $this->prepare_previews_for_js( $this->demo_packages );
11
+
12
+ ?>
13
+ <div class="theme-browser rendered">
14
+ <div class="themes wp-clearfix">
15
+ <?php foreach ( $previews as $demo ) : ?>
16
+ <div class="theme" tabindex="0">
17
+ <a target="_blank" href="<?php echo esc_url( $demo['actions']['preview_url'] ); ?>">
18
+ <?php if ( $demo['screenshot'] ) : ?>
19
+ <div class="theme-screenshot">
20
+ <img src="<?php echo esc_url( $demo['screenshot'] ); ?>" alt="" />
21
+ </div>
22
+ <?php else : ?>
23
+ <div class="theme-screenshot blank"></div>
24
+ <?php endif; ?>
25
+ <span class="more-details"><?php _e( 'Demo Preview', 'themegrill-demo-importer' ); ?></span>
26
+ </a>
27
+ <div class="theme-author"><?php
28
+ /* translators: %s: Demo author name */
29
+ printf( __( 'By %s', 'themegrill-demo-importer' ), $demo['author'] );
30
+ ?></div>
31
+ <h3 class="theme-name"><?php echo esc_html( $demo['name'] ); ?></h3>
32
+
33
+ <div class="theme-actions">
34
+ <?php if ( ! $demo['installed'] ) : ?>
35
+ <?php
36
+ /* translators: %s: Demo name */
37
+ $aria_label = sprintf( _x( 'Download %s', 'demo', 'themegrill-demo-importer' ), esc_attr( $demo['name'] ) );
38
+ ?>
39
+ <a class="button button-primary demo-download" data-name="<?php echo esc_attr( $demo['name'] ); ?>" href="<?php echo esc_url( $demo['actions']['download_url'] ); ?>" aria-label="<?php echo esc_attr( $aria_label ); ?>"><?php _e( 'Download', 'themegrill-demo-importer' ); ?></a>
40
+ <?php endif; ?>
41
+ <a class="button button-secondary demo-preview" target="_blank" href="<?php echo esc_url( $demo['actions']['preview_url'] ); ?>"><?php _e( 'Preview', 'themegrill-demo-importer' ); ?></a>
42
+ </div>
43
+
44
+ <?php if ( $demo['installed'] ) : ?>
45
+ <div class="notice notice-success notice-alt inline"><p><?php _ex( 'Installed', 'theme', 'themegrill-demo-importer' ); ?></p></div>
46
+ <?php endif; ?>
47
+ </div>
48
+ <?php endforeach; ?>
49
+ </div>
50
+ </div>
includes/includes/admin/views/html-admin-page-installer-uploads.php ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Admin View: Page - Demo Uploads
4
+ */
5
+
6
+ if ( ! defined( 'ABSPATH' ) ) {
7
+ exit;
8
+ }
9
+
10
+ ?>
11
+ <div class="theme-browser">
12
+ <div class="themes wp-clearfix">
13
+ <?php foreach ( $demos as $demo ) : ?>
14
+ <div class="theme<?php if ( $demo['active'] ) echo ' active'; ?>" tabindex="0" aria-describedby="<?php echo esc_attr( $demo['id'] . '-action ' . $demo['id'] . '-name' ); ?>">
15
+ <?php if ( $demo['screenshot'] ) : ?>
16
+ <div class="theme-screenshot">
17
+ <img src="<?php echo esc_url( $demo['screenshot'] ); ?>" alt="" />
18
+ </div>
19
+ <?php else : ?>
20
+ <div class="theme-screenshot blank"></div>
21
+ <?php endif; ?>
22
+
23
+ <span class="more-details" id="<?php echo esc_attr( $demo['id'] . '-action' ); ?>"><?php esc_html_e( 'Demo Details', 'themegrill-demo-importer' ); ?></span>
24
+ <div class="theme-author"><?php
25
+ /* translators: %s: Demo author name */
26
+ printf( __( 'By %s', 'themegrill-demo-importer' ), $demo['author'] );
27
+ ?></div>
28
+
29
+ <?php if ( $demo['active'] ) { ?>
30
+ <h2 class="theme-name" id="demo-name"><?php
31
+ /* translators: %s: Demo name */
32
+ printf( __( '<span>Imported:</span> %s', 'themegrill-demo-importer' ), esc_html( $demo['name'] ) );
33
+ ?></h2>
34
+ <?php } else { ?>
35
+ <h2 class="theme-name" id="<?php echo esc_attr( $demo['id'] . '-name' ); ?>"><?php echo esc_html( $demo['name'] ); ?></h2>
36
+ <?php } ?>
37
+
38
+ <div class="theme-actions">
39
+ <?php if ( $demo['active'] ) : ?>
40
+ <a class="button button-primary live-preview" target="_blank" href="<?php echo esc_url( $demo['actions']['preview'] ); ?>"><?php _e( 'Live Preview', 'themegrill-demo-importer' ); ?></a>
41
+ <?php else : ?>
42
+ <?php if ( ! empty( $demo['hasNotice'] ) ) : ?>
43
+ <?php if ( isset( $demo['hasNotice']['required_theme'] ) ) : ?>
44
+ <a class="button button-primary hide-if-no-js tips demo-import disabled" href="#" data-name=<?php echo esc_attr( $demo['name'] );?>" data-slug="<?php echo esc_attr( $demo['id'] ); ?>" data-tip="<?php echo esc_attr( sprintf( __( 'Required %s theme must be activated to import this demo.', 'themegrill-demo-importer' ), $demo['theme'] ) ); ?>"><?php _e( 'Import', 'themegrill-demo-importer' ); ?></a>
45
+ <?php elseif ( isset( $demo['hasNotice']['required_plugins'] ) ) : ?>
46
+ <a class="button button-primary hide-if-no-js tips demo-import disabled" href="#" data-name=<?php echo esc_attr( $demo['name'] );?>" data-slug="<?php echo esc_attr( $demo['id'] ); ?>" data-tip="<?php echo esc_attr( 'Required Plugin must be activated to import this demo.', 'themegrill-demo-importer' ); ?>"><?php _e( 'Import', 'themegrill-demo-importer' ); ?></a>
47
+ <?php endif; ?>
48
+ <?php else : ?>
49
+ <?php
50
+ /* translators: %s: Demo name */
51
+ $aria_label = sprintf( _x( 'Import %s', 'demo', 'themegrill-demo-importer' ), esc_attr( $demo['name'] ) );
52
+ ?>
53
+ <a class="button button-primary hide-if-no-js import" href="#" data-name=<?php echo esc_attr( $demo['name'] );?>" data-slug="<?php echo esc_attr( $demo['id'] ); ?>" aria-label="<?php echo $aria_label; ?>"><?php _e( 'Import', 'themegrill-demo-importer' ); ?></a>
54
+ <?php endif; ?>
55
+ <a class="button button-secondary demo-preview" target="_blank" href="<?php echo esc_url( $demo['actions']['demo_url'] ); ?>"><?php _e( 'Preview', 'themegrill-demo-importer' ); ?></a>
56
+ <?php endif; ?>
57
+ </div>
58
+ </div>
59
+ <?php endforeach; ?>
60
+ </div>
61
+ </div>
62
+ <div class="theme-overlay"></div>
includes/includes/admin/views/html-admin-page-installer.php ADDED
@@ -0,0 +1,295 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Admin View: Page - Installer
4
+ */
5
+
6
+ if ( ! defined( 'ABSPATH' ) ) {
7
+ exit;
8
+ }
9
+
10
+ global $current_filter;
11
+
12
+ $current_filter = empty( $_GET['browse'] ) ? 'welcome' : sanitize_title( $_GET['browse'] );
13
+ $demo_imported_id = get_option( 'themegrill_demo_imported_id' );
14
+ $demo_filter_links = apply_filters( 'themegrill_demo_importer_filter_links_array', array(
15
+ 'welcome' => __( 'Welcome', 'themegrill-demo-importer' ),
16
+ 'uploads' => __( 'Installed Demos', 'themegrill-demo-importer' ),
17
+ 'preview' => __( 'Theme Demos', 'themegrill-demo-importer' ),
18
+ ) );
19
+
20
+ ?>
21
+ <div class="wrap demo-installer">
22
+ <h1><?php
23
+ esc_html_e( 'Demo Importer', 'themegrill-demo-importer' );
24
+ if ( current_user_can( 'upload_files' ) ) {
25
+ echo ' <button type="button" class="upload-view-toggle page-title-action hide-if-no-js tg-demo-upload" aria-expanded="false">' . __( 'Upload Demo', 'themegrill-demo-importer' ) . '</button>';
26
+ }
27
+ ?></h1>
28
+ <?php if ( ! get_option( 'themegrill_demo_imported_notice_dismiss' ) && in_array( $demo_imported_id, array_keys( $this->demo_config ) ) ) : ?>
29
+ <div id="message" class="notice notice-info is-dismissible" data-notice_id="demo-importer">
30
+ <p><?php printf( __( '<strong>Notice</strong> &#8211; If you want to completely remove a demo installation after importing it, you can use a plugin like %1$sWordPress Reset%2$s.', 'themegrill-demo-importer' ), '<a target="_blank" href="' . esc_url( 'https://wordpress.org/plugins/wordpress-reset/' ) . '">', '</a>' ); ?></p>
31
+ </div>
32
+ <?php endif; ?>
33
+ <div class="error hide-if-js">
34
+ <p><?php _e( 'The Demo Importer screen requires JavaScript.', 'themegrill-demo-importer' ); ?></p>
35
+ </div>
36
+
37
+ <div class="upload-theme">
38
+ <p class="install-help"><?php _e( 'If you have a demo pack in a .zip format, you may install it by uploading it here.', 'themegrill-demo-importer' ); ?></p>
39
+ <form method="post" enctype="multipart/form-data" class="wp-upload-form" action="<?php echo self_admin_url( 'themes.php?page=demo-importer&action=upload-demo' ); ?>">
40
+ <?php wp_nonce_field( 'demo-upload' ); ?>
41
+ <label class="screen-reader-text" for="demozip"><?php _e( 'Demo zip file', 'themegrill-demo-importer' ); ?></label>
42
+ <input type="file" id="demozip" name="demozip" />
43
+ <?php submit_button( __( 'Install Now', 'themegrill-demo-importer' ), 'button', 'install-demo-submit', false ); ?>
44
+ </form>
45
+ </div>
46
+
47
+ <h2 class="screen-reader-text hide-if-no-js"><?php _e( 'Filter demos list', 'themegrill-demo-importer' ); ?></h2>
48
+
49
+ <div class="wp-filter hide-if-no-js">
50
+ <div class="filter-count">
51
+ <span class="count theme-count demo-count"><?php echo 'preview' == $current_filter ? count( $this->demo_packages ) : count( $this->demo_config ); ?></span>
52
+ </div>
53
+
54
+ <ul class="filter-links">
55
+ <?php
56
+ foreach ( $demo_filter_links as $name => $label ) {
57
+ if ( ( empty( $this->demo_config ) && 'uploads' == $name ) || ( empty( $this->demo_packages ) && 'preview' == $name ) ) {
58
+ continue;
59
+ }
60
+ echo '<li><a href="' . admin_url( 'themes.php?page=demo-importer&browse=' . $name ) . '" class="demo-tab ' . ( $current_filter == $name ? 'current' : '' ) . '">' . $label . '</a></li>';
61
+ }
62
+ do_action( 'themegrill_demo_importer_filter_links' );
63
+ ?>
64
+ </ul>
65
+
66
+ <div class="search-form"></div>
67
+ </div>
68
+ <?php if ( 'welcome' === $current_filter ) : ?>
69
+ <div id="welcome-panel" class="welcome-panel">
70
+ <div class="welcome-panel-content">
71
+ <h2><?php _e( 'Welcome to ThemeGrill Demo Importer!', 'themegrill-demo-importer' ); ?></h2>
72
+ <h3><?php _e( 'Get Started','themegrill-demo-importer' ); ?></h3>
73
+ <div class="welcome-panel-column-container">
74
+ <div class="welcome-panel-column">
75
+ <ul>
76
+ <li><?php printf( __( '1. Visit <a href="%s" target="_blank"><strong>this page</strong></a> and download demo zip file.','themegrill-demo-importer' ),esc_url( 'http://themegrill.com/theme-demo-file-downloads/' ) ); ?></li>
77
+ <li><?php _e( '2. Click <strong>Upload Demo</strong> button on the top of this Page.','themegrill-demo-importer' ); ?></li>
78
+ <li><?php _e( '3. Browse the demo zip file and click <strong>Install Now</strong>.','themegrill-demo-importer' ); ?></li>
79
+ <li><?php _e( '4. Go to <strong>Installed Demos</strong> tab.','themegrill-demo-importer' ); ?></li>
80
+ <li><?php _e( '5. Click <strong>Import</strong> button and wait for few minutes. Done!','themegrill-demo-importer' ); ?></li>
81
+ </ul>
82
+ </div>
83
+ </div>
84
+ </div>
85
+ </div>
86
+ <?php else : ?>
87
+ <h2 class="screen-reader-text hide-if-no-js"><?php _e( 'Available demos list', 'themegrill-demo-importer' ); ?></h2>
88
+ <?php
89
+ if ( in_array( $current_filter, array( 'uploads', 'preview' ) ) ) {
90
+ include_once( dirname( __FILE__ ) . "/html-admin-page-installer-{$current_filter}.php" );
91
+ }
92
+ do_action( 'themegrill_demo_importer_' . $current_filter );
93
+ ?>
94
+ <p class="no-themes"><?php _e( 'No demos found. Try a different search.', 'themegrill-demo-importer' ); ?></p>
95
+ <?php endif; ?>
96
+ </div>
97
+
98
+ <script id="tmpl-demo" type="text/template">
99
+ <# if ( data.screenshot ) { #>
100
+ <div class="theme-screenshot">
101
+ <img src="{{ data.screenshot }}" alt="" />
102
+ </div>
103
+ <# } else { #>
104
+ <div class="theme-screenshot blank"></div>
105
+ <# } #>
106
+
107
+ <span class="more-details" id="{{ data.id }}-action"><?php _e( 'Demo Details', 'themegrill-demo-importer' ); ?></span>
108
+ <div class="theme-author"><?php
109
+ /* translators: %s: Demo author name */
110
+ printf( __( 'By %s', 'themegrill-demo-importer' ), '{{{ data.author }}}' );
111
+ ?></div>
112
+
113
+ <# if ( data.active ) { #>
114
+ <h2 class="theme-name" id="{{ data.id }}-name"><?php
115
+ /* translators: %s: Demo name */
116
+ printf( __( '<span>Imported:</span> %s', 'themegrill-demo-importer' ), '{{{ data.name }}}' );
117
+ ?></h2>
118
+ <# } else { #>
119
+ <h2 class="theme-name" id="{{ data.id }}-name">{{{ data.name }}}</h2>
120
+ <# } #>
121
+
122
+ <div class="theme-actions">
123
+ <# if ( data.active ) { #>
124
+ <a class="button button-primary live-preview" target="_blank" href="{{{ data.actions.preview }}}"><?php _e( 'Live Preview', 'themegrill-demo-importer' ); ?></a>
125
+ <# } else { #>
126
+ <# if ( ! _.isEmpty( data.hasNotice ) ) { #>
127
+ <# if ( data.hasNotice['required_theme'] ) { #>
128
+ <a class="button button-primary hide-if-no-js tips demo-import disabled" href="#" data-name="{{ data.name }}" data-slug="{{ data.id }}" data-tip="<?php echo esc_attr( sprintf( __( 'Required %s theme must be activated to import this demo.', 'themegrill-demo-importer' ), '{{{ data.theme }}}' ) ); ?>"><?php _e( 'Import', 'themegrill-demo-importer' ); ?></a>
129
+ <# } else if ( data.hasNotice['required_plugins'] ) { #>
130
+ <a class="button button-primary hide-if-no-js tips demo-import disabled" href="#" data-name="{{ data.name }}" data-slug="{{ data.id }}" data-tip="<?php echo esc_attr( 'Required Plugin must be activated to import this demo.', 'themegrill-demo-importer' ); ?>"><?php _e( 'Import', 'themegrill-demo-importer' ); ?></a>
131
+ <# } #>
132
+ <# } else { #>
133
+ <?php
134
+ /* translators: %s: Demo name */
135
+ $aria_label = sprintf( _x( 'Import %s', 'demo', 'themegrill-demo-importer' ), '{{ data.name }}' );
136
+ ?>
137
+ <a class="button button-primary hide-if-no-js demo-import" href="#" data-name="{{ data.name }}" data-slug="{{ data.id }}" aria-label="<?php echo $aria_label; ?>"><?php _e( 'Import', 'themegrill-demo-importer' ); ?></a>
138
+ <# } #>
139
+ <a class="button button-secondary demo-preview" target="_blank" href="{{{ data.actions.demo_url }}}"><?php _e( 'Preview', 'themegrill-demo-importer' ); ?></a>
140
+ <# } #>
141
+ </div>
142
+
143
+ <# if ( data.imported ) { #>
144
+ <div class="notice notice-success notice-alt"><p><?php _ex( 'Imported', 'demo', 'themegrill-demo-importer' ); ?></p></div>
145
+ <# } #>
146
+ </script>
147
+
148
+ <script id="tmpl-demo-single" type="text/template">
149
+ <div class="theme-backdrop"></div>
150
+ <div class="theme-wrap wp-clearfix">
151
+ <div class="theme-header">
152
+ <button class="left dashicons dashicons-no"><span class="screen-reader-text"><?php _e( 'Show previous demo', 'themegrill-demo-importer' ); ?></span></button>
153
+ <button class="right dashicons dashicons-no"><span class="screen-reader-text"><?php _e( 'Show next demo', 'themegrill-demo-importer' ); ?></span></button>
154
+ <button class="close dashicons dashicons-no"><span class="screen-reader-text"><?php _e( 'Close details dialog', 'themegrill-demo-importer' ); ?></span></button>
155
+ </div>
156
+ <div class="theme-about wp-clearfix">
157
+ <div class="theme-screenshots">
158
+ <# if ( data.screenshot ) { #>
159
+ <div class="screenshot"><img src="{{ data.screenshot }}" alt="" /></div>
160
+ <# } else { #>
161
+ <div class="screenshot blank"></div>
162
+ <# } #>
163
+ </div>
164
+
165
+ <div class="theme-info">
166
+ <# if ( data.active ) { #>
167
+ <span class="current-label"><?php _e( 'Imported Demo', 'themegrill-demo-importer' ); ?></span>
168
+ <# } #>
169
+ <h2 class="theme-name">{{{ data.name }}}<span class="theme-version"><?php printf( __( 'Version: %s', 'themegrill-demo-importer' ), '{{ data.version }}' ); ?></span></h2>
170
+ <p class="theme-author"><?php printf( __( 'By %s', 'themegrill-demo-importer' ), '{{{ data.authorAndUri }}}' ); ?></p>
171
+
172
+ <# if ( ! _.isEmpty( data.hasNotice ) ) { #>
173
+ <div class="notice demo-message notice-warning notice-alt">
174
+ <# if ( data.hasNotice['required_theme'] ) { #>
175
+ <p class="demo-notice"><?php printf( esc_html__( 'Required %s theme must be activated to import this demo.', 'themegrill-demo-importer' ), '<strong>{{{ data.theme }}}</strong>' ); ?></p>
176
+ <# } else if ( data.hasNotice['required_plugins'] ) { #>
177
+ <p class="demo-notice"><?php _e( 'Required Plugin must be activated to import this demo.', 'themegrill-demo-importer' ); ?></p>
178
+ <# } #>
179
+ </div>
180
+ <# } #>
181
+ <p class="theme-description">{{{ data.description }}}</p>
182
+
183
+ <h3 class="plugins-info"><?php _e( 'Plugins Information', 'themegrill-demo-importer' ); ?></h3>
184
+
185
+ <table class="plugins-list-table widefat">
186
+ <thead>
187
+ <tr>
188
+ <th class="plugin-name"><?php esc_html_e( 'Plugin Name', 'themegrill-demo-importer' ); ?></th>
189
+ <th class="plugin-type"><?php esc_html_e( 'Type', 'themegrill-demo-importer' ); ?></th>
190
+ <th class="plugin-status"><?php esc_html_e( 'Status', 'themegrill-demo-importer' ); ?></th>
191
+ </tr>
192
+ </thead>
193
+ <tbody>
194
+ <# if ( ! _.isEmpty( data.plugins ) ) { #>
195
+ <# _.each( data.plugins, function( plugin, slug ) { #>
196
+ <tr>
197
+ <td class="plugin-name">
198
+ <# if ( plugin.link ) { #>
199
+ <a href="{{{ plugin.link }}}" target="_blank">{{{ plugin.name }}}</a>
200
+ <# } else { #>
201
+ <a href="<?php echo esc_url( admin_url( 'plugin-install.php?tab=search&type=term&s=' ) ); ?>{{ slug }}" target="_blank">{{ plugin.name }}</a>
202
+ <# } #>
203
+ </td>
204
+ <td class="plugin-type">
205
+ <# if ( plugin.required ) { #>
206
+ <span class="required"><?php esc_html_e( 'Required', 'themegrill-demo-importer' ); ?></span>
207
+ <# } else { #>
208
+ <span class="recommended"><?php esc_html_e( 'Recommended', 'themegrill-demo-importer' ); ?></span>
209
+ <# } #>
210
+ </td>
211
+ <td class="plugin-status">
212
+ <# if ( plugin.is_active ) { #>
213
+ <mark class="yes"><span class="dashicons dashicons-yes"></span></mark>
214
+ <# } else { #>
215
+ <mark class="error"><span class="dashicons dashicons-no-alt"></span></mark>
216
+ <# } #>
217
+ </td>
218
+ </tr>
219
+ <# }); #>
220
+ <# } else { #>
221
+ <tr>
222
+ <td class="plugins-list-table-blank-state" colspan="3"><p><?php _e( 'No plugins are needed to import this demo.', 'themegrill-demo-importer' ); ?></p></td>
223
+ </tr>
224
+ <# } #>
225
+ </tbody>
226
+ </table>
227
+
228
+ <# if ( data.tags ) { #>
229
+ <p class="theme-tags"><span><?php _e( 'Tags:', 'themegrill-demo-importer' ); ?></span> {{{ data.tags }}}</p>
230
+ <# } #>
231
+ </div>
232
+ </div>
233
+
234
+ <div class="theme-actions">
235
+ <div class="active-theme">
236
+ <a href="{{{ data.actions.preview }}}" class="button button-primary live-preview" target="_blank"><?php _e( 'Live Preview', 'themegrill-demo-importer' ); ?></a>
237
+ </div>
238
+ <div class="inactive-theme">
239
+ <?php
240
+ /* translators: %s: Demo name */
241
+ $aria_label = sprintf( _x( 'Import %s', 'demo', 'themegrill-demo-importer' ), '{{ data.name }}' );
242
+ ?>
243
+ <# if ( _.isEmpty( data.hasNotice ) ) { #>
244
+ <# if ( data.imported ) { #>
245
+ <a href="{{{ data.actions.preview }}}" class="button button-primary live-preview" target="_blank"><?php _e( 'Live Preview', 'themegrill-demo-importer' ); ?></a>
246
+ <# } else { #>
247
+ <a class="button button-primary hide-if-no-js demo-import" href="#" data-name="{{ data.name }}" data-slug="{{ data.id }}" aria-label="<?php echo $aria_label; ?>"><?php _e( 'Import', 'themegrill-demo-importer' ); ?></a>
248
+ <# } #>
249
+ <# } #>
250
+ <a class="button button-secondary demo-preview" target="_blank" href="{{{ data.actions.demo_url }}}"><?php _e( 'Preview', 'themegrill-demo-importer' ); ?></a>
251
+ </div>
252
+
253
+ <# if ( data.package && data.actions['delete'] ) { #>
254
+ <a href="{{{ data.actions['delete'] }}}" class="button delete-theme delete-demo"><?php _e( 'Delete', 'themegrill-demo-importer' ); ?></a>
255
+ <# } #>
256
+ </div>
257
+ </div>
258
+ </script>
259
+
260
+ <script id="tmpl-demo-preview" type="text/template">
261
+ <a target="_blank" href="{{{ data.actions.preview_url }}}">
262
+ <# if ( data.screenshot ) { #>
263
+ <div class="theme-screenshot">
264
+ <img src="{{ data.screenshot }}" alt="" />
265
+ </div>
266
+ <# } else { #>
267
+ <div class="theme-screenshot blank"></div>
268
+ <# } #>
269
+ <span class="more-details"><?php _e( 'Demo Preview', 'themegrill-demo-importer' ); ?></span>
270
+ </a>
271
+ <div class="theme-author"><?php
272
+ /* translators: %s: Demo author name */
273
+ printf( __( 'By %s', 'themegrill-demo-importer' ), '{{{ data.author }}}' );
274
+ ?></div>
275
+ <h3 class="theme-name">{{ data.name }}</h3>
276
+
277
+ <div class="theme-actions">
278
+ <# if ( ! data.installed ) { #>
279
+ <?php
280
+ /* translators: %s: Demo name */
281
+ $aria_label = sprintf( _x( 'Download %s', 'demo', 'themegrill-demo-importer' ), '{{ data.name }}' );
282
+ ?>
283
+ <a class="button button-primary demo-download" data-name="{{ data.name }}" href="{{ data.actions.download_url }}" aria-label="<?php echo esc_attr( $aria_label ); ?>"><?php _e( 'Download', 'themegrill-demo-importer' ); ?></a>
284
+ <# } #>
285
+ <a class="button button-secondary demo-preview" target="_blank" href="{{{ data.actions.preview_url }}}"><?php _e( 'Preview', 'themegrill-demo-importer' ); ?></a>
286
+ </div>
287
+
288
+ <# if ( data.installed ) { #>
289
+ <div class="notice notice-success notice-alt"><p><?php _ex( 'Installed', 'demo', 'themegrill-demo-importer' ); ?></p></div>
290
+ <# } #>
291
+ </script>
292
+
293
+ <?php
294
+ wp_print_request_filesystem_credentials_modal();
295
+ wp_print_admin_notice_templates();
includes/includes/functions-demo-importer.php CHANGED
@@ -71,7 +71,7 @@ function tg_get_attachment_id( $filename ) {
71
  'compare' => 'LIKE',
72
  'key' => '_wp_attachment_metadata',
73
  ),
74
- )
75
  );
76
 
77
  $query = new WP_Query( $query_args );
@@ -89,53 +89,147 @@ function tg_get_attachment_id( $filename ) {
89
  $attachment_id = $post_id;
90
  break;
91
  }
92
-
93
  }
94
-
95
  }
96
 
97
  return $attachment_id;
98
  }
99
 
100
  /**
101
- * Retrieve the links for each plugins list.
102
- *
103
- * @param array $plugins_list
104
- * @return mixed
105
  */
106
- function tg_get_plugins_links( $plugins_list ) {
107
- $plugins_link = array();
108
-
109
- foreach ( $plugins_list as $plugin_slug => $plugin_data ) {
110
- if ( isset( $plugin_data['link'] ) ) {
111
- $plugin_url = $plugin_data['link'];
112
- } else {
113
- $plugin_url = admin_url( 'plugin-install.php?tab=search&type=term&s=' . $plugin_slug );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
114
  }
115
 
116
- $plugins_link[ $plugin_slug ] = '<a href="' . esc_url( $plugin_url ) . '" target="_blank">' . esc_html( $plugin_data['name'] ) . '</a>';
117
  }
118
 
119
- return implode( ', ', $plugins_link );
 
 
 
 
 
 
 
 
 
 
120
  }
 
121
 
122
  /**
123
- * Checks whether the required plugins are active.
 
124
  *
125
- * @param array $raw_plugins_list Plugins list to check.
126
- * @return bool
 
 
 
127
  */
128
- function tg_is_plugins_active( $raw_plugins_list ) {
129
- $plugins_data = array();
130
- $plugins_list = wp_list_pluck( $raw_plugins_list, 'slug' );
 
 
 
131
 
132
- foreach ( $plugins_list as $plugin_name => $plugin_slug ) {
133
- if ( is_plugin_active( $plugin_slug ) ) {
134
- $plugins_data[ $plugin_name ] = $plugin_slug;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
135
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
136
  }
137
 
138
- return array_diff( $plugins_list, $plugins_data ) ? true : false;
139
  }
140
 
141
  /**
71
  'compare' => 'LIKE',
72
  'key' => '_wp_attachment_metadata',
73
  ),
74
+ ),
75
  );
76
 
77
  $query = new WP_Query( $query_args );
89
  $attachment_id = $post_id;
90
  break;
91
  }
 
92
  }
 
93
  }
94
 
95
  return $attachment_id;
96
  }
97
 
98
  /**
99
+ * Ajax handler for deleting a demo pack.
100
+ * @see tg_delete_demo_pack()
 
 
101
  */
102
+ function tg_ajax_delete_demo_pack() {
103
+ check_ajax_referer( 'updates' );
104
+
105
+ if ( empty( $_POST['slug'] ) ) {
106
+ wp_send_json_error( array(
107
+ 'slug' => '',
108
+ 'errorCode' => 'no_demo_specified',
109
+ 'errorMessage' => __( 'No demo specified.', 'themegrill-demo-importer' ),
110
+ ) );
111
+ }
112
+
113
+ $demo_pack = preg_replace( '/[^A-z0-9_\-]/', '', wp_unslash( $_POST['slug'] ) );
114
+ $status = array(
115
+ 'delete' => 'demo_pack',
116
+ 'slug' => $demo_pack,
117
+ );
118
+
119
+ if ( ! current_user_can( 'upload_files' ) ) {
120
+ $status['errorMessage'] = __( 'Sorry, you are not allowed to delete demo on this site.', 'themegrill-demo-importer' );
121
+ wp_send_json_error( $status );
122
+ }
123
+
124
+ // Check filesystem credentials. `tg_delete_demo_pack()` will bail otherwise.
125
+ $url = wp_nonce_url( 'tthemes.php?page=demo-importer&browse=uploads&action=delete&demo_pack=' . urlencode( $demo_pack ), 'delete-demo_' . $demo_pack );
126
+ ob_start();
127
+ $credentials = request_filesystem_credentials( $url );
128
+ ob_end_clean();
129
+ if ( false === $credentials || ! WP_Filesystem( $credentials ) ) {
130
+ global $wp_filesystem;
131
+
132
+ $status['errorCode'] = 'unable_to_connect_to_filesystem';
133
+ $status['errorMessage'] = __( 'Unable to connect to the filesystem. Please confirm your credentials.', 'themegrill-demo-importer' );
134
+
135
+ // Pass through the error from WP_Filesystem if one was raised.
136
+ if ( $wp_filesystem instanceof WP_Filesystem_Base && is_wp_error( $wp_filesystem->errors ) && $wp_filesystem->errors->get_error_code() ) {
137
+ $status['errorMessage'] = esc_html( $wp_filesystem->errors->get_error_message() );
138
  }
139
 
140
+ wp_send_json_error( $status );
141
  }
142
 
143
+ $result = tg_delete_demo_pack( $demo_pack );
144
+
145
+ if ( is_wp_error( $result ) ) {
146
+ $status['errorMessage'] = $result->get_error_message();
147
+ wp_send_json_error( $status );
148
+ } elseif ( false === $result ) {
149
+ $status['errorMessage'] = __( 'Demo could not be deleted.', 'themegrill-demo-importer' );
150
+ wp_send_json_error( $status );
151
+ }
152
+
153
+ wp_send_json_success( $status );
154
  }
155
+ add_action( 'wp_ajax_delete-demo', 'tg_ajax_delete_demo_pack', 1 );
156
 
157
  /**
158
+ * Remove a demo.
159
+ *
160
  *
161
+ * @global WP_Filesystem_Base $wp_filesystem Subclass
162
+ *
163
+ * @param string $demo_pack Demo pack to delete completely.
164
+ * @param string $redirect Redirect to page when complete.
165
+ * @return void|bool|WP_Error When void, echoes content.
166
  */
167
+ function tg_delete_demo_pack( $demo_pack, $redirect = '' ) {
168
+ global $wp_filesystem;
169
+
170
+ $upload_dir = wp_upload_dir();
171
+ $demo_packs = $upload_dir['basedir'] . '/tg-demo-pack/';
172
+ $demo_imported_id = get_option( 'themegrill_demo_imported_id' );
173
 
174
+ if ( empty( $demo_pack ) ) {
175
+ return false;
176
+ }
177
+
178
+ if ( empty( $redirect ) ) {
179
+ $redirect = wp_nonce_url( 'themes.php?page=demo-importer&browse=uploads&action=delete&demo_pack=' . urlencode( $demo_pack ), 'delete-demo_' . $demo_pack );
180
+ }
181
+
182
+ ob_start();
183
+ $credentials = request_filesystem_credentials( $redirect );
184
+ $data = ob_get_clean();
185
+
186
+ if ( false === $credentials ) {
187
+ if ( ! empty( $data ) ) {
188
+ include_once( ABSPATH . 'wp-admin/admin-header.php' );
189
+ echo $data;
190
+ include( ABSPATH . 'wp-admin/admin-footer.php' );
191
+ exit;
192
+ }
193
+ return;
194
+ }
195
+
196
+ if ( ! WP_Filesystem( $credentials ) ) {
197
+ ob_start();
198
+ request_filesystem_credentials( $redirect, '', true ); // Failed to connect, Error and request again.
199
+ $data = ob_get_clean();
200
+
201
+ if ( ! empty( $data ) ) {
202
+ include_once( ABSPATH . 'wp-admin/admin-header.php' );
203
+ echo $data;
204
+ include( ABSPATH . 'wp-admin/admin-footer.php' );
205
+ exit;
206
  }
207
+ return;
208
+ }
209
+
210
+ if ( ! is_object( $wp_filesystem ) ) {
211
+ return new WP_Error( 'fs_unavailable', __( 'Could not access filesystem.', 'themegrill-demo-importer' ) );
212
+ }
213
+
214
+ if ( is_wp_error( $wp_filesystem->errors ) && $wp_filesystem->errors->get_error_code() ) {
215
+ return new WP_Error( 'fs_error', __( 'Filesystem error.', 'themegrill-demo-importer' ), $wp_filesystem->errors );
216
+ }
217
+
218
+ // Get the base demo folder.
219
+ $demos_dir = $wp_filesystem->find_folder( $demo_packs );
220
+ if ( empty( $demos_dir ) ) {
221
+ return new WP_Error( 'fs_no_themes_dir', __( 'Unable to locate ThemeGrill demo pack directory.', 'themegrill-demo-importer' ) );
222
+ }
223
+
224
+ $demos_dir = trailingslashit( $demos_dir );
225
+ $demo_dir = trailingslashit( $demos_dir . $demo_pack );
226
+ $deleted = $wp_filesystem->delete( $demo_dir, true );
227
+
228
+ if ( ! $deleted ) {
229
+ return new WP_Error( 'could_not_remove_demo', sprintf( __( 'Could not fully remove the demo %s.', 'themegrill-demo-importer' ), $demo ) );
230
  }
231
 
232
+ return true;
233
  }
234
 
235
  /**
languages/themegrill-demo-importer.pot CHANGED
@@ -2,9 +2,9 @@
2
  # This file is distributed under the GPLv3 or later.
3
  msgid ""
4
  msgstr ""
5
- "Project-Id-Version: ThemeGrill Demo Importer 1.0.0\n"
6
  "Report-Msgid-Bugs-To: themegrill@gmail.com\n"
7
- "POT-Creation-Date: 2016-12-13 06:51:06+00:00\n"
8
  "MIME-Version: 1.0\n"
9
  "Content-Type: text/plain; charset=utf-8\n"
10
  "Content-Transfer-Encoding: 8bit\n"
@@ -13,36 +13,120 @@ msgstr ""
13
  "Language-Team: LANGUAGE <EMAIL@ADDRESS>\n"
14
  "X-Generator: grunt-wp-i18n 0.5.4\n"
15
 
16
- #: includes/class-demo-importer.php:135
17
- #: includes/includes/admin/views/html-admin-page-importer.php:20
 
 
18
  msgid "Demo Importer"
19
  msgstr ""
20
 
21
- #: includes/class-demo-importer.php:156
22
- msgid "Importing Failed. Try again!"
 
 
 
 
23
  msgstr ""
24
 
25
- #: includes/class-demo-importer.php:157
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
  msgid ""
27
  "Importing demo content will replicate the live demo and overwrites your "
28
  "current customizer, widgets and other settings. It might take few minutes "
29
  "to complete the demo import. Are you sure you want to import this demo?"
30
  msgstr ""
31
 
32
- #: includes/class-demo-importer.php:204
33
- msgid "Sorry, you are not allowed to install demo on this site."
 
 
 
 
 
 
 
 
 
 
 
 
34
  msgstr ""
35
 
36
  #: includes/class-demo-importer.php:211
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
  msgid "Installing Demo from uploaded file: %s"
38
  msgstr ""
39
 
40
- #: includes/class-demo-importer.php:278
41
- msgid "Successfully Imported"
 
 
 
 
 
42
  msgstr ""
43
 
44
- #: includes/class-demo-importer.php:323
45
- msgid "The XML file containing the dummy content is not available."
 
 
 
 
 
 
 
 
46
  msgstr ""
47
 
48
  #: includes/includes/admin/class-demo-installer-skin.php:47
@@ -67,145 +151,267 @@ msgid "Unpacking the package&#8230;"
67
  msgstr ""
68
 
69
  #: includes/includes/admin/class-demo-upgrader.php:43
70
- msgid "Installing the demo&#8230;"
71
  msgstr ""
72
 
73
  #: includes/includes/admin/class-demo-upgrader.php:44
74
- msgid "The demo contains no files."
75
  msgstr ""
76
 
77
  #: includes/includes/admin/class-demo-upgrader.php:45
78
- msgid "Demo install failed."
79
  msgstr ""
80
 
81
  #: includes/includes/admin/class-demo-upgrader.php:46
 
 
 
 
 
 
 
 
82
  msgid "Demo installed successfully."
83
  msgstr ""
84
 
85
- #: includes/includes/admin/class-demo-upgrader.php:129
86
  msgid "No valid demos were found."
87
  msgstr ""
88
 
89
- #: includes/includes/admin/views/html-admin-page-importer-previews.php:16
90
- msgid "Theme demos list"
91
  msgstr ""
92
 
93
- #: includes/includes/admin/views/html-admin-page-importer-previews.php:35
94
- #: includes/includes/admin/views/html-admin-page-importer-uploaded.php:64
95
- msgid "Live Preview"
 
 
 
96
  msgstr ""
97
 
98
- #: includes/includes/admin/views/html-admin-page-importer-uploaded.php:16
99
- msgid "Available demos list"
 
100
  msgstr ""
101
 
102
- #: includes/includes/admin/views/html-admin-page-importer-uploaded.php:35
103
- msgid "<strong>Required Plugins:</strong> %s"
 
 
 
104
  msgstr ""
105
 
106
- #: includes/includes/admin/views/html-admin-page-importer-uploaded.php:38
107
- msgid "<strong>Recommended Plugins:</strong> %s"
 
 
 
 
 
 
 
 
108
  msgstr ""
109
 
110
- #: includes/includes/admin/views/html-admin-page-importer-uploaded.php:46
111
- #. translators: %s: demo name
 
 
 
112
  msgid "<span>Imported:</span> %s"
113
  msgstr ""
114
 
115
- #: includes/includes/admin/views/html-admin-page-importer-uploaded.php:54
116
- #: includes/includes/admin/views/html-admin-page-importer-uploaded.php:57
117
- #: includes/includes/admin/views/html-admin-page-importer-uploaded.php:59
118
- #: includes/includes/admin/views/html-admin-page-importer-uploaded.php:62
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
119
  msgid "Import"
120
  msgstr ""
121
 
122
- #: includes/includes/admin/views/html-admin-page-importer-uploaded.php:57
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
123
  msgid "Required Plugin must be activated to import this demo."
124
  msgstr ""
125
 
126
- #: includes/includes/admin/views/html-admin-page-importer-uploaded.php:66
127
- msgid "Preview"
 
128
  msgstr ""
129
 
130
- #: includes/includes/admin/views/html-admin-page-importer-uploaded.php:67
131
- msgid "Please Wait&hellip;"
 
132
  msgstr ""
133
 
134
- #: includes/includes/admin/views/html-admin-page-importer-welcome.php:14
135
- msgid "Welcome to ThemeGrill Demo Importer!"
 
136
  msgstr ""
137
 
138
- #: includes/includes/admin/views/html-admin-page-importer-welcome.php:15
139
- msgid "Get Started"
 
140
  msgstr ""
141
 
142
- #: includes/includes/admin/views/html-admin-page-importer-welcome.php:19
143
- msgid ""
144
- "1. Visit <a href=\"%s\" target=\"_blank\"><strong>this page</strong></a> "
145
- "and download demo zip file."
146
  msgstr ""
147
 
148
- #: includes/includes/admin/views/html-admin-page-importer-welcome.php:20
149
- msgid "2. Click <strong>Upload Demo</strong> button on the top of this Page."
 
150
  msgstr ""
151
 
152
- #: includes/includes/admin/views/html-admin-page-importer-welcome.php:21
153
- msgid "3. Browse the demo zip file and click <strong>Install Now</strong>."
 
154
  msgstr ""
155
 
156
- #: includes/includes/admin/views/html-admin-page-importer-welcome.php:22
157
- msgid "4. Go to <strong>Available Demos</strong> tab."
 
158
  msgstr ""
159
 
160
- #: includes/includes/admin/views/html-admin-page-importer-welcome.php:23
161
- msgid "5. Click <strong>Import</strong> button and wait for few minutes. Done!"
 
162
  msgstr ""
163
 
164
- #: includes/includes/admin/views/html-admin-page-importer.php:12
165
- msgid "Welcome"
 
166
  msgstr ""
167
 
168
- #: includes/includes/admin/views/html-admin-page-importer.php:13
169
- msgid "Available Demos"
 
170
  msgstr ""
171
 
172
- #: includes/includes/admin/views/html-admin-page-importer.php:14
173
- msgid "Theme Demos"
174
  msgstr ""
175
 
176
- #: includes/includes/admin/views/html-admin-page-importer.php:22
177
- msgid "Upload Demo"
178
  msgstr ""
179
 
180
- #: includes/includes/admin/views/html-admin-page-importer.php:27
181
- msgid ""
182
- "<strong>Notice</strong> &#8211; If you want to completely remove a demo "
183
- "installation after importing it, you can use a plugin like %1$sWordPress "
184
- "Reset%2$s."
185
  msgstr ""
186
 
187
- #: includes/includes/admin/views/html-admin-page-importer.php:31
188
- msgid "The Demo Importer screen requires JavaScript."
189
  msgstr ""
190
 
191
- #: includes/includes/admin/views/html-admin-page-importer.php:34
192
  msgid ""
193
  "If you have a demo pack in a .zip format, you may install it by uploading "
194
  "it here."
195
  msgstr ""
196
 
197
- #: includes/includes/admin/views/html-admin-page-importer.php:37
198
  msgid "Demo zip file"
199
  msgstr ""
200
 
201
- #: includes/includes/admin/views/html-admin-page-importer.php:39
202
  msgid "Install Now"
203
  msgstr ""
204
 
205
- #: includes/includes/admin/views/html-admin-page-importer.php:43
206
  msgid "Filter demos list"
207
  msgstr ""
208
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
209
  #: includes/includes/class-customizer-importer.php:42
210
  msgid ""
211
  "The customizer import file is not in a correct format. Please make sure to "
@@ -246,6 +452,34 @@ msgstr ""
246
  msgid "No Title"
247
  msgstr ""
248
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
249
  #: includes/includes/importers/class-wxr-importer.php:126
250
  #: includes/includes/importers/class-wxr-importer.php:135
251
  #: includes/includes/importers/class-wxr-importer.php:186
@@ -446,23 +680,35 @@ msgstr ""
446
  msgid "This does not appear to be a WXR file, missing/invalid WXR version number"
447
  msgstr ""
448
 
449
- #: themegrill-demo-importer.php:165
450
- msgid "View Demos"
 
 
 
 
451
  msgstr ""
452
 
453
- #: themegrill-demo-importer.php:165
454
- msgid "Demos"
 
 
 
 
 
 
 
 
455
  msgstr ""
456
 
457
  #. Plugin Name of the plugin/theme
458
  msgid "ThemeGrill Demo Importer"
459
  msgstr ""
460
 
461
- #: themegrill-demo-importer.php:177
462
  msgid "This plugin requires %s by ThemeGrill to work."
463
  msgstr ""
464
 
465
- #: themegrill-demo-importer.php:177
466
  msgid "Official Theme"
467
  msgstr ""
468
 
@@ -472,14 +718,69 @@ msgstr ""
472
 
473
  #. Description of the plugin/theme
474
  msgid ""
475
- "Import your demo content, widgets and theme settings with one click for "
476
- "ThemeGrill themes"
477
- msgstr ""
478
-
479
- #. Author of the plugin/theme
480
- msgid "ThemeGrill"
481
  msgstr ""
482
 
483
  #. Author URI of the plugin/theme
484
  msgid "http://themegrill.com"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
485
  msgstr ""
2
  # This file is distributed under the GPLv3 or later.
3
  msgid ""
4
  msgstr ""
5
+ "Project-Id-Version: ThemeGrill Demo Importer 1.1.0\n"
6
  "Report-Msgid-Bugs-To: themegrill@gmail.com\n"
7
+ "POT-Creation-Date: 2016-12-30 16:49:14+00:00\n"
8
  "MIME-Version: 1.0\n"
9
  "Content-Type: text/plain; charset=utf-8\n"
10
  "Content-Transfer-Encoding: 8bit\n"
13
  "Language-Team: LANGUAGE <EMAIL@ADDRESS>\n"
14
  "X-Generator: grunt-wp-i18n 0.5.4\n"
15
 
16
+ #: includes/class-demo-importer.php:137
17
+ #: includes/includes/admin/views/html-admin-page-importer.php:14
18
+ #: includes/includes/admin/views/html-admin-page-installer.php:23
19
+ #: themegrill-demo-importer.php:171
20
  msgid "Demo Importer"
21
  msgstr ""
22
 
23
+ #: includes/class-demo-importer.php:177
24
+ msgid "Importing..."
25
+ msgstr ""
26
+
27
+ #: includes/class-demo-importer.php:179
28
+ msgid "Importing... please wait."
29
  msgstr ""
30
 
31
+ #: includes/class-demo-importer.php:180
32
+ msgid "Import completed successfully."
33
+ msgstr ""
34
+
35
+ #: includes/class-demo-importer.php:181
36
+ msgid "Import Failed!"
37
+ msgstr ""
38
+
39
+ #: includes/class-demo-importer.php:182
40
+ msgid "Import failed: %s"
41
+ msgstr ""
42
+
43
+ #: includes/class-demo-importer.php:185
44
+ #: includes/includes/admin/views/html-admin-page-importer.php:58
45
+ #: includes/includes/admin/views/html-admin-page-importer.php:110
46
+ #: includes/includes/admin/views/html-admin-page-importer.php:222
47
+ #: includes/includes/admin/views/html-admin-page-importer.php:231
48
+ #: includes/includes/admin/views/html-admin-page-installer-uploads.php:40
49
+ #: includes/includes/admin/views/html-admin-page-installer.php:124
50
+ #: includes/includes/admin/views/html-admin-page-installer.php:236
51
+ #: includes/includes/admin/views/html-admin-page-installer.php:245
52
+ msgid "Live Preview"
53
+ msgstr ""
54
+
55
+ #: includes/class-demo-importer.php:187
56
+ msgid "Imported!"
57
+ msgstr ""
58
+
59
+ #: includes/class-demo-importer.php:188
60
+ msgid "Try this solution!"
61
+ msgstr ""
62
+
63
+ #: includes/class-demo-importer.php:201
64
+ msgid ""
65
+ "Are you sure you want to delete this demo?\n"
66
+ "\n"
67
+ "Click 'Cancel' to go back, 'OK' to confirm the delete."
68
+ msgstr ""
69
+
70
+ #: includes/class-demo-importer.php:202
71
  msgid ""
72
  "Importing demo content will replicate the live demo and overwrites your "
73
  "current customizer, widgets and other settings. It might take few minutes "
74
  "to complete the demo import. Are you sure you want to import this demo?"
75
  msgstr ""
76
 
77
+ #: includes/class-demo-importer.php:207
78
+ msgid "Add New Demo"
79
+ msgstr ""
80
+
81
+ #: includes/class-demo-importer.php:208
82
+ msgid "Search Demos"
83
+ msgstr ""
84
+
85
+ #: includes/class-demo-importer.php:209
86
+ msgid "Search demos..."
87
+ msgstr ""
88
+
89
+ #: includes/class-demo-importer.php:210
90
+ msgid "Number of Demos found: %d"
91
  msgstr ""
92
 
93
  #: includes/class-demo-importer.php:211
94
+ #: includes/includes/admin/views/html-admin-page-importer.php:81
95
+ #: includes/includes/admin/views/html-admin-page-installer.php:94
96
+ msgid "No demos found. Try a different search."
97
+ msgstr ""
98
+
99
+ #. Author of the plugin/theme
100
+ msgid "ThemeGrill"
101
+ msgstr ""
102
+
103
+ #: includes/class-demo-importer.php:393
104
+ msgid "Sorry, you are not allowed to install demo on this site."
105
+ msgstr ""
106
+
107
+ #: includes/class-demo-importer.php:400
108
  msgid "Installing Demo from uploaded file: %s"
109
  msgstr ""
110
 
111
+ #: includes/class-demo-importer.php:444
112
+ #: includes/includes/functions-demo-importer.php:109
113
+ msgid "No demo specified."
114
+ msgstr ""
115
+
116
+ #: includes/class-demo-importer.php:460
117
+ msgid "Sorry, you are not allowed to import."
118
  msgstr ""
119
 
120
+ #: includes/class-demo-importer.php:525
121
+ msgid "The XML file dummy content is missing."
122
+ msgstr ""
123
+
124
+ #: includes/class-demo-importer.php:588
125
+ msgid "The DAT file customizer data is missing."
126
+ msgstr ""
127
+
128
+ #: includes/class-demo-importer.php:612
129
+ msgid "The WIE file widget content is missing."
130
  msgstr ""
131
 
132
  #: includes/includes/admin/class-demo-installer-skin.php:47
151
  msgstr ""
152
 
153
  #: includes/includes/admin/class-demo-upgrader.php:43
154
+ msgid "Removing the old version of the demo&#8230;"
155
  msgstr ""
156
 
157
  #: includes/includes/admin/class-demo-upgrader.php:44
158
+ msgid "Could not remove the old demo."
159
  msgstr ""
160
 
161
  #: includes/includes/admin/class-demo-upgrader.php:45
162
+ msgid "Installing the demo&#8230;"
163
  msgstr ""
164
 
165
  #: includes/includes/admin/class-demo-upgrader.php:46
166
+ msgid "The demo contains no files."
167
+ msgstr ""
168
+
169
+ #: includes/includes/admin/class-demo-upgrader.php:47
170
+ msgid "Demo install failed."
171
+ msgstr ""
172
+
173
+ #: includes/includes/admin/class-demo-upgrader.php:48
174
  msgid "Demo installed successfully."
175
  msgstr ""
176
 
177
+ #: includes/includes/admin/class-demo-upgrader.php:131
178
  msgid "No valid demos were found."
179
  msgstr ""
180
 
181
+ #: includes/includes/admin/views/html-admin-page-importer.php:17
182
+ msgid "New Demos"
183
  msgstr ""
184
 
185
+ #: includes/includes/admin/views/html-admin-page-importer.php:22
186
+ #: includes/includes/admin/views/html-admin-page-installer.php:30
187
+ msgid ""
188
+ "<strong>Notice</strong> &#8211; If you want to completely remove a demo "
189
+ "installation after importing it, you can use a plugin like %1$sWordPress "
190
+ "Reset%2$s."
191
  msgstr ""
192
 
193
+ #: includes/includes/admin/views/html-admin-page-importer.php:26
194
+ #: includes/includes/admin/views/html-admin-page-installer.php:34
195
+ msgid "The Demo Importer screen requires JavaScript."
196
  msgstr ""
197
 
198
+ #: includes/includes/admin/views/html-admin-page-importer.php:41
199
+ #: includes/includes/admin/views/html-admin-page-importer.php:93
200
+ #: includes/includes/admin/views/html-admin-page-installer-uploads.php:23
201
+ #: includes/includes/admin/views/html-admin-page-installer.php:107
202
+ msgid "Demo Details"
203
  msgstr ""
204
 
205
+ #: includes/includes/admin/views/html-admin-page-importer.php:44
206
+ #: includes/includes/admin/views/html-admin-page-importer.php:96
207
+ #: includes/includes/admin/views/html-admin-page-importer.php:156
208
+ #: includes/includes/admin/views/html-admin-page-installer-preview.php:29
209
+ #: includes/includes/admin/views/html-admin-page-installer-uploads.php:26
210
+ #: includes/includes/admin/views/html-admin-page-installer.php:110
211
+ #: includes/includes/admin/views/html-admin-page-installer.php:170
212
+ #: includes/includes/admin/views/html-admin-page-installer.php:273
213
+ #. translators: %s: Demo author name
214
+ msgid "By %s"
215
  msgstr ""
216
 
217
+ #: includes/includes/admin/views/html-admin-page-importer.php:50
218
+ #: includes/includes/admin/views/html-admin-page-importer.php:102
219
+ #: includes/includes/admin/views/html-admin-page-installer-uploads.php:32
220
+ #: includes/includes/admin/views/html-admin-page-installer.php:116
221
+ #. translators: %s: Demo name
222
  msgid "<span>Imported:</span> %s"
223
  msgstr ""
224
 
225
+ #: includes/includes/admin/views/html-admin-page-importer.php:62
226
+ #: includes/includes/admin/views/html-admin-page-importer.php:114
227
+ #: includes/includes/admin/views/html-admin-page-importer.php:161
228
+ #: includes/includes/admin/views/html-admin-page-installer-uploads.php:44
229
+ #: includes/includes/admin/views/html-admin-page-installer.php:128
230
+ #: includes/includes/admin/views/html-admin-page-installer.php:175
231
+ msgid "Required %s theme must be activated to import this demo."
232
+ msgstr ""
233
+
234
+ #: includes/includes/admin/views/html-admin-page-importer.php:62
235
+ #: includes/includes/admin/views/html-admin-page-importer.php:64
236
+ #: includes/includes/admin/views/html-admin-page-importer.php:71
237
+ #: includes/includes/admin/views/html-admin-page-importer.php:114
238
+ #: includes/includes/admin/views/html-admin-page-importer.php:116
239
+ #: includes/includes/admin/views/html-admin-page-importer.php:123
240
+ #: includes/includes/admin/views/html-admin-page-importer.php:233
241
+ #: includes/includes/admin/views/html-admin-page-installer-uploads.php:44
242
+ #: includes/includes/admin/views/html-admin-page-installer-uploads.php:46
243
+ #: includes/includes/admin/views/html-admin-page-installer-uploads.php:53
244
+ #: includes/includes/admin/views/html-admin-page-installer.php:128
245
+ #: includes/includes/admin/views/html-admin-page-installer.php:130
246
+ #: includes/includes/admin/views/html-admin-page-installer.php:137
247
+ #: includes/includes/admin/views/html-admin-page-installer.php:247
248
  msgid "Import"
249
  msgstr ""
250
 
251
+ #: includes/includes/admin/views/html-admin-page-importer.php:73
252
+ #: includes/includes/admin/views/html-admin-page-importer.php:125
253
+ #: includes/includes/admin/views/html-admin-page-importer.php:236
254
+ #: includes/includes/admin/views/html-admin-page-installer-preview.php:41
255
+ #: includes/includes/admin/views/html-admin-page-installer-uploads.php:55
256
+ #: includes/includes/admin/views/html-admin-page-installer.php:139
257
+ #: includes/includes/admin/views/html-admin-page-installer.php:250
258
+ #: includes/includes/admin/views/html-admin-page-installer.php:285
259
+ msgid "Preview"
260
+ msgstr ""
261
+
262
+ #: includes/includes/admin/views/html-admin-page-importer.php:138
263
+ #: includes/includes/admin/views/html-admin-page-installer.php:152
264
+ msgid "Show previous demo"
265
+ msgstr ""
266
+
267
+ #: includes/includes/admin/views/html-admin-page-importer.php:139
268
+ #: includes/includes/admin/views/html-admin-page-installer.php:153
269
+ msgid "Show next demo"
270
+ msgstr ""
271
+
272
+ #: includes/includes/admin/views/html-admin-page-importer.php:140
273
+ #: includes/includes/admin/views/html-admin-page-installer.php:154
274
+ msgid "Close details dialog"
275
+ msgstr ""
276
+
277
+ #: includes/includes/admin/views/html-admin-page-importer.php:153
278
+ #: includes/includes/admin/views/html-admin-page-installer.php:167
279
+ msgid "Imported Demo"
280
+ msgstr ""
281
+
282
+ #: includes/includes/admin/views/html-admin-page-importer.php:155
283
+ #: includes/includes/admin/views/html-admin-page-installer.php:169
284
+ msgid "Version: %s"
285
+ msgstr ""
286
+
287
+ #: includes/includes/admin/views/html-admin-page-importer.php:163
288
+ #: includes/includes/admin/views/html-admin-page-installer.php:177
289
  msgid "Required Plugin must be activated to import this demo."
290
  msgstr ""
291
 
292
+ #: includes/includes/admin/views/html-admin-page-importer.php:169
293
+ #: includes/includes/admin/views/html-admin-page-installer.php:183
294
+ msgid "Plugins Information"
295
  msgstr ""
296
 
297
+ #: includes/includes/admin/views/html-admin-page-importer.php:174
298
+ #: includes/includes/admin/views/html-admin-page-installer.php:188
299
+ msgid "Plugin Name"
300
  msgstr ""
301
 
302
+ #: includes/includes/admin/views/html-admin-page-importer.php:175
303
+ #: includes/includes/admin/views/html-admin-page-installer.php:189
304
+ msgid "Type"
305
  msgstr ""
306
 
307
+ #: includes/includes/admin/views/html-admin-page-importer.php:176
308
+ #: includes/includes/admin/views/html-admin-page-installer.php:190
309
+ msgid "Status"
310
  msgstr ""
311
 
312
+ #: includes/includes/admin/views/html-admin-page-importer.php:192
313
+ #: includes/includes/admin/views/html-admin-page-installer.php:206
314
+ msgid "Required"
 
315
  msgstr ""
316
 
317
+ #: includes/includes/admin/views/html-admin-page-importer.php:194
318
+ #: includes/includes/admin/views/html-admin-page-installer.php:208
319
+ msgid "Recommended"
320
  msgstr ""
321
 
322
+ #: includes/includes/admin/views/html-admin-page-importer.php:208
323
+ #: includes/includes/admin/views/html-admin-page-installer.php:222
324
+ msgid "No plugins are needed to import this demo."
325
  msgstr ""
326
 
327
+ #: includes/includes/admin/views/html-admin-page-importer.php:215
328
+ #: includes/includes/admin/views/html-admin-page-installer.php:229
329
+ msgid "Tags:"
330
  msgstr ""
331
 
332
+ #: includes/includes/admin/views/html-admin-page-importer.php:240
333
+ #: includes/includes/admin/views/html-admin-page-installer.php:254
334
+ msgid "Delete"
335
  msgstr ""
336
 
337
+ #: includes/includes/admin/views/html-admin-page-installer-preview.php:25
338
+ #: includes/includes/admin/views/html-admin-page-installer.php:269
339
+ msgid "Demo Preview"
340
  msgstr ""
341
 
342
+ #: includes/includes/admin/views/html-admin-page-installer-preview.php:39
343
+ #: includes/includes/admin/views/html-admin-page-installer.php:283
344
+ msgid "Download"
345
  msgstr ""
346
 
347
+ #: includes/includes/admin/views/html-admin-page-installer.php:15
348
+ msgid "Welcome"
349
  msgstr ""
350
 
351
+ #: includes/includes/admin/views/html-admin-page-installer.php:16
352
+ msgid "Installed Demos"
353
  msgstr ""
354
 
355
+ #: includes/includes/admin/views/html-admin-page-installer.php:17
356
+ msgid "Theme Demos"
 
 
 
357
  msgstr ""
358
 
359
+ #: includes/includes/admin/views/html-admin-page-installer.php:25
360
+ msgid "Upload Demo"
361
  msgstr ""
362
 
363
+ #: includes/includes/admin/views/html-admin-page-installer.php:38
364
  msgid ""
365
  "If you have a demo pack in a .zip format, you may install it by uploading "
366
  "it here."
367
  msgstr ""
368
 
369
+ #: includes/includes/admin/views/html-admin-page-installer.php:41
370
  msgid "Demo zip file"
371
  msgstr ""
372
 
373
+ #: includes/includes/admin/views/html-admin-page-installer.php:43
374
  msgid "Install Now"
375
  msgstr ""
376
 
377
+ #: includes/includes/admin/views/html-admin-page-installer.php:47
378
  msgid "Filter demos list"
379
  msgstr ""
380
 
381
+ #: includes/includes/admin/views/html-admin-page-installer.php:71
382
+ msgid "Welcome to ThemeGrill Demo Importer!"
383
+ msgstr ""
384
+
385
+ #: includes/includes/admin/views/html-admin-page-installer.php:72
386
+ msgid "Get Started"
387
+ msgstr ""
388
+
389
+ #: includes/includes/admin/views/html-admin-page-installer.php:76
390
+ msgid ""
391
+ "1. Visit <a href=\"%s\" target=\"_blank\"><strong>this page</strong></a> "
392
+ "and download demo zip file."
393
+ msgstr ""
394
+
395
+ #: includes/includes/admin/views/html-admin-page-installer.php:77
396
+ msgid "2. Click <strong>Upload Demo</strong> button on the top of this Page."
397
+ msgstr ""
398
+
399
+ #: includes/includes/admin/views/html-admin-page-installer.php:78
400
+ msgid "3. Browse the demo zip file and click <strong>Install Now</strong>."
401
+ msgstr ""
402
+
403
+ #: includes/includes/admin/views/html-admin-page-installer.php:79
404
+ msgid "4. Go to <strong>Installed Demos</strong> tab."
405
+ msgstr ""
406
+
407
+ #: includes/includes/admin/views/html-admin-page-installer.php:80
408
+ msgid "5. Click <strong>Import</strong> button and wait for few minutes. Done!"
409
+ msgstr ""
410
+
411
+ #: includes/includes/admin/views/html-admin-page-installer.php:87
412
+ msgid "Available demos list"
413
+ msgstr ""
414
+
415
  #: includes/includes/class-customizer-importer.php:42
416
  msgid ""
417
  "The customizer import file is not in a correct format. Please make sure to "
452
  msgid "No Title"
453
  msgstr ""
454
 
455
+ #: includes/includes/functions-demo-importer.php:120
456
+ msgid "Sorry, you are not allowed to delete demo on this site."
457
+ msgstr ""
458
+
459
+ #: includes/includes/functions-demo-importer.php:133
460
+ msgid "Unable to connect to the filesystem. Please confirm your credentials."
461
+ msgstr ""
462
+
463
+ #: includes/includes/functions-demo-importer.php:149
464
+ msgid "Demo could not be deleted."
465
+ msgstr ""
466
+
467
+ #: includes/includes/functions-demo-importer.php:211
468
+ msgid "Could not access filesystem."
469
+ msgstr ""
470
+
471
+ #: includes/includes/functions-demo-importer.php:215
472
+ msgid "Filesystem error."
473
+ msgstr ""
474
+
475
+ #: includes/includes/functions-demo-importer.php:221
476
+ msgid "Unable to locate ThemeGrill demo pack directory."
477
+ msgstr ""
478
+
479
+ #: includes/includes/functions-demo-importer.php:229
480
+ msgid "Could not fully remove the demo %s."
481
+ msgstr ""
482
+
483
  #: includes/includes/importers/class-wxr-importer.php:126
484
  #: includes/includes/importers/class-wxr-importer.php:135
485
  #: includes/includes/importers/class-wxr-importer.php:186
680
  msgid "This does not appear to be a WXR file, missing/invalid WXR version number"
681
  msgstr ""
682
 
683
+ #: themegrill-demo-importer.php:171
684
+ msgid "View Demo Importer"
685
+ msgstr ""
686
+
687
+ #: themegrill-demo-importer.php:186
688
+ msgid "View Demo Importer Documentation"
689
  msgstr ""
690
 
691
+ #: themegrill-demo-importer.php:186
692
+ msgid "Docs"
693
+ msgstr ""
694
+
695
+ #: themegrill-demo-importer.php:187
696
+ msgid "Visit Free Customer Support Forum"
697
+ msgstr ""
698
+
699
+ #: themegrill-demo-importer.php:187
700
+ msgid "Free Support"
701
  msgstr ""
702
 
703
  #. Plugin Name of the plugin/theme
704
  msgid "ThemeGrill Demo Importer"
705
  msgstr ""
706
 
707
+ #: themegrill-demo-importer.php:202
708
  msgid "This plugin requires %s by ThemeGrill to work."
709
  msgstr ""
710
 
711
+ #: themegrill-demo-importer.php:202
712
  msgid "Official Theme"
713
  msgstr ""
714
 
718
 
719
  #. Description of the plugin/theme
720
  msgid ""
721
+ "Description: Import your demo content, widgets and theme settings with one "
722
+ "click for ThemeGrill official themes."
 
 
 
 
723
  msgstr ""
724
 
725
  #. Author URI of the plugin/theme
726
  msgid "http://themegrill.com"
727
+ msgstr ""
728
+
729
+ #: includes/class-demo-importer.php:153
730
+ msgctxt "Admin menu name"
731
+ msgid "Demo Importer"
732
+ msgstr ""
733
+
734
+ #: includes/class-demo-importer.php:178
735
+ msgctxt "demo"
736
+ msgid "Importing %s..."
737
+ msgstr ""
738
+
739
+ #: includes/class-demo-importer.php:183
740
+ msgctxt "demo"
741
+ msgid "%s imported!"
742
+ msgstr ""
743
+
744
+ #: includes/class-demo-importer.php:184
745
+ msgctxt "demo"
746
+ msgid "%s import failed"
747
+ msgstr ""
748
+
749
+ #: includes/class-demo-importer.php:186
750
+ msgctxt "demo"
751
+ msgid "Live Preview %s"
752
+ msgstr ""
753
+
754
+ #: includes/includes/admin/views/html-admin-page-importer.php:69
755
+ #: includes/includes/admin/views/html-admin-page-importer.php:121
756
+ #: includes/includes/admin/views/html-admin-page-importer.php:227
757
+ #: includes/includes/admin/views/html-admin-page-installer-uploads.php:51
758
+ #: includes/includes/admin/views/html-admin-page-installer.php:135
759
+ #: includes/includes/admin/views/html-admin-page-installer.php:241
760
+ #. translators: %s: Demo name
761
+ msgctxt "demo"
762
+ msgid "Import %s"
763
+ msgstr ""
764
+
765
+ #: includes/includes/admin/views/html-admin-page-importer.php:130
766
+ #: includes/includes/admin/views/html-admin-page-installer.php:144
767
+ msgctxt "demo"
768
+ msgid "Imported"
769
+ msgstr ""
770
+
771
+ #: includes/includes/admin/views/html-admin-page-installer-preview.php:37
772
+ #: includes/includes/admin/views/html-admin-page-installer.php:281
773
+ #. translators: %s: Demo name
774
+ msgctxt "demo"
775
+ msgid "Download %s"
776
+ msgstr ""
777
+
778
+ #: includes/includes/admin/views/html-admin-page-installer.php:289
779
+ msgctxt "demo"
780
+ msgid "Installed"
781
+ msgstr ""
782
+
783
+ #: includes/includes/admin/views/html-admin-page-installer-preview.php:45
784
+ msgctxt "theme"
785
+ msgid "Installed"
786
  msgstr ""
phpcs.ruleset.xml ADDED
@@ -0,0 +1,194 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <ruleset name="WordPress Coding Standards">
3
+ <!-- See https://github.com/squizlabs/PHP_CodeSniffer/wiki/Annotated-ruleset.xml -->
4
+ <!-- See https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards/blob/develop/WordPress-Core/ruleset.xml -->
5
+
6
+ <!-- Set a description for this ruleset. -->
7
+ <description>A custom set of code standard rules to check for WordPress themes and plugins.</description>
8
+
9
+ <!-- Include the WordPress ruleset, with exclusions. -->
10
+ <rule ref="WordPress">
11
+ <exclude name="Generic.CodeAnalysis.EmptyStatement.DetectedCATCH" />
12
+ <exclude name="Generic.CodeAnalysis.EmptyStatement.DetectedIF" />
13
+ <exclude name="Generic.CodeAnalysis.EmptyStatement.DetectedELSE" />
14
+ <exclude name="Generic.CodeAnalysis.ForLoopWithTestFunctionalCall.NotAllowed" />
15
+ <exclude name="Generic.Commenting.DocComment.LongNotCapital" />
16
+ <exclude name="Generic.Commenting.DocComment.MissingShort" />
17
+ <exclude name="Generic.Commenting.DocComment.ShortNotCapital" />
18
+ <exclude name="Generic.Commenting.DocComment.SpacingAfter" />
19
+ <exclude name="Generic.Commenting.DocComment.SpacingBeforeTags" />
20
+ <exclude name="Generic.ControlStructures.InlineControlStructure.NotAllowed" />
21
+ <!-- <exclude name="Generic.Files.EndFileNewline.NotFound" /> -->
22
+ <exclude name="Generic.Files.LineEndings.InvalidEOLChar" />
23
+ <exclude name="Generic.Files.LowercasedFilename.NotFound" />
24
+ <!-- <exclude name="Generic.Formatting.DisallowMultipleStatements.SameLine" /> -->
25
+ <!-- <exclude name="Generic.Formatting.SpaceAfterCast.NoSpace" /> -->
26
+ <exclude name="Generic.Functions.OpeningFunctionBraceKernighanRitchie.BraceOnNewLine" />
27
+ <exclude name="Generic.Functions.OpeningFunctionBraceKernighanRitchie.ContentAfterBrace" />
28
+ <exclude name="Generic.Functions.OpeningFunctionBraceKernighanRitchie.SpaceBeforeBrace" />
29
+ <exclude name="Generic.PHP.DeprecatedFunctions.Deprecated" />
30
+ <exclude name="Generic.PHP.ForbiddenFunctions.FoundWithAlternative" />
31
+ <exclude name="Generic.PHP.LowerCaseKeyword.Found" />
32
+ <exclude name="Generic.PHP.NoSilencedErrors.Discouraged" />
33
+ <exclude name="Generic.Strings.UnnecessaryStringConcat.Found" />
34
+ <exclude name="Generic.WhiteSpace.DisallowSpaceIndent.SpacesUsed" />
35
+ <exclude name="Generic.WhiteSpace.ScopeIndent.Incorrect" />
36
+ <exclude name="Generic.WhiteSpace.ScopeIndent.IncorrectExact" />
37
+ <exclude name="PEAR.Functions.FunctionCallSignature.Indent" />
38
+ <!-- <exclude name="PEAR.Functions.FunctionCallSignature.SpaceAfterCloseBracket" /> -->
39
+ <!-- <exclude name="PEAR.Functions.FunctionCallSignature.SpaceAfterOpenBracket" /> -->
40
+ <!-- <exclude name="PEAR.Functions.FunctionCallSignature.SpaceBeforeCloseBracket" /> -->
41
+ <!-- <exclude name="PEAR.Functions.FunctionCallSignature.SpaceBeforeOpenBracket" /> -->
42
+ <!-- <exclude name="Squiz.Commenting.BlockComment.NoEmptyLineBefore" /> -->
43
+ <!-- <exclude name="Squiz.Commenting.BlockComment.NoNewLine" /> -->
44
+ <exclude name="Squiz.Commenting.BlockComment.WrongEnd" />
45
+ <exclude name="Squiz.Commenting.ClassComment.SpacingAfter" />
46
+ <exclude name="Squiz.Commenting.ClassComment.Missing" />
47
+ <exclude name="Squiz.Commenting.ClosingDeclarationComment.Abstract" />
48
+ <!-- <exclude name="Squiz.Commenting.DocCommentAlignment.SpaceBeforeStar" /> -->
49
+ <exclude name="Squiz.Commenting.EmptyCatchComment.Missing" />
50
+ <exclude name="Squiz.Commenting.FileComment.Missing" />
51
+ <exclude name="Squiz.Commenting.FileComment.MissingPackageTag" />
52
+ <exclude name="Squiz.Commenting.FileComment.SpacingAfterComment" />
53
+ <exclude name="Squiz.Commenting.FileComment.SpacingAfterOpen" />
54
+ <exclude name="Squiz.Commenting.FileComment.WrongStyle" />
55
+ <exclude name="Squiz.Commenting.FunctionComment.EmptyThrows" />
56
+ <exclude name="Squiz.Commenting.FunctionComment.ExtraParamComment" />
57
+ <exclude name="Squiz.Commenting.FunctionComment.InvalidNoReturn" />
58
+ <exclude name="Squiz.Commenting.FunctionComment.InvalidReturnVoid" />
59
+ <exclude name="Squiz.Commenting.FunctionComment.Missing" />
60
+ <exclude name="Squiz.Commenting.FunctionComment.MissingParamComment" />
61
+ <exclude name="Squiz.Commenting.FunctionComment.MissingParamName" />
62
+ <exclude name="Squiz.Commenting.FunctionComment.MissingParamTag" />
63
+ <exclude name="Squiz.Commenting.FunctionComment.ParamCommentFullStop" />
64
+ <exclude name="Squiz.Commenting.FunctionComment.ParamNameNoCaseMatch" />
65
+ <exclude name="Squiz.Commenting.FunctionComment.ParamNameNoMatch" />
66
+ <exclude name="Squiz.Commenting.FunctionComment.ScalarTypeHintMissing" />
67
+ <!-- <exclude name="Squiz.Commenting.FunctionComment.SpacingAfter" /> -->
68
+ <exclude name="Squiz.Commenting.FunctionComment.SpacingAfterParamType" />
69
+ <exclude name="Squiz.Commenting.FunctionComment.ThrowsNoFullStop" />
70
+ <exclude name="Squiz.Commenting.FunctionComment.ThrowsNotCapital" />
71
+ <exclude name="Squiz.Commenting.FunctionCommentThrowTag.Missing" />
72
+ <exclude name="Squiz.Commenting.FunctionCommentThrowTag.WrongNumber" />
73
+ <exclude name="Squiz.Commenting.FunctionComment.WrongStyle" />
74
+ <exclude name="Squiz.Commenting.InlineComment.Empty" />
75
+ <exclude name="Squiz.Commenting.InlineComment.InvalidEndChar" />
76
+ <!-- <exclude name="Squiz.Commenting.InlineComment.NoSpaceBefore" /> -->
77
+ <exclude name="Squiz.Commenting.InlineComment.NotCapital" />
78
+ <!-- <exclude name="Squiz.Commenting.InlineComment.SpacingAfter" /> -->
79
+ <!-- <exclude name="Squiz.Commenting.InlineComment.SpacingBefore" /> -->
80
+ <exclude name="Squiz.Commenting.InlineComment.WrongStyle" />
81
+ <exclude name="Squiz.Commenting.VariableComment.Missing" />
82
+ <exclude name="Squiz.Commenting.VariableComment.MissingVar" />
83
+ <exclude name="Squiz.Commenting.VariableComment.WrongStyle" />
84
+ <!-- <exclude name="Squiz.ControlStructures.ControlSignature.SpaceAfterCloseBrace" /> -->
85
+ <!-- <exclude name="Squiz.ControlStructures.ControlSignature.SpaceAfterCloseParenthesis" /> -->
86
+ <exclude name="Squiz.ControlStructures.ControlSignature.SpaceAfterKeyword" />
87
+ <exclude name="Squiz.Functions.FunctionDeclarationArgumentSpacing.SpaceAfterDefault" />
88
+ <exclude name="Squiz.Functions.FunctionDeclarationArgumentSpacing.SpacingAfterOpen" />
89
+ <exclude name="Squiz.Functions.FunctionDeclarationArgumentSpacing.SpacingAfterOpenHint" />
90
+ <exclude name="Squiz.Functions.FunctionDeclarationArgumentSpacing.SpaceBeforeEquals" />
91
+ <exclude name="Squiz.Functions.FunctionDeclarationArgumentSpacing.SpacingBeforeClose" />
92
+ <exclude name="Squiz.PHP.CommentedOutCode.Found" />
93
+ <exclude name="Squiz.Strings.DoubleQuoteUsage.NotRequired" />
94
+ <!-- <exclude name="Squiz.WhiteSpace.SuperfluousWhitespace.EmptyLines" /> -->
95
+ <!-- <exclude name="Squiz.WhiteSpace.SuperfluousWhitespace.EndLine" /> -->
96
+ <!-- <exclude name="WordPress.Arrays.ArrayDeclaration.CloseBraceNewLine" /> -->
97
+ <!-- <exclude name="WordPress.Arrays.ArrayDeclaration.FirstIndexNoNewline" /> -->
98
+ <!-- <exclude name="WordPress.Arrays.ArrayDeclaration.FirstValueNoNewline" /> -->
99
+ <!-- <exclude name="WordPress.Arrays.ArrayDeclaration.IndexNoNewline" /> -->
100
+ <!-- <exclude name="WordPress.Arrays.ArrayDeclaration.NoComma" /> -->
101
+ <!-- <exclude name="WordPress.Arrays.ArrayDeclaration.NoCommaAfterLast" /> -->
102
+ <!-- <exclude name="WordPress.Arrays.ArrayDeclaration.NoSpaceAfterComma" /> -->
103
+ <!-- <exclude name="WordPress.Arrays.ArrayDeclaration.NoSpaceAfterDoubleArrow" /> -->
104
+ <!-- <exclude name="WordPress.Arrays.ArrayDeclaration.NoSpaceAfterOpenParenthesis" /> -->
105
+ <!-- <exclude name="WordPress.Arrays.ArrayDeclaration.NoSpaceBeforeDoubleArrow" /> -->
106
+ <!-- <exclude name="WordPress.Arrays.ArrayDeclaration.SpaceAfterArrayOpener" /> -->
107
+ <!-- <exclude name="WordPress.Arrays.ArrayDeclaration.SpaceAfterDoubleArrow" /> -->
108
+ <!-- <exclude name="WordPress.Arrays.ArrayDeclaration.SpaceAfterKeyword" /> -->
109
+ <!-- <exclude name="WordPress.Arrays.ArrayDeclaration.SpaceBeforeComma" /> -->
110
+ <!-- <exclude name="WordPress.Arrays.ArrayDeclaration.SpaceInEmptyArray" /> -->
111
+ <!-- <exclude name="WordPress.Arrays.ArrayDeclaration.ValueNoNewline" /> -->
112
+ <!-- <exclude name="WordPress.Arrays.ArrayKeySpacingRestrictions.NoSpacesAroundArrayKeys" /> -->
113
+ <!-- <exclude name="WordPress.Arrays.ArrayKeySpacingRestrictions.SpacesAroundArrayKeys" /> -->
114
+ <exclude name="WordPress.Classes.ClassOpeningStatement.BraceOnNewLine" />
115
+ <exclude name="WordPress.CSRF.NonceVerification.NoNonceVerification" />
116
+ <exclude name="WordPress.DB.RestrictedFunctions.mysql" />
117
+ <exclude name="WordPress.Files.FileName.UnderscoresNotAllowed" />
118
+ <exclude name="WordPress.Functions.DontExtract.extract" />
119
+ <exclude name="WordPress.NamingConventions.ValidFunctionName.FunctionNameInvalid" />
120
+ <exclude name="WordPress.NamingConventions.ValidFunctionName.MethodNameInvalid" />
121
+ <exclude name="WordPress.NamingConventions.ValidHookName.UseUnderscores" />
122
+ <exclude name="WordPress.NamingConventions.ValidVariableName.MemberNotSnakeCase" />
123
+ <exclude name="WordPress.NamingConventions.ValidVariableName.NotSnakeCase" />
124
+ <exclude name="WordPress.NamingConventions.ValidVariableName.NotSnakeCaseMemberVar" />
125
+ <exclude name="WordPress.NamingConventions.ValidVariableName.StringNotSnakeCase" />
126
+ <exclude name="WordPress.PHP.DiscouragedFunctions.Discouraged" />
127
+ <exclude name="WordPress.PHP.DiscouragedFunctions.DiscouragedWithAlternative" />
128
+ <exclude name="WordPress.PHP.StrictComparisons.LooseComparison" />
129
+ <exclude name="WordPress.PHP.StrictInArray.MissingTrueStrict" />
130
+ <!-- <exclude name="WordPress.PHP.YodaConditions.NotYoda" /> -->
131
+ <exclude name="WordPress.VIP.AdminBarRemoval.RemovalDetected" />
132
+ <exclude name="WordPress.VIP.CronInterval.ChangeDetected" />
133
+ <exclude name="WordPress.VIP.DirectDatabaseQuery.DirectQuery" />
134
+ <exclude name="WordPress.VIP.DirectDatabaseQuery.NoCaching" />
135
+ <exclude name="WordPress.VIP.DirectDatabaseQuery.SchemaChange" />
136
+ <exclude name="WordPress.VIP.FileSystemWritesDisallow.FileWriteDetected" />
137
+ <exclude name="WordPress.VIP.OrderByRand.orderby" />
138
+ <exclude name="WordPress.VIP.PostsPerPage.posts_per_page" />
139
+ <exclude name="WordPress.VIP.RestrictedFunctions.count_user_posts" />
140
+ <exclude name="WordPress.VIP.RestrictedFunctions.custom_role" />
141
+ <exclude name="WordPress.VIP.RestrictedFunctions.cookies" />
142
+ <exclude name="WordPress.VIP.RestrictedFunctions.curl" />
143
+ <exclude name="WordPress.VIP.RestrictedFunctions.error_log" />
144
+ <exclude name="WordPress.VIP.RestrictedFunctions.extract" />
145
+ <exclude name="WordPress.VIP.RestrictedFunctions.file_get_contents" />
146
+ <exclude name="WordPress.VIP.RestrictedFunctions.get_pages" />
147
+ <exclude name="WordPress.VIP.RestrictedFunctions.get_posts" />
148
+ <exclude name="WordPress.VIP.RestrictedFunctions.get_term_by" />
149
+ <exclude name="WordPress.VIP.RestrictedFunctions.get_term_link" />
150
+ <exclude name="WordPress.VIP.RestrictedFunctions.get_page_by_title" />
151
+ <exclude name="WordPress.VIP.RestrictedFunctions.parse_url" />
152
+ <exclude name="WordPress.VIP.RestrictedFunctions.prevent_path_disclosure" />
153
+ <exclude name="WordPress.VIP.RestrictedFunctions.runtime_configuration" />
154
+ <exclude name="WordPress.VIP.RestrictedFunctions.serialize" />
155
+ <exclude name="WordPress.VIP.RestrictedFunctions.urlencode" />
156
+ <exclude name="WordPress.VIP.RestrictedFunctions.url_to_postid" />
157
+ <exclude name="WordPress.VIP.RestrictedFunctions.user_meta" />
158
+ <exclude name="WordPress.VIP.RestrictedFunctions.wp_get_post_terms" />
159
+ <exclude name="WordPress.VIP.RestrictedFunctions.wp_redirect" />
160
+ <exclude name="WordPress.VIP.RestrictedFunctions.wp_remote_get" />
161
+ <exclude name="WordPress.VIP.RestrictedVariables.user_meta" />
162
+ <exclude name="WordPress.VIP.RestrictedVariables.cache_constraints" />
163
+ <exclude name="WordPress.VIP.SessionFunctionsUsage.session_write_close" />
164
+ <exclude name="WordPress.VIP.SlowDBQuery.slow_db_query" />
165
+ <exclude name="WordPress.VIP.SuperGlobalInputUsage.AccessDetected" />
166
+ <exclude name="WordPress.VIP.ValidatedSanitizedInput.InputNotSanitized" />
167
+ <exclude name="WordPress.VIP.ValidatedSanitizedInput.InputNotValidated" />
168
+ <exclude name="WordPress.VIP.ValidatedSanitizedInput.MissingUnslash" />
169
+ <exclude name="WordPress.Variables.GlobalVariables.OverrideProhibited" />
170
+ <exclude name="WordPress.WP.EnqueuedResources.NonEnqueuedScript" />
171
+ <exclude name="WordPress.WP.I18n.MissingSingularPlaceholder" />
172
+ <exclude name="WordPress.WP.I18n.MismatchedPlaceholders" />
173
+ <exclude name="WordPress.WP.I18n.NonSingularStringLiteralPlural" />
174
+ <exclude name="WordPress.WP.I18n.NonSingularStringLiteralText" />
175
+ <exclude name="WordPress.WP.EnqueuedResources.NonEnqueuedStylesheet" />
176
+ <exclude name="WordPress.WP.PreparedSQL.NotPrepared" />
177
+ <!-- <exclude name="WordPress.WhiteSpace.ControlStructureSpacing.BlankLineAfterEnd" /> -->
178
+ <!-- <exclude name="WordPress.WhiteSpace.ControlStructureSpacing.ExtraSpaceAfterCloseParenthesis" /> -->
179
+ <!-- <exclude name="WordPress.WhiteSpace.ControlStructureSpacing.NoSpaceAfterCloseParenthesis" /> -->
180
+ <!-- <exclude name="WordPress.WhiteSpace.ControlStructureSpacing.NoSpaceAfterOpenParenthesis" /> -->
181
+ <!-- <exclude name="WordPress.WhiteSpace.ControlStructureSpacing.NoSpaceAfterStructureOpen" /> -->
182
+ <!-- <exclude name="WordPress.WhiteSpace.ControlStructureSpacing.NoSpaceBetweenStructureColon" /> -->
183
+ <!-- <exclude name="WordPress.WhiteSpace.ControlStructureSpacing.NoSpaceBeforeCloseParenthesis" /> -->
184
+ <!-- <exclude name="WordPress.WhiteSpace.ControlStructureSpacing.NoSpaceBeforeOpenParenthesis" /> -->
185
+ <!-- <exclude name="WordPress.WhiteSpace.ControlStructureSpacing.OpenBraceNotSameLine" /> -->
186
+ <!-- <exclude name="WordPress.WhiteSpace.ControlStructureSpacing.SpaceBeforeFunctionOpenParenthesis" /> -->
187
+ <!-- <exclude name="WordPress.WhiteSpace.OperatorSpacing.NoSpaceAfter" /> -->
188
+ <!-- <exclude name="WordPress.WhiteSpace.OperatorSpacing.NoSpaceBefore" /> -->
189
+ <!-- <exclude name="WordPress.WhiteSpace.OperatorSpacing.SpacingAfter" /> -->
190
+ <!-- <exclude name="WordPress.WhiteSpace.OperatorSpacing.SpacingBefore" /> -->
191
+ <exclude name="WordPress.XSS.EscapeOutput.OutputNotEscaped" />
192
+ <exclude name="WordPress.XSS.EscapeOutput.UnsafePrintingFunction" />
193
+ </rule>
194
+ </ruleset>
readme.txt CHANGED
@@ -3,15 +3,14 @@ Contributors: ThemeGrill, shivapoudel
3
  Tags: themegrill, themes, demo, importer, download
4
  Requires at least: 4.0
5
  Tested up to: 4.7
6
- Stable tag: 1.0.0
7
  License: GPLv3 or later
8
  License URI: https://www.gnu.org/licenses/gpl-3.0.html
9
 
10
- Import your demo content, widgets and theme settings with one click for themegrill themes
11
-
12
  == Description ==
13
 
14
- Import your demo content, widgets and theme settings with one click for <a href="https://themegrill.com/themes/" target="_blank" rel="nofollow">ThemeGrill</a> themes
15
 
16
  Get free support at http://themegrill.com/support-forum/
17
 
@@ -40,5 +39,14 @@ Yes you can! Join in on our [GitHub repository](https://github.com/themegrill/th
40
 
41
  == Changelog ==
42
 
 
 
 
 
 
 
 
 
 
43
  = 1.0.0 =
44
  * Initial Public Release
3
  Tags: themegrill, themes, demo, importer, download
4
  Requires at least: 4.0
5
  Tested up to: 4.7
6
+ Stable tag: 1.1.0
7
  License: GPLv3 or later
8
  License URI: https://www.gnu.org/licenses/gpl-3.0.html
9
 
10
+ Import your demo content, widgets and theme settings with one click for ThemeGrill official themes.
 
11
  == Description ==
12
 
13
+ Import your demo content, widgets and theme settings with one click for <a href="https://themegrill.com/themes/" target="_blank" rel="nofollow">ThemeGrill</a> official themes.
14
 
15
  Get free support at http://themegrill.com/support-forum/
16
 
39
 
40
  == Changelog ==
41
 
42
+ = 1.1.0 =
43
+ * Feature - Backbone views interface for demos and previews
44
+ * Feature - Added download button for the preview not installed
45
+ * Feature - Robust quick search view to change in demo interface
46
+ * Feature - Detailed information in popup to showcase plugins, events, etc
47
+ * Refactor - Replace old way to import demo with new `wp.updates` methods
48
+ * Fix - Menu classes to hide admin menu if no JS using css class `hide-if-no-js`
49
+ * Fix - Remove the old demo pack if found and to update the new demo packs
50
+
51
  = 1.0.0 =
52
  * Initial Public Release
themegrill-demo-importer.php CHANGED
@@ -2,8 +2,8 @@
2
  /**
3
  * Plugin Name: ThemeGrill Demo Importer
4
  * Plugin URI: http://themegrill.com/demo-importer/
5
- * Description: Import your demo content, widgets and theme settings with one click for ThemeGrill themes
6
- * Version: 1.0.0
7
  * Author: ThemeGrill
8
  * Author URI: http://themegrill.com
9
  * License: GPLv3 or later
@@ -26,7 +26,7 @@ final class ThemeGrill_Demo_Importer {
26
  * Plugin version.
27
  * @var string
28
  */
29
- const VERSION = '1.0.0';
30
 
31
  /**
32
  * Instance of this class.
@@ -49,6 +49,7 @@ final class ThemeGrill_Demo_Importer {
49
  // Hooks.
50
  add_filter( 'themegrill_demo_importer_assets_path', array( $this, 'plugin_assets_path' ) );
51
  add_filter( 'plugin_action_links_' . plugin_basename( __FILE__ ), array( $this, 'plugin_action_links' ) );
 
52
  } else {
53
  add_action( 'admin_notices', array( $this, 'theme_support_missing_notice' ) );
54
  }
@@ -124,6 +125,7 @@ final class ThemeGrill_Demo_Importer {
124
  */
125
  private function includes() {
126
  include_once( dirname( __FILE__ ) . '/includes/class-demo-importer.php' );
 
127
  }
128
 
129
  /**
@@ -166,12 +168,31 @@ final class ThemeGrill_Demo_Importer {
166
  */
167
  public function plugin_action_links( $actions ) {
168
  $new_actions = array(
169
- 'previews' => '<a href="' . admin_url( 'themes.php?page=demo-importer&tab=previews' ) . '" aria-label="' . esc_attr( __( 'View Demos', 'themegrill-demo-importer' ) ) . '">' . __( 'Demos', 'themegrill-demo-importer' ) . '</a>',
170
  );
171
 
172
  return array_merge( $new_actions, $actions );
173
  }
174
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
175
  /**
176
  * Theme support fallback notice.
177
  * @return string
2
  /**
3
  * Plugin Name: ThemeGrill Demo Importer
4
  * Plugin URI: http://themegrill.com/demo-importer/
5
+ * Description: Description: Import your demo content, widgets and theme settings with one click for ThemeGrill official themes.
6
+ * Version: 1.1.0
7
  * Author: ThemeGrill
8
  * Author URI: http://themegrill.com
9
  * License: GPLv3 or later
26
  * Plugin version.
27
  * @var string
28
  */
29
+ const VERSION = '1.1.0';
30
 
31
  /**
32
  * Instance of this class.
49
  // Hooks.
50
  add_filter( 'themegrill_demo_importer_assets_path', array( $this, 'plugin_assets_path' ) );
51
  add_filter( 'plugin_action_links_' . plugin_basename( __FILE__ ), array( $this, 'plugin_action_links' ) );
52
+ add_filter( 'plugin_row_meta', array( $this, 'plugin_row_meta' ), 10, 2 );
53
  } else {
54
  add_action( 'admin_notices', array( $this, 'theme_support_missing_notice' ) );
55
  }
125
  */
126
  private function includes() {
127
  include_once( dirname( __FILE__ ) . '/includes/class-demo-importer.php' );
128
+ include_once( dirname( __FILE__ ) . '/includes/functions-demo-update.php' );
129
  }
130
 
131
  /**
168
  */
169
  public function plugin_action_links( $actions ) {
170
  $new_actions = array(
171
+ 'importer' => '<a href="' . admin_url( 'themes.php?page=demo-importer' ) . '" aria-label="' . esc_attr( __( 'View Demo Importer', 'themegrill-demo-importer' ) ) . '">' . __( 'Demo Importer', 'themegrill-demo-importer' ) . '</a>',
172
  );
173
 
174
  return array_merge( $new_actions, $actions );
175
  }
176
 
177
+ /**
178
+ * Display row meta in the Plugins list table.
179
+ * @param array $plugin_meta
180
+ * @param string $plugin_file
181
+ * @return array
182
+ */
183
+ public function plugin_row_meta( $plugin_meta, $plugin_file ) {
184
+ if ( plugin_basename( __FILE__ ) == $plugin_file ) {
185
+ $new_plugin_meta = array(
186
+ 'docs' => '<a href="' . esc_url( apply_filters( 'themegrill_demo_importer_docs_url', 'http://themegrill.com/docs/themegrill-demo-importer/' ) ) . '" title="' . esc_attr( __( 'View Demo Importer Documentation', 'themegrill-demo-importer' ) ) . '">' . __( 'Docs', 'themegrill-demo-importer' ) . '</a>',
187
+ 'support' => '<a href="' . esc_url( apply_filters( 'themegrill_demo_importer_support_url', 'http://themegrill.com/support-forum/' ) ) . '" title="' . esc_attr( __( 'Visit Free Customer Support Forum', 'themegrill-demo-importer' ) ) . '">' . __( 'Free Support', 'themegrill-demo-importer' ) . '</a>',
188
+ );
189
+
190
+ return array_merge( $plugin_meta, $new_plugin_meta );
191
+ }
192
+
193
+ return (array) $plugin_meta;
194
+ }
195
+
196
  /**
197
  * Theme support fallback notice.
198
  * @return string