├── .gitignore ├── Gemfile ├── LICENSE ├── LICENSE.txt ├── README.md ├── Rakefile ├── jekyll-auto-image.gemspec ├── lib ├── jekyll-auto-image.rb └── jekyll-auto-image │ └── version.rb └── test ├── fixtures ├── _posts │ └── 2015-01-01-post-with-contents-image.md ├── contents-html.html ├── contents-image.md ├── front-matter-image.md └── no-image.md ├── helper.rb └── test_jekyll_auto_image.rb /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.rbc 3 | .bundle 4 | .config 5 | .yardoc 6 | Gemfile.lock 7 | InstalledFiles 8 | _yardoc 9 | coverage 10 | doc/ 11 | lib/bundler/man 12 | pkg 13 | rdoc 14 | spec/reports 15 | test/tmp 16 | test/version_tmp 17 | tmp 18 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Specify your gem's dependencies in jekyll-auto-image.gemspec 4 | gemspec 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Merlos 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 Juan M. Merlos (@merlos) jekyll-auto-image 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # jekyll-auto-image plugin 2 | 3 | jekyll plugin that makes available the first image of a post in the template as a variable. 4 | 5 | By installing the plugin you will be able to access the first image of a page through `{{ @page.image }}`. 6 | 7 | This plugin is useful if you want to: 8 | 9 | * Include an image on your list of posts 10 | * Set a twitter card image for a post (see example below) 11 | 12 | 13 | # Install 14 | 15 | Add to your Gemfile: 16 | 17 | ``` 18 | gem 'jekyll-auto-image' 19 | ``` 20 | or run 21 | 22 | ``` 23 | $ gem install jekyll-auto-image 24 | ``` 25 | 26 | 27 | Then, add to your `_config.yml`: 28 | 29 | ```yaml 30 | gems: 31 | - jekyll-auto-image 32 | ``` 33 | 34 | The plugin allows you to set a default image for all pages/posts. To do that, add to your `_config.yml`: 35 | 36 | ```yaml 37 | # _config.yml 38 | 39 | image: /path/to/your/default/image.png 40 | ``` 41 | 42 | ### Jekyll 3.0 43 | Versions of jekyll-auto-image >= 1.1.0 are compatible with jekyll 3.0. If you require compatibility with jekyll 2.0 use jekyll-auto-image 1.0.2. 44 | 45 | ``` 46 | # Run this command check installed versions 47 | $ gem list | grep jekyll 48 | jekyll (3.0.1) 49 | jekyll-auto-image (1.0.2) 50 | ``` 51 | 52 | # Usage 53 | 54 | In each post/page, the plugin will set `{{ page.image }}` following this fallback rules: 55 | 56 | 1. Front matter `image` value 57 | 2. First image in the post/page contents 58 | 3. Default site image (defined in `_config.yml`) 59 | 4. nil 60 | 61 | Basically, the plugin will return the front matter image value if set. If it is not set, then it will look for the first image asset that is defined in your post content. If the post does not have any image, then it will set the site.image defined in _config.yml. 62 | 63 | 64 | ### Example of usage 65 | 66 | Example post 1: 67 | 68 | ```markdown 69 | --- 70 | layout: post 71 | title: Post 1 72 | --- 73 | 74 | This is my example post. It includes an image in the contents. 75 | 76 | ![first image](/assets/first_image.png) 77 | 78 | ``` 79 | Example post 2: 80 | 81 | ```markdown 82 | --- 83 | layout: post 84 | title: Post 2 85 | image: /assets/front_matter_image.png 86 | --- 87 | 88 | This is my second example post, because the 89 | post includes the front matter image, the plugin 90 | will return it instead of the first image in the 91 | contents. 92 | 93 | ![first image](/assets/first_image.png) 94 | 95 | ``` 96 | 97 | #### Template example 98 | 99 | ```liquid 100 | {% for post in site.posts %} 101 | title: {{ post.title }} 102 |
103 | image: {{ post.image }} 104 |
105 | ``` 106 | 107 | #### Output HTML Rendered: 108 | 109 | ```html 110 | title: Post 1 111 |
112 | image: /assets/first_image.png 113 |
114 | 115 | title: Post 2 116 |
117 | image: /assets/front_matter_image.png 118 | ``` 119 | ### Example using twitter cards 120 | 121 | Another use of this plugin is to create a [twitter card](https://dev.twitter.com/cards/getting-started). 122 | 123 | You can define a set of `` elements in your `head.html` template, so when sharing a post in twitter, the tweet displays it in cool way. You have more info in [twitter's developers page](https://dev.twitter.com/cards/types) 124 | 125 | Here you have a sample: 126 | 127 | ```html 128 | 129 | 130 | 131 | 132 | 133 | 134 | {% if page.image %} 135 | 136 | {% endif %} 137 | 138 | ``` 139 | 140 | You can validate how it will look using the [cards validator](https://cards-dev.twitter.com/validator) 141 | 142 | 143 | # Contributing 144 | 145 | 1. Fork it (https://github.com/merlos/jekyll-auto-image/fork) 146 | 2. Create your feature branch (`git checkout -b my-new-feature) 147 | 3. Commit your changes (`git commit -am 'Add some feature'`) 148 | 4. Push to the branch (git push origin my-new-feature) 149 | 4. Create a new Pull Request 150 | 151 | # Run tests 152 | 153 | ``` 154 | $ rake test 155 | ``` 156 | 157 | The tests are based on the code of [https://github.com/ivantsepp/jekyll-autolink_email](https://github.com/ivantsepp/jekyll-autolink_email) 158 | 159 | 160 | # License 161 | 162 | Copyright (c) 2015 Juan M. Merlos (@merlos) [www.merlos.org](http://www.merlos.org) Distributed under MIT License 163 | 164 | 165 | 166 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | require 'rake/testtask' 3 | 4 | Rake::TestTask.new(:test) do |t| 5 | t.libs << 'test' 6 | t.test_files = FileList['test/test_*.rb'] 7 | t.verbose = true 8 | end -------------------------------------------------------------------------------- /jekyll-auto-image.gemspec: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | lib = File.expand_path('../lib', __FILE__) 3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 4 | require 'jekyll-auto-image/version' 5 | 6 | Gem::Specification.new do |spec| 7 | spec.name = "jekyll-auto-image" 8 | spec.version = Jekyll::AutoImage::VERSION 9 | spec.authors = ["merlos"] 10 | spec.email = ["jmmerlos@merlos.org"] 11 | spec.summary = %q{jekyll plugin that makes available the first image of a post in the template} 12 | spec.description = %q{jekyll plugin that makes available the first image of a post in the template} 13 | spec.homepage = "https://github.com/merlos/jekyll-auto-image" 14 | spec.license = "MIT" 15 | 16 | spec.files = `git ls-files`.split($/) 17 | spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } 18 | spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) 19 | spec.require_paths = ["lib"] 20 | 21 | spec.add_dependency "jekyll" 22 | 23 | spec.add_development_dependency "bundler", "~> 1.5" 24 | spec.add_development_dependency "rake" 25 | spec.add_development_dependency "shoulda" 26 | spec.add_development_dependency "mocha" 27 | 28 | end 29 | -------------------------------------------------------------------------------- /lib/jekyll-auto-image.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Juan M. Merlos (@merlos) jekyll-auto-image 3 | # 4 | # MIT License 5 | # 6 | # Permission is hereby granted, free of charge, to any person obtaining 7 | # a copy of this software and associated documentation files (the 8 | # "Software"), to deal in the Software without restriction, including 9 | # without limitation the rights to use, copy, modify, merge, publish, 10 | # distribute, sublicense, and/or sell copies of the Software, and to 11 | # permit persons to whom the Software is furnished to do so, subject to 12 | # the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be 15 | # included in all copies or substantial portions of the Software. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 20 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 21 | # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 22 | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 23 | # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | 26 | require "jekyll-auto-image/version" 27 | require "jekyll" 28 | 29 | module Jekyll 30 | 31 | # 32 | # Auto Image Generator 33 | # 34 | # Sets {{page.image}} variable in liquid with the following fallback: 35 | # 36 | # 1) image value in front matter 37 | # 2) first image in the post/pàge 38 | # 3) _config.yaml image default 39 | # 4) nothing (not set) 40 | # 41 | # 42 | class AutoImageGenerator < Generator 43 | 44 | def generate(site) 45 | @site = site 46 | 47 | site.pages.each do |page| 48 | img = get_image(page) 49 | page.data['image'] = img if img 50 | end 51 | # Now do the same with posts 52 | site.posts.docs.each do |post| 53 | #puts "hola" 54 | #puts Jekyll::VERSION 55 | #puts post.class 56 | #puts post.inspect 57 | #puts post.data.inspect 58 | #puts "-----" 59 | #puts post.output 60 | #puts "----" 61 | img = get_image(post) 62 | post.data['image'] = img if img 63 | end 64 | end # generate 65 | 66 | # 67 | # page: is either a Jekyll::Page or a Jekyll::Post in 2.x. In Jekyll 3.0 is Jekyll::Document and 68 | # in Jekyll 3.3 is either Jekyll::Page or Jekyll::Document (fascinating!) 69 | # 70 | # returns the path of the first image found in the contents 71 | # of the page/post 72 | # 73 | def get_image(page) 74 | 75 | # debug lines 76 | #puts page.title 77 | #puts page.name 78 | #puts page.ext 79 | #puts @site.converters.select { |c| c.matches(page.ext) }.sort 80 | if page.data['image'] 81 | return page.data['image'] 82 | end 83 | 84 | # fix for jekyll 3.3.0, 85 | @site.config['kramdown'] = @site.config['kramdown'].dup 86 | 87 | # convert the contents to html, and extract the first Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin finibus, ante ut tincidunt placerat, sapien nulla lobortis tellus, vel consequat quam est eget ligula. 6 |

