vinsol_spree_themes 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (83) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +36 -0
  3. data/.ruby-version +1 -0
  4. data/Appraisals +16 -0
  5. data/Gemfile +9 -0
  6. data/Gemfile.lock +386 -0
  7. data/LICENSE +26 -0
  8. data/README.md +250 -0
  9. data/Rakefile +21 -0
  10. data/app/assets/javascripts/spree/backend/codemirror/codemirror.js +9351 -0
  11. data/app/assets/javascripts/spree/backend/codemirror/css-hint.js +60 -0
  12. data/app/assets/javascripts/spree/backend/codemirror/fullscreen.js +41 -0
  13. data/app/assets/javascripts/spree/backend/codemirror/html-hint.js +348 -0
  14. data/app/assets/javascripts/spree/backend/codemirror/javascript-hint.js +155 -0
  15. data/app/assets/javascripts/spree/backend/codemirror/javascript.js +813 -0
  16. data/app/assets/javascripts/spree/backend/codemirror/markdown.js +796 -0
  17. data/app/assets/javascripts/spree/backend/codemirror/ruby.js +295 -0
  18. data/app/assets/javascripts/spree/backend/codemirror/show-hint.js +438 -0
  19. data/app/assets/javascripts/spree/backend/editor.js +11 -0
  20. data/app/assets/javascripts/spree/backend/jquery.treemenu.js +87 -0
  21. data/app/assets/javascripts/spree/backend/main.js +26 -0
  22. data/app/assets/javascripts/spree/backend/spree_themes.js +2 -0
  23. data/app/assets/javascripts/spree/backend/template.js +51 -0
  24. data/app/assets/javascripts/spree/backend/theme.js +17 -0
  25. data/app/assets/javascripts/spree/frontend/spree_themes.js +2 -0
  26. data/app/assets/stylesheets/spree/backend/codemirror/codemirror.css +340 -0
  27. data/app/assets/stylesheets/spree/backend/codemirror/fullscreen.css +6 -0
  28. data/app/assets/stylesheets/spree/backend/codemirror/show-hint.css +36 -0
  29. data/app/assets/stylesheets/spree/backend/editor.css +7 -0
  30. data/app/assets/stylesheets/spree/backend/jquery.treemenu.css +8 -0
  31. data/app/assets/stylesheets/spree/backend/spree_themes.css +7 -0
  32. data/app/assets/stylesheets/spree/backend/style.css +239 -0
  33. data/app/assets/stylesheets/spree/backend/template_editor.css +39 -0
  34. data/app/assets/stylesheets/spree/frontend/spree_themes.css +6 -0
  35. data/app/assets/stylesheets/spree/frontend/theme_preview.css +9 -0
  36. data/app/controllers/spree/admin/themes_controller.rb +80 -0
  37. data/app/controllers/spree/admin/themes_preview_controller.rb +30 -0
  38. data/app/controllers/spree/admin/themes_templates_controller.rb +60 -0
  39. data/app/controllers/spree/fragment_cache_controller.rb +13 -0
  40. data/app/controllers/spree/store_controller_decorator.rb +37 -0
  41. data/app/helpers/spree/base_helper_decorator.rb +45 -0
  42. data/app/models/spree/theme.rb +153 -0
  43. data/app/models/spree/themes_template.rb +67 -0
  44. data/app/models/spree/themes_template/cache_resolver.rb +37 -0
  45. data/app/overrides/spree/add_preview_bar_to_store.html.rb +6 -0
  46. data/app/overrides/spree/add_theme_meta_details_to_store.html.rb +6 -0
  47. data/app/overrides/spree/admin/add_themes_tab.html.rb +6 -0
  48. data/app/services/assets_precompiler_service.rb +86 -0
  49. data/app/services/file_generator_service.rb +29 -0
  50. data/app/services/template_generator_service.rb +101 -0
  51. data/app/services/zip_file_builder.rb +87 -0
  52. data/app/services/zip_file_extractor.rb +52 -0
  53. data/app/views/spree/admin/shared/_theme_menu_button.html.erb +5 -0
  54. data/app/views/spree/admin/themes/_themes.html.erb +44 -0
  55. data/app/views/spree/admin/themes/_upload.html.erb +17 -0
  56. data/app/views/spree/admin/themes/index.html.erb +50 -0
  57. data/app/views/spree/admin/themes_templates/_editor.html.erb +29 -0
  58. data/app/views/spree/admin/themes_templates/_template.html.erb +12 -0
  59. data/app/views/spree/admin/themes_templates/edit.html.erb +13 -0
  60. data/app/views/spree/admin/themes_templates/edit.js.erb +1 -0
  61. data/app/views/spree/admin/themes_templates/index.html.erb +27 -0
  62. data/app/views/spree/admin/themes_templates/new.html.erb +56 -0
  63. data/app/views/spree/shared/_preview_bar.html.erb +7 -0
  64. data/app/views/spree/shared/_theme_metadata.html.erb +9 -0
  65. data/bin/rails +7 -0
  66. data/config/initializers/assets.rb +24 -0
  67. data/config/initializers/sprockets.rb +85 -0
  68. data/config/locales/en.yml +52 -0
  69. data/config/routes.rb +22 -0
  70. data/db/migrate/20170628072452_vinsol_spree_themes_create_themes_and_themes_templates_table.rb +24 -0
  71. data/gemfiles/spree_3_1.gemfile +8 -0
  72. data/gemfiles/spree_3_2.gemfile +9 -0
  73. data/gemfiles/spree_master.gemfile +9 -0
  74. data/lib/generators/themes/default.zip +0 -0
  75. data/lib/generators/vinsol_spree_themes/install/install_generator.rb +50 -0
  76. data/lib/tasks/sync_templates.rake +47 -0
  77. data/lib/vinsol_spree_themes.rb +3 -0
  78. data/lib/vinsol_spree_themes/engine.rb +22 -0
  79. data/lib/vinsol_spree_themes/factories.rb +6 -0
  80. data/lib/vinsol_spree_themes/version.rb +18 -0
  81. data/spec/spec_helper.rb +93 -0
  82. data/vinsol_spree_themes.gemspec +43 -0
  83. metadata +374 -0
