mirror of
https://github.com/danbee/my-images
synced 2025-03-04 08:49:05 +00:00
Remove tags with JS
This commit is contained in:
parent
b42a80f806
commit
1ce11c4781
18
.babelrc
Normal file
18
.babelrc
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"presets": [
|
||||||
|
["env", {
|
||||||
|
"modules": false,
|
||||||
|
"targets": {
|
||||||
|
"browsers": "> 1%",
|
||||||
|
"uglify": true
|
||||||
|
},
|
||||||
|
"useBuiltIns": true
|
||||||
|
}]
|
||||||
|
],
|
||||||
|
|
||||||
|
"plugins": [
|
||||||
|
"syntax-dynamic-import",
|
||||||
|
"transform-object-rest-spread",
|
||||||
|
["transform-class-properties", { "spec": true }]
|
||||||
|
]
|
||||||
|
}
|
||||||
5
.gitignore
vendored
5
.gitignore
vendored
@ -20,3 +20,8 @@
|
|||||||
|
|
||||||
# Ignore dragonfly uploads
|
# Ignore dragonfly uploads
|
||||||
/public/system
|
/public/system
|
||||||
|
/public/packs
|
||||||
|
/public/packs-test
|
||||||
|
/node_modules
|
||||||
|
yarn-debug.log*
|
||||||
|
.yarn-integrity
|
||||||
|
|||||||
3
.postcssrc.yml
Normal file
3
.postcssrc.yml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
plugins:
|
||||||
|
postcss-import: {}
|
||||||
|
postcss-cssnext: {}
|
||||||
2
Gemfile
2
Gemfile
@ -16,6 +16,7 @@ gem "puma"
|
|||||||
gem "sass-rails"
|
gem "sass-rails"
|
||||||
gem "simple_form"
|
gem "simple_form"
|
||||||
gem "uglifier"
|
gem "uglifier"
|
||||||
|
gem "webpacker"
|
||||||
|
|
||||||
group :doc do
|
group :doc do
|
||||||
gem "sdoc", require: false
|
gem "sdoc", require: false
|
||||||
@ -30,6 +31,7 @@ end
|
|||||||
group :test do
|
group :test do
|
||||||
gem "capybara"
|
gem "capybara"
|
||||||
gem "launchy"
|
gem "launchy"
|
||||||
|
gem "poltergeist"
|
||||||
gem "rspec-rails"
|
gem "rspec-rails"
|
||||||
gem "shoulda-matchers"
|
gem "shoulda-matchers"
|
||||||
gem "webmock"
|
gem "webmock"
|
||||||
|
|||||||
13
Gemfile.lock
13
Gemfile.lock
@ -59,6 +59,7 @@ GEM
|
|||||||
rack (>= 1.6.0)
|
rack (>= 1.6.0)
|
||||||
rack-test (>= 0.6.3)
|
rack-test (>= 0.6.3)
|
||||||
xpath (~> 3.1)
|
xpath (~> 3.1)
|
||||||
|
cliver (0.3.2)
|
||||||
coderay (1.1.2)
|
coderay (1.1.2)
|
||||||
concurrent-ruby (1.0.5)
|
concurrent-ruby (1.0.5)
|
||||||
crack (0.4.3)
|
crack (0.4.3)
|
||||||
@ -142,12 +143,18 @@ GEM
|
|||||||
oauth2 (~> 1.1)
|
oauth2 (~> 1.1)
|
||||||
omniauth (~> 1.2)
|
omniauth (~> 1.2)
|
||||||
pg (1.1.3)
|
pg (1.1.3)
|
||||||
|
poltergeist (1.18.1)
|
||||||
|
capybara (>= 2.1, < 4)
|
||||||
|
cliver (~> 0.3.1)
|
||||||
|
websocket-driver (>= 0.2.0)
|
||||||
pry (0.11.3)
|
pry (0.11.3)
|
||||||
coderay (~> 1.1.0)
|
coderay (~> 1.1.0)
|
||||||
method_source (~> 0.9.0)
|
method_source (~> 0.9.0)
|
||||||
public_suffix (3.0.3)
|
public_suffix (3.0.3)
|
||||||
puma (3.12.0)
|
puma (3.12.0)
|
||||||
rack (2.0.5)
|
rack (2.0.5)
|
||||||
|
rack-proxy (0.6.4)
|
||||||
|
rack
|
||||||
rack-test (1.1.0)
|
rack-test (1.1.0)
|
||||||
rack (>= 1.0, < 3)
|
rack (>= 1.0, < 3)
|
||||||
rails (5.2.1)
|
rails (5.2.1)
|
||||||
@ -236,6 +243,10 @@ GEM
|
|||||||
addressable (>= 2.3.6)
|
addressable (>= 2.3.6)
|
||||||
crack (>= 0.3.2)
|
crack (>= 0.3.2)
|
||||||
hashdiff
|
hashdiff
|
||||||
|
webpacker (3.5.5)
|
||||||
|
activesupport (>= 4.2)
|
||||||
|
rack-proxy (>= 0.6.1)
|
||||||
|
railties (>= 4.2)
|
||||||
websocket-driver (0.7.0)
|
websocket-driver (0.7.0)
|
||||||
websocket-extensions (>= 0.1.0)
|
websocket-extensions (>= 0.1.0)
|
||||||
websocket-extensions (0.1.3)
|
websocket-extensions (0.1.3)
|
||||||
@ -257,6 +268,7 @@ DEPENDENCIES
|
|||||||
launchy
|
launchy
|
||||||
omniauth-github
|
omniauth-github
|
||||||
pg
|
pg
|
||||||
|
poltergeist
|
||||||
pry
|
pry
|
||||||
puma
|
puma
|
||||||
rails (= 5.2.1)
|
rails (= 5.2.1)
|
||||||
@ -267,6 +279,7 @@ DEPENDENCIES
|
|||||||
simple_form
|
simple_form
|
||||||
uglifier
|
uglifier
|
||||||
webmock
|
webmock
|
||||||
|
webpacker
|
||||||
|
|
||||||
RUBY VERSION
|
RUBY VERSION
|
||||||
ruby 2.5.1p57
|
ruby 2.5.1p57
|
||||||
|
|||||||
@ -1,15 +0,0 @@
|
|||||||
// This is a manifest file that'll be compiled into application.js, which will include all the files
|
|
||||||
// listed below.
|
|
||||||
//
|
|
||||||
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
|
|
||||||
// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
|
|
||||||
//
|
|
||||||
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
|
|
||||||
// compiled file.
|
|
||||||
//
|
|
||||||
// Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
|
|
||||||
// about supported directives.
|
|
||||||
//
|
|
||||||
//= require jquery
|
|
||||||
//= require jquery_ujs
|
|
||||||
//= require_tree .
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
// Place all the behaviors and hooks related to the matching controller here.
|
|
||||||
// All this logic will automatically be available in application.js.
|
|
||||||
// You can use CoffeeScript in this file: http://coffeescript.org/
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
// Place all the behaviors and hooks related to the matching controller here.
|
|
||||||
// All this logic will automatically be available in application.js.
|
|
||||||
// You can use CoffeeScript in this file: http://coffeescript.org/
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
// Place all the behaviors and hooks related to the matching controller here.
|
|
||||||
// All this logic will automatically be available in application.js.
|
|
||||||
// You can use CoffeeScript in this file: http://coffeescript.org/
|
|
||||||
@ -14,7 +14,7 @@
|
|||||||
grid-area: image-info;
|
grid-area: image-info;
|
||||||
}
|
}
|
||||||
|
|
||||||
.image-tags {
|
.image-tags-list {
|
||||||
list-style: none;
|
list-style: none;
|
||||||
padding-left: 0;
|
padding-left: 0;
|
||||||
}
|
}
|
||||||
@ -27,6 +27,10 @@
|
|||||||
color: #333;
|
color: #333;
|
||||||
margin: 0.25rem 0.125rem;
|
margin: 0.25rem 0.125rem;
|
||||||
padding: 0.125rem 0.5rem;
|
padding: 0.125rem 0.5rem;
|
||||||
|
|
||||||
|
&.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
img {
|
img {
|
||||||
|
|||||||
@ -4,7 +4,7 @@ class TagsController < ApplicationController
|
|||||||
def create
|
def create
|
||||||
image = @current_user.images.find(params[:image_id])
|
image = @current_user.images.find(params[:image_id])
|
||||||
tag = params[:tag]
|
tag = params[:tag]
|
||||||
image.tags << tag unless image.tags.include? tag
|
image.tags << tag unless image.tags.include?(tag)
|
||||||
image.save
|
image.save
|
||||||
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
|
|||||||
31
app/javascript/controllers/tag_controller.js
Normal file
31
app/javascript/controllers/tag_controller.js
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import { Controller } from "stimulus";
|
||||||
|
import ajaxService from "../services/ajax_service";
|
||||||
|
|
||||||
|
export default class extends Controller {
|
||||||
|
static targets = [ "name" ];
|
||||||
|
|
||||||
|
connect() {
|
||||||
|
console.log("Connected to our tags");
|
||||||
|
}
|
||||||
|
|
||||||
|
disconnect() {
|
||||||
|
console.log("Bye bye tag!");
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(event) {
|
||||||
|
const imageId = this.element.dataset.imageId;
|
||||||
|
const tag = this.nameTarget.innerText;
|
||||||
|
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
this.element.classList.add("hidden");
|
||||||
|
|
||||||
|
ajaxService.deleteTag(tag)
|
||||||
|
.then(response => {
|
||||||
|
this.element.parentElement.removeChild(this.element);
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
this.element.classList.remove("hidden")
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
15
app/javascript/packs/application.js
Normal file
15
app/javascript/packs/application.js
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
/* eslint no-console:0 */
|
||||||
|
// This file is automatically compiled by Webpack, along with any other files
|
||||||
|
// present in this directory. You're encouraged to place your actual application logic in
|
||||||
|
// a relevant structure within app/javascript and only use these pack files to reference
|
||||||
|
// that code so it'll be compiled.
|
||||||
|
//
|
||||||
|
// To reference this file, add <%= javascript_pack_tag 'application' %> to the appropriate
|
||||||
|
// layout file, like app/views/layouts/application.html.erb
|
||||||
|
|
||||||
|
import { Application } from "stimulus";
|
||||||
|
import { definitionsFromContext } from "stimulus/webpack-helpers";
|
||||||
|
|
||||||
|
const application = Application.start();
|
||||||
|
const context = require.context("controllers", true, /.js$/);
|
||||||
|
application.load(definitionsFromContext(context));
|
||||||
29
app/javascript/services/ajax_service.js
Normal file
29
app/javascript/services/ajax_service.js
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import axios from "axios";
|
||||||
|
|
||||||
|
const csrfToken = () => {
|
||||||
|
return document
|
||||||
|
.getElementsByName("csrf-token")[0]
|
||||||
|
.attributes["content"]
|
||||||
|
.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
const imageId = () => {
|
||||||
|
return document
|
||||||
|
.getElementsByClassName("show-image")[0]
|
||||||
|
.attributes["data-image-id"]
|
||||||
|
.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
const config = () => ({
|
||||||
|
headers: { "X-CSRF-Token": csrfToken() }
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
export default {
|
||||||
|
createTag: (tag) => {
|
||||||
|
},
|
||||||
|
|
||||||
|
deleteTag: (tag) => {
|
||||||
|
return axios.delete(`/user/images/${imageId()}/tags/${tag}.json`, config());
|
||||||
|
}
|
||||||
|
}
|
||||||
10
app/views/images/_tag.html.erb
Normal file
10
app/views/images/_tag.html.erb
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<li class="image-tag"
|
||||||
|
id="tag-<%= tag %>"
|
||||||
|
data-controller="tag">
|
||||||
|
<span data-target="tag.name"><%= tag %></span>
|
||||||
|
<%= link_to "×".html_safe,
|
||||||
|
user_image_tag_path(@image, tag),
|
||||||
|
method: :delete,
|
||||||
|
data: { action: "click->tag#delete" },
|
||||||
|
class: "delete-tag" %>
|
||||||
|
</li>
|
||||||
@ -4,19 +4,23 @@
|
|||||||
<%= @image.image.name %>
|
<%= @image.image.name %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<div class="show-image">
|
<div class="show-image" data-image-id="<%= @image.id %>">
|
||||||
<div class="image-container">
|
<div class="image-container">
|
||||||
<%= render "image", image: @image %>
|
<%= render "image", image: @image %>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="image-info">
|
<div class="image-info">
|
||||||
<%= render "tags/tags", image: @image, tags: @image.tags %>
|
<div class="image-tags">
|
||||||
|
<%= render "tags/tags", image: @image, tags: @image.tags %>
|
||||||
|
|
||||||
<div class="new-tag-form">
|
<div class="new-tag-form">
|
||||||
<%= form_tag user_image_tags_path(@image), remote: true, method: :post do %>
|
<%= form_tag user_image_tags_path(@image),
|
||||||
<%= text_field_tag :tag %>
|
remote: true,
|
||||||
<%= submit_tag "Add Tag" %>
|
method: :post do %>
|
||||||
<% end %>
|
<%= text_field_tag :tag %>
|
||||||
|
<%= submit_tag "Add Tag" %>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -3,8 +3,8 @@
|
|||||||
<head>
|
<head>
|
||||||
<title>My Images</title>
|
<title>My Images</title>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<%= stylesheet_link_tag "application", media: "all", "data-turbolinks-track" => true %>
|
<%= stylesheet_link_tag "application", media: "all" %>
|
||||||
<%= javascript_include_tag "application", "data-turbolinks-track" => true %>
|
<%= javascript_pack_tag "application" %>
|
||||||
<%= csrf_meta_tags %>
|
<%= csrf_meta_tags %>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
<ul class="image-tags" id="image-tags">
|
<ul class="image-tags-list" id="image-tags">
|
||||||
<% tags.each do |tag| %>
|
<% tags.each do |tag| %>
|
||||||
<%= render "tags/tag", image: image, tag: tag %>
|
<%= render "tags/tag", image: image, tag: tag %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|||||||
15
bin/webpack
Executable file
15
bin/webpack
Executable file
@ -0,0 +1,15 @@
|
|||||||
|
#!/usr/bin/env ruby
|
||||||
|
|
||||||
|
ENV["RAILS_ENV"] ||= ENV["RACK_ENV"] || "development"
|
||||||
|
ENV["NODE_ENV"] ||= "development"
|
||||||
|
|
||||||
|
require "pathname"
|
||||||
|
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
||||||
|
Pathname.new(__FILE__).realpath)
|
||||||
|
|
||||||
|
require "rubygems"
|
||||||
|
require "bundler/setup"
|
||||||
|
|
||||||
|
require "webpacker"
|
||||||
|
require "webpacker/webpack_runner"
|
||||||
|
Webpacker::WebpackRunner.run(ARGV)
|
||||||
15
bin/webpack-dev-server
Executable file
15
bin/webpack-dev-server
Executable file
@ -0,0 +1,15 @@
|
|||||||
|
#!/usr/bin/env ruby
|
||||||
|
|
||||||
|
ENV["RAILS_ENV"] ||= ENV["RACK_ENV"] || "development"
|
||||||
|
ENV["NODE_ENV"] ||= "development"
|
||||||
|
|
||||||
|
require "pathname"
|
||||||
|
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
||||||
|
Pathname.new(__FILE__).realpath)
|
||||||
|
|
||||||
|
require "rubygems"
|
||||||
|
require "bundler/setup"
|
||||||
|
|
||||||
|
require "webpacker"
|
||||||
|
require "webpacker/dev_server_runner"
|
||||||
|
Webpacker::DevServerRunner.run(ARGV)
|
||||||
5
config/webpack/development.js
Normal file
5
config/webpack/development.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
process.env.NODE_ENV = process.env.NODE_ENV || 'development'
|
||||||
|
|
||||||
|
const environment = require('./environment')
|
||||||
|
|
||||||
|
module.exports = environment.toWebpackConfig()
|
||||||
3
config/webpack/environment.js
Normal file
3
config/webpack/environment.js
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
const { environment } = require('@rails/webpacker')
|
||||||
|
|
||||||
|
module.exports = environment
|
||||||
5
config/webpack/production.js
Normal file
5
config/webpack/production.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
process.env.NODE_ENV = process.env.NODE_ENV || 'production'
|
||||||
|
|
||||||
|
const environment = require('./environment')
|
||||||
|
|
||||||
|
module.exports = environment.toWebpackConfig()
|
||||||
5
config/webpack/test.js
Normal file
5
config/webpack/test.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
process.env.NODE_ENV = process.env.NODE_ENV || 'development'
|
||||||
|
|
||||||
|
const environment = require('./environment')
|
||||||
|
|
||||||
|
module.exports = environment.toWebpackConfig()
|
||||||
68
config/webpacker.yml
Normal file
68
config/webpacker.yml
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
# Note: You must restart bin/webpack-dev-server for changes to take effect
|
||||||
|
|
||||||
|
default: &default
|
||||||
|
source_path: app/javascript
|
||||||
|
source_entry_path: packs
|
||||||
|
public_output_path: packs
|
||||||
|
cache_path: tmp/cache/webpacker
|
||||||
|
|
||||||
|
# Additional paths webpack should lookup modules
|
||||||
|
# ['app/assets', 'engine/foo/app/assets']
|
||||||
|
resolved_paths: []
|
||||||
|
|
||||||
|
# Reload manifest.json on all requests so we reload latest compiled packs
|
||||||
|
cache_manifest: false
|
||||||
|
|
||||||
|
extensions:
|
||||||
|
- .js
|
||||||
|
- .sass
|
||||||
|
- .scss
|
||||||
|
- .css
|
||||||
|
- .module.sass
|
||||||
|
- .module.scss
|
||||||
|
- .module.css
|
||||||
|
- .png
|
||||||
|
- .svg
|
||||||
|
- .gif
|
||||||
|
- .jpeg
|
||||||
|
- .jpg
|
||||||
|
|
||||||
|
development:
|
||||||
|
<<: *default
|
||||||
|
compile: true
|
||||||
|
|
||||||
|
# Reference: https://webpack.js.org/configuration/dev-server/
|
||||||
|
dev_server:
|
||||||
|
https: false
|
||||||
|
host: localhost
|
||||||
|
port: 3035
|
||||||
|
public: localhost:3035
|
||||||
|
hmr: false
|
||||||
|
# Inline should be set to true if using HMR
|
||||||
|
inline: true
|
||||||
|
overlay: true
|
||||||
|
compress: true
|
||||||
|
disable_host_check: true
|
||||||
|
use_local_ip: false
|
||||||
|
quiet: false
|
||||||
|
headers:
|
||||||
|
'Access-Control-Allow-Origin': '*'
|
||||||
|
watch_options:
|
||||||
|
ignored: /node_modules/
|
||||||
|
|
||||||
|
|
||||||
|
test:
|
||||||
|
<<: *default
|
||||||
|
compile: true
|
||||||
|
|
||||||
|
# Compile test packs to a separate directory
|
||||||
|
public_output_path: packs-test
|
||||||
|
|
||||||
|
production:
|
||||||
|
<<: *default
|
||||||
|
|
||||||
|
# Production depends on precompilation of packs prior to booting for performance.
|
||||||
|
compile: false
|
||||||
|
|
||||||
|
# Cache manifest.json for performance
|
||||||
|
cache_manifest: true
|
||||||
10
package.json
Normal file
10
package.json
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"dependencies": {
|
||||||
|
"@rails/webpacker": "3.5",
|
||||||
|
"axios": "^0.18.0",
|
||||||
|
"stimulus": "^1.1.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"webpack-dev-server": "2.11.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -9,6 +9,7 @@ end
|
|||||||
require "rspec/rails"
|
require "rspec/rails"
|
||||||
require "shoulda/matchers"
|
require "shoulda/matchers"
|
||||||
require "capybara/rspec"
|
require "capybara/rspec"
|
||||||
|
require "capybara/poltergeist"
|
||||||
|
|
||||||
Dir[Rails.root.join("spec", "support", "**", "*.rb")].each { |f| require f }
|
Dir[Rails.root.join("spec", "support", "**", "*.rb")].each { |f| require f }
|
||||||
|
|
||||||
@ -19,6 +20,8 @@ rescue ActiveRecord::PendingMigrationError => e
|
|||||||
exit 1
|
exit 1
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Capybara.javascript_driver = :poltergeist
|
||||||
|
|
||||||
RSpec.configure do |config|
|
RSpec.configure do |config|
|
||||||
config.fixture_path = "#{::Rails.root}/spec/fixtures"
|
config.fixture_path = "#{::Rails.root}/spec/fixtures"
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
require "webmock/rspec"
|
require "webmock/rspec"
|
||||||
WebMock.disable_net_connect!
|
WebMock.allow_net_connect!
|
||||||
|
|
||||||
RSpec.configure do |config|
|
RSpec.configure do |config|
|
||||||
config.expect_with :rspec do |expectations|
|
config.expect_with :rspec do |expectations|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user