7 | blabla 8 | 9 |

10 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin finibus, ante ut tincidunt placerat, sapien nulla lobortis tellus, vel consequat quam est eget ligula. 11 |

12 |

13 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin finibus, ante ut tincidunt placerat, sapien nulla lobortis tellus, vel consequat quam est eget ligula. 14 |

-------------------------------------------------------------------------------- /test/fixtures/contents-image.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Page with an image in the contents 3 | --- 4 | 5 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin finibus, ante ut tincidunt placerat, sapien nulla lobortis tellus, vel consequat quam est eget ligula. 6 | 7 | ![Image within the contents](/assets/contents-image.png) 8 | 9 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin finibus, ante ut tincidunt placerat, sapien nulla lobortis tellus, vel consequat quam est eget ligula. 10 | 11 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin finibus, ante ut tincidunt placerat, sapien nulla lobortis tellus, vel consequat quam est eget ligula. -------------------------------------------------------------------------------- /test/fixtures/front-matter-image.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Page that defines the front matter image 3 | image: /assets/front-matter-image.png 4 | --- 5 | 6 | Although this post has the following image in the contents, the plugin should set the one in the frontmatter 7 | 8 | ![In post Image](/assets/contents-image.png) -------------------------------------------------------------------------------- /test/fixtures/no-image.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: this page does not have an image 3 | --- 4 | 5 | This post does not have an image, in the fallback rules it should display the site.image or nothing if site.image is not defined in _config.yml -------------------------------------------------------------------------------- /test/helper.rb: -------------------------------------------------------------------------------- 1 | require 'minitest/autorun' 2 | require 'minitest/unit' 3 | require 'shoulda' 4 | require 'mocha/mini_test' 5 | require 'jekyll' 6 | require 'jekyll-auto-image' 7 | -------------------------------------------------------------------------------- /test/test_jekyll_auto_image.rb: -------------------------------------------------------------------------------- 1 | require 'helper' 2 | 3 | class Jekyll::AutoImageTest < Minitest::Test 4 | def set_page_image (page, image_path) 5 | page.instance_variable_set(:@content, '') 6 | end 7 | 8 | context 'AutoImage' do 9 | 10 | setup do 11 | 12 | @default_image_path = '/assets/default_image.png' 13 | 14 | Jekyll.logger.log_level = :error 15 | 16 | # 17 | # Sites 18 | # 19 | @config = Jekyll::Configuration::DEFAULTS.dup 20 | @config['destination'] = File.expand_path('../tmp/', __FILE__) 21 | @site = Jekyll::Site.new(@config) 22 | 23 | # config with default image 24 | @config_with_image = @config.dup 25 | @config_with_image['image'] = @default_image_path 26 | @site_with_default_image = Jekyll::Site.new(@config_with_image) 27 | 28 | # posts are in test/fixtures/_posts/ 29 | @config_with_posts = @config.dup 30 | @config_with_posts['source'] = File.expand_path('../fixtures/', __FILE__) 31 | @site_with_posts = Jekyll::Site.new(@config_with_posts) 32 | # now add the collection 33 | @posts_collection = Jekyll::Collection.new(@site_with_posts, 'posts') 34 | 35 | # Pages 36 | @no_image_page = Jekyll::Page.new(@site, File.expand_path('../fixtures/', __FILE__), '', 'no-image.md') 37 | @front_matter_image_page = Jekyll::Page.new(@site, File.expand_path('../fixtures/', __FILE__), '', 'front-matter-image.md') 38 | @contents_image_page = Jekyll::Page.new(@site, File.expand_path('../fixtures/', __FILE__), '', 'contents-image.md') 39 | @contents_html_page = Jekyll::Page.new(@site, File.expand_path('../fixtures/', __FILE__), '', 'contents-html.html') 40 | 41 | # Posts as collections 42 | #@contents_html_page = Jekyll::Document.new(File.expand_path('../fixtures/_posts/contents-image.md', __FILE__), {:site =>@site,:collection =>'post'}) 43 | 44 | 45 | @auto_image = Jekyll::AutoImageGenerator.new 46 | @auto_image.generate(@site) 47 | @auto_image_with_default_image = Jekyll::AutoImageGenerator.new 48 | @auto_image_with_default_image.generate(@site_with_default_image) 49 | 50 | 51 | #@page.instance_variable_set(:@content, '
ivan.tse1@gmail.com
') 52 | #@site.pages << @page 53 | #@email_link = '
ivan.tse1@gmail.com
' 54 | end 55 | 56 | 57 | # 58 | # FALLBACK LOGIC TESTS 59 | # 60 | 61 | # Tests without {{site.image}} 62 | 63 | should 'not be defined site image by default' do 64 | assert_nil @site.config['image'] 65 | end 66 | 67 | should 'not return image when not set in config and not included in page' do 68 | assert_nil @auto_image.get_image(@no_image_page) 69 | end 70 | 71 | should 'use front matter image whenever defined' do 72 | assert_equal @front_matter_image_page.data['image'], @auto_image.get_image(@front_matter_image_page) 73 | end 74 | 75 | should 'detect contents image on markdown' do 76 | assert_equal '/assets/contents-image.png', @auto_image.get_image(@contents_image_page) 77 | end 78 | 79 | should 'detect contents image in html' do 80 | assert_equal '/assets/contents-html.png', @auto_image.get_image(@contents_html_page) 81 | end 82 | 83 | # Tests with {{site.image}} defined 84 | 85 | should 'be defined site_image in config' do 86 | assert_equal @default_image_path, @site_with_default_image.config['image'] 87 | end 88 | 89 | should 'return default image when page does not have image' do 90 | assert_equal @site_with_default_image.config['image'], @auto_image_with_default_image.get_image(@no_image_page) 91 | end 92 | 93 | should 'return front matter image even if default image is defined' do 94 | assert_equal @front_matter_image_page.data['image'], @auto_image_with_default_image.get_image(@front_matter_image_page) 95 | end 96 | 97 | 98 | # 99 | # Tests to check if the regexp works in some use cases 100 | # 101 | should 'find contents image that includes http' do 102 | image ="http://github.com/merlos/jekyll-auto-image/yes.png" 103 | set_page_image(@no_image_page,image) 104 | assert image, @auto_image.get_image(@no_image_page) 105 | end 106 | 107 | # 108 | # Tests to check if the regexp works in some use cases 109 | # 110 | should 'find image with weird characters in name' do 111 | image ="http://github.com/merlos/%$·$%&/(),.-,.-./yes.png" 112 | set_page_image(@no_image_page,image) 113 | assert image, @auto_image.get_image(@no_image_page) 114 | end 115 | 116 | # 117 | # Tests to check if the regexp works in some use cases 118 | # 119 | should 'not find image with space in name' do 120 | image ="http://github.com/merlos/jekyll auto image/yes.png" 121 | set_page_image(@no_image_page,image) 122 | assert_nil @auto_image.get_image(@no_image_page) 123 | end 124 | 125 | # 126 | # Generate site with data 127 | # 128 | should 'generate a site with a page' do 129 | #add page to site 130 | @site.pages << @contents_image_page 131 | @site.generate() 132 | @auto_image.generate(@site) 133 | @auto_image.get_image(@contents_html_page) 134 | assert_equal '/assets/contents-html.png', @auto_image.get_image(@contents_html_page) 135 | end 136 | 137 | should 'generate a site with post as part of collection' do 138 | #puts @posts_collection.directory 139 | assert_equal 1, @posts_collection.entries.length 140 | assert_equal 1, @posts_collection.filtered_entries.length 141 | @site_with_posts.process 142 | @auto_image.generate(@site_with_posts) 143 | assert_equal 1, @site_with_posts.posts.docs.length 144 | #puts @site_with_posts.collections.inspect 145 | assert_equal '/assets/contents-image.png', @auto_image.get_image(@site_with_posts.posts.docs[0]) 146 | end 147 | 148 | 149 | end 150 | end 151 | --------------------------------------------------------------------------------