@@ -0,0 +1,6 @@
1
+ Deface::Override.new(
2
+ virtual_path: 'spree/layouts/spree_application',
3
+ name: 'add_preview_bar_to_store',
4
+ insert_before: '[data-hook="body"]',
5
+ partial: 'spree/shared/preview_bar'
6
+ )
@@ -0,0 +1,6 @@
1
+ Deface::Override.new(
2
+ virtual_path: 'spree/layouts/spree_application',
3
+ name: 'add_theme_meta_details_to_store',
4
+ insert_bottom: '[data-hook="inside_head"]',
5
+ partial: 'spree/shared/theme_metadata'
6
+ )
@@ -0,0 +1,6 @@
1
+ Deface::Override.new(
2
+ virtual_path: 'spree/admin/shared/_main_menu',
3
+ name: 'add_themes_tab',
4
+ insert_before: 'div.spree-version',
5
+ partial: 'spree/admin/shared/theme_menu_button'
6
+ )
@@ -0,0 +1,86 @@
1
+ class AssetsPrecompilerService
2
+
3
+ attr_reader :theme, :env, :manifest
4
+
5
+ PUBLIC_PRECOMPILED_ASSET_PATH = File.join('public', 'assets', 'vinsol_spree_theme')
6
+ PUBLIC_PRECOMPILED_ASSET_PATH_FOR_PREVIEW = File.join('public', 'assets', 'preview_vinsol_spree_theme')
7
+ THEME_PATH = File.join('public', 'vinsol_spree_themes')
8
+ CURRENT_THEME_PATH = File.join(THEME_PATH, 'current')
9
+
10
+ def initialize(theme)
11
+ @theme = theme
12
+ end
13
+
14
+ def minify(options= {})
15
+ options.merge!({ precompile: true }) unless options.key?(:precompile)
16
+ build_environment
17
+ build_manifest
18
+ options[:precompile] ? assets_precompile : manifest
19
+ end
20
+
21
+ def copy_assets
22
+ source_path = File.join(CURRENT_THEME_PATH, 'precompiled_assets', '.')
23
+
24
+ FileUtils.rm_r(PUBLIC_PRECOMPILED_ASSET_PATH) if File.exists?(PUBLIC_PRECOMPILED_ASSET_PATH)
25
+ FileUtils.mkdir_p(PUBLIC_PRECOMPILED_ASSET_PATH)
26
+ FileUtils.cp_r(source_path, PUBLIC_PRECOMPILED_ASSET_PATH)
27
+ end
28
+
29
+ def copy_preview_assets
30
+ source_path = File.join(theme_path, 'precompiled_assets', '.')
31
+
32
+ FileUtils.rm_r(PUBLIC_PRECOMPILED_ASSET_PATH_FOR_PREVIEW) if File.exists?(PUBLIC_PRECOMPILED_ASSET_PATH_FOR_PREVIEW)
33
+ FileUtils.mkdir_p(PUBLIC_PRECOMPILED_ASSET_PATH_FOR_PREVIEW)
34
+ FileUtils.cp_r(source_path, PUBLIC_PRECOMPILED_ASSET_PATH_FOR_PREVIEW)
35
+ end
36
+
37
+ private
38
+
39
+ def build_environment
40
+ @env ||= Sprockets::Environment.new()
41
+ prepend_stylesheet_path
42
+ prepend_javascript_path
43
+ prepend_images_path
44
+ prepend_fonts_path
45
+ set_compressors
46
+ end
47
+
48
+ def build_manifest
49
+ @manifest ||= Sprockets::Manifest.new(env, File.join(theme_path, 'precompiled_assets'))
50
+ end
51
+
52
+ def prepend_stylesheet_path
53
+ env.prepend_path(File.join(source_asset_path, 'stylesheets'))
54
+ end
55
+
56
+ def prepend_javascript_path
57
+ env.prepend_path(File.join(source_asset_path, 'javascripts'))
58
+ end
59
+
60
+ def prepend_images_path
61
+ env.prepend_path(File.join(source_asset_path, 'images'))
62
+ end
63
+
64
+ def prepend_fonts_path
65
+ env.prepend_path(File.join(source_asset_path, 'fonts'))
66
+ end
67
+
68
+ def set_compressors
69
+ env.js_compressor = Rails.application.config.assets.js_compressor
70
+ env.css_compressor = Rails.application.config.assets.css_compressor
71
+ end
72
+
73
+ def assets_precompile
74
+ manifest.clobber
75
+ manifest.compile('*')
76
+ end
77
+
78
+ def source_asset_path
79
+ theme.published? ? CURRENT_THEME_PATH : theme_path
80
+ end
81
+
82
+ def theme_path
83
+ File.join(THEME_PATH, theme.name)
84
+ end
85
+
86
+ end
@@ -0,0 +1,29 @@
1
+ class FileGeneratorService
2
+
3
+ attr_reader :template, :theme
4
+
5
+ def initialize(template)
6
+ @template = template
7
+ @theme = template.theme
8
+ end
9
+
10
+ def self.create(template)
11
+ new(template).send :create
12
+ end
13
+
14
+ private
15
+
16
+ def create
17
+ FileUtils.mkdir_p(output_directory)
18
+ File.open(filepath, 'w+') { |file| file.puts(template.body) }
19
+ end
20
+
21
+ def filepath
22
+ File.join(template.path, template.name)
23
+ end
24
+
25
+ def output_directory
26
+ File.dirname(filepath)
27
+ end
28
+
29
+ end
@@ -0,0 +1,101 @@
1
+ class TemplateGeneratorService
2
+
3
+ DEFAULT_LOCALE = 'en'
4
+ FILE_EXTENSIONS = { css: '.css', scss: '.scss', js: '.js', yml: '.yml' }
5
+ IMAGE_EXTENSIONS = ['.png', '.gif', '.jpeg', '.jpg']
6
+ FONT_EXTENSIONS = ['.woff', '.ttf', '.svg', '.eot', '.woff2', '.otf']
7
+
8
+ attr_reader :filepath, :theme_template, :theme
9
+
10
+ def initialize(filepath, theme)
11
+ @filepath = filepath
12
+ @theme = theme
13
+ @theme_template = build_template
14
+ end
15
+
16
+ def generate
17
+ return nil if(image_file?(filepath) || font_directory?(filepath))
18
+ theme_template.assign_attributes(template_attributes)
19
+ theme_template.save
20
+ end
21
+
22
+ private
23
+
24
+ def build_template
25
+ @theme.templates.find_or_initialize_by(path: get_path, name: file_name)
26
+ end
27
+
28
+ def template_attributes
29
+ {
30
+ body: File.read(filepath),
31
+ path: get_path,
32
+ partial: is_partial?,
33
+ handler: get_handler,
34
+ format: get_format,
35
+ locale: DEFAULT_LOCALE,
36
+ theme_id: theme.id,
37
+ name: file_name
38
+ }
39
+ end
40
+
41
+ def get_path
42
+ File.dirname(filepath)
43
+ end
44
+
45
+ def is_partial?
46
+ file_name.starts_with?('_')
47
+ end
48
+
49
+ def get_handler
50
+ return nil if assets_file?(filepath) || yml_files?(filepath)
51
+ File.extname(filepath).gsub('.', '')
52
+ end
53
+
54
+ def get_format
55
+ return nil if assets_file?(filepath) || yml_files?(filepath)
56
+ # In spree few `.js.erb` files related to google are rendered in html format.
57
+ script_embeded_partial? ? 'html' : format
58
+ end
59
+
60
+ def script_embeded_partial?
61
+ is_partial? && format.eql?('js')
62
+ end
63
+
64
+ def file_name
65
+ File.basename(filepath)
66
+ end
67
+
68
+ def format
69
+ file_name_without_ext.split('.')[-1]
70
+ end
71
+
72
+ def file_name_without_ext
73
+ File.basename(filepath, get_handler)
74
+ end
75
+
76
+ def stylesheet_file?(filename)
77
+ File.extname(filename) == FILE_EXTENSIONS[:css] || FILE_EXTENSIONS[:scss]
78
+ end
79
+
80
+ def javascript_file?(filename)
81
+ File.extname(filename) == FILE_EXTENSIONS[:js]
82
+ end
83
+
84
+ def assets_file?(filename)
85
+ stylesheet_file?(filename) || javascript_file?(filename)
86
+ end
87
+
88
+ # FIX_ME_PG:- considering all images used in themes to be kept in images directory. Later invalidate using file content-type.
89
+ def image_file?(filename)
90
+ file_name == 'snapshot.png' || get_path.split('/').include?('images') && IMAGE_EXTENSIONS.include?(File.extname(filename))
91
+ end
92
+
93
+ def font_directory?(filename)
94
+ get_path.split('/').include?('fonts') && FONT_EXTENSIONS.include?(File.extname(filename))
95
+ end
96
+
97
+ def yml_files?(filename)
98
+ File.extname(filename) == FILE_EXTENSIONS[:yml]
99
+ end
100
+
101
+ end
@@ -0,0 +1,87 @@
1
+ require 'zip'
2
+
3
+ class ZipFileBuilder
4
+
5
+ THEMES_PATH = File.join('public', 'vinsol_spree_themes')
6
+ INVALID_DIRECTORIES = ['.', '..', 'precompiled_assets']
7
+
8
+ attr_reader :theme, :entries, :input_path, :output_path, :zip, :name
9
+
10
+ def initialize(theme)
11
+ @theme = theme
12
+ @name = name
13
+ input_theme_directory_path
14
+ output_zip_file_path
15
+ end
16
+
17
+ def archive
18
+ remove
19
+ @entries = get_directory_content(input_theme_directory_path)
20
+ delete_non_zip_content(@entries)
21
+ build_zip_file
22
+ end
23
+
24
+ def remove
25
+ File.delete(output_path) if File.exist?(output_path)
26
+ end
27
+
28
+ def name
29
+ "#{ theme.name }.zip"
30
+ end
31
+
32
+ private
33
+
34
+ def input_theme_directory_path
35
+ @input_path = File.join(THEMES_PATH, theme.name)
36
+ end
37
+
38
+ def output_zip_file_path
39
+ @output_path = File.join('tmp', name)
40
+ end
41
+
42
+ def get_directory_content(directory_path)
43
+ Dir.entries(directory_path)
44
+ end
45
+
46
+ def delete_non_zip_content(entries)
47
+ INVALID_DIRECTORIES.each { |dir| entries.delete(dir) }
48
+ end
49
+
50
+ def build_zip_file
51
+ open_zip_file
52
+ write_entries('', entries)
53
+ zip.close();
54
+ end
55
+
56
+ def open_zip_file
57
+ @zip = Zip::File.open(output_path, Zip::File::CREATE)
58
+ end
59
+
60
+ def write_entries(path, entries)
61
+ entries.each do |e|
62
+ zip_path = path == '' ? e : File.join(path, e)
63
+ filepath = File.join(input_path, zip_path)
64
+
65
+ if File.directory?(filepath)
66
+ build_sub_directory(zip_path, filepath)
67
+ else
68
+ build_file_to_zip(zip_path, filepath)
69
+ end
70
+ end
71
+ end
72
+
73
+ def build_sub_directory(zip_path, filepath)
74
+ zip.mkdir(zip_path)
75
+ subdir_entries = get_directory_content(filepath);
76
+ delete_non_zip_content(subdir_entries)
77
+
78
+ write_entries(zip_path, subdir_entries)
79
+ end
80
+
81
+ def build_file_to_zip(zip_path, filepath)
82
+ zip.get_output_stream(zip_path) do |file|
83
+ file.puts(File.open(filepath, "rb").read())
84
+ end
85
+ end
86
+
87
+ end
@@ -0,0 +1,52 @@
1
+ require 'zip'
2
+
3
+ class ZipFileExtractor
4
+
5
+ OUTPUT_PATH = File.join('public', 'vinsol_spree_themes')
6
+ IGNORED_FILES_REGEX = /\/(\.|__)/
7
+
8
+ attr_reader :file_path, :theme
9
+
10
+ def initialize(file_path, theme)
11
+ @file_path = file_path
12
+ @theme = theme
13
+ end
14
+
15
+ def extract
16
+ FileUtils.mkdir_p(OUTPUT_PATH)
17
+ parse_file
18
+ end
19
+
20
+ private
21
+
22
+ def parse_file
23
+ Zip::File.open(file_path) do |zip_file|
24
+ zip_file.each do |file|
25
+ filepath = File.join(output_path, file.name)
26
+ next if filepath =~ IGNORED_FILES_REGEX
27
+ unless File.exist?(filepath)
28
+ FileUtils::mkdir_p(File.dirname(filepath))
29
+ zip_file.extract(file, filepath)
30
+ end
31
+ generate_template(filepath) if File.file?(filepath)
32
+ end
33
+ end
34
+ end
35
+
36
+ def output_path
37
+ @output_path ||= File.join(OUTPUT_PATH, file_name)
38
+ end
39
+
40
+ def file_name
41
+ @file_name ||= File.basename(file_path, file_extension)
42
+ end
43
+
44
+ def file_extension
45
+ File.extname(file_path)
46
+ end
47
+
48
+ def generate_template(filepath)
49
+ TemplateGeneratorService.new(filepath, theme).generate
50
+ end
51
+
52
+ end
@@ -0,0 +1,5 @@
1
+ <% if can? :admin, Spree::Theme %>
2
+ <ul class="nav nav-sidebar">
3
+ <%= tab Spree.t(:vinsol_spree_themes), url: admin_themes_path, icon: 'picture' %>
4
+ </ul>
5
+ <% end %>
@@ -0,0 +1,44 @@
1
+ <!-- LISTING ALL THE THEMES -->
2
+ <div class="themes-container">
3
+
4
+ <% sorted_themes(@themes).each do |theme| %>
5
+ <div class="theme theme-col col-md-4 col-sm-6 <%= theme.state %>">
6
+ <div class="theme-block">
7
+ <div class="thumbnail cmn-height-block">
8
+ <%= link_to image_tag(snapshot_path(theme)), admin_theme_templates_path(theme), class: 'img-responsive theme-image' %>
9
+ </div>
10
+
11
+ <div class="theme-content">
12
+ <div class="theme-name-area">
13
+ <h2 class="theme-name"><%= theme.name %></h2>
14
+
15
+ <div class="btn-group dropup">
16
+ <button type="button" class="btn btn-danger dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><i class="glyphicon glyphicon-option-horizontal more-action-glyphicon"></i></button>
17
+
18
+ <div class="dropdown-menu">
19
+ <% if theme.drafted? %>
20
+ <%= link_to Spree.t('actions.compiled'), state_change_admin_theme_path(theme, state: 'compiled'), method: :patch, class: 'dropdown-item' %>
21
+ <% elsif theme.compiled? %>
22
+ <%= link_to Spree.t('actions.published'), state_change_admin_theme_path(theme, state: 'published'), method: :patch, class: 'dropdown-item' %>
23
+ <% end %>
24
+
25
+ <% unless theme.published? %>
26
+ <%= link_to 'Delete', admin_theme_path(theme), method: :delete, class: 'dropdown-item', data: { confirm: 'Are you sure?' } %>
27
+ <% end %>
28
+
29
+ <%= link_to Spree.t('actions.download'), download_admin_theme_path(theme), method: :patch, class: 'dropdown-item action-download' %>
30
+ </div>
31
+ </div>
32
+ </div>
33
+ </div>
34
+
35
+ <div class="theme-action-view">
36
+ <%= link_to Spree.t(:templates), admin_theme_templates_path(theme) , class: 'btn btn-primary btn-sm' %>
37
+ <%= link_to Spree.t('actions.preview'), admin_theme_preview_path(theme_id: theme), class: 'btn btn-info btn-sm', target: '_blank' %>
38
+ </div>
39
+ </div>
40
+ </div>
41
+ <% end %>
42
+ </div>
43
+
44
+ <%= paginate @themes %>
@@ -0,0 +1,17 @@
1
+ <%= form_for @theme, url: upload_admin_themes_path, method: :post do |f| %>
2
+ <div class="updload-theme-panel col-md-4 col-sm-6" data-hook="theme-file-upload-form">
3
+ <div class="upload-theme-col">
4
+ <label class="cmn-height-block text-center">
5
+ <%= f.file_field :template_file, class: 'form-control' %>
6
+ <div class="file-btn-helper">
7
+ <i class="glyphicon glyphicon-upload upload-icon"></i><br />
8
+ ADD NEW THEME
9
+ </div>
10
+ </label>
11
+ </div>
12
+ </div>
13
+
14
+ <div class="form-actions hidden" data-hook="buttons">
15
+ <%= f.submit Spree.t('actions.upload'), class: 'btn-success' %>
16
+ </div>
17
+ <% end %>