Skip to content

Commit

Permalink
Init
Browse files Browse the repository at this point in the history
  • Loading branch information
Andy Leverenz committed Sep 15, 2019
1 parent 3a2fdd0 commit f5181a4
Show file tree
Hide file tree
Showing 26 changed files with 563 additions and 29 deletions.
64 changes: 64 additions & 0 deletions app/controllers/posts_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
class PostsController < ApplicationController
before_action :authenticate_user!, except: [:show, :index]
before_action :set_post, only: [:show, :edit, :update, :destroy]


def index
@posts = Post.all
end

def show
end

def new
@post = Post.new
end

def edit
end

def create
@post = Post.new(post_params)
@post.user_id = current_user.id

respond_to do |format|
if @post.save
format.html { redirect_to @post, notice: 'Post was successfully created.' }
format.json { render :show, status: :created, location: @post }
else
format.html { render :new }
format.json { render json: @post.errors, status: :unprocessable_entity }
end
end
end

def update
respond_to do |format|
if @post.update(post_params)
format.html { redirect_to @post, notice: 'Post was successfully updated.' }
format.json { render :show, status: :ok, location: @post }
else
format.html { render :edit }
format.json { render json: @post.errors, status: :unprocessable_entity }
end
end
end

def destroy
@post.destroy
respond_to do |format|
format.html { redirect_to posts_url, notice: 'Post was successfully destroyed.' }
format.json { head :no_content }
end
end

private

def set_post
@post = Post.find(params[:id])
end

def post_params
params.require(:post).permit(:title, :body, :user_id, :feature_image)
end
end
2 changes: 2 additions & 0 deletions app/helpers/posts_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
module PostsHelper
end
155 changes: 155 additions & 0 deletions app/javascript/controllers/dropzone_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
import Dropzone from "dropzone";
import { Controller } from "stimulus";
import { DirectUpload } from "@rails/activestorage";
import {
getMetaValue,
toArray,
findElement,
removeElement,
insertAfter
} from "helpers";

export default class extends Controller {
static targets = ["input"];

connect() {
this.dropZone = createDropZone(this);
this.hideFileInput();
this.bindEvents();
Dropzone.autoDiscover = false;
}

// Private
hideFileInput() {
this.inputTarget.disabled = true;
this.inputTarget.style.display = "none";
}

bindEvents() {
this.dropZone.on("addedfile", file => {
setTimeout(() => {
file.accepted && createDirectUploadController(this, file).start();
}, 500);
});

this.dropZone.on("removedfile", file => {
file.controller && removeElement(file.controller.hiddenInput);
});

this.dropZone.on("canceled", file => {
file.controller && file.controller.xhr.abort();
});
}

get headers() {
return { "X-CSRF-Token": getMetaValue("csrf-token") };
}

get url() {
return this.inputTarget.getAttribute("data-direct-upload-url");
}

get maxFiles() {
return this.data.get("maxFiles") || 1;
}

get maxFileSize() {
return this.data.get("maxFileSize") || 256;
}

get acceptedFiles() {
return this.data.get("acceptedFiles");
}

get addRemoveLinks() {
return this.data.get("addRemoveLinks") || true;
}
}

class DirectUploadController {
constructor(source, file) {
this.directUpload = createDirectUpload(file, source.url, this);
this.source = source;
this.file = file;
}

start() {
this.file.controller = this;
this.hiddenInput = this.createHiddenInput();
this.directUpload.create((error, attributes) => {
if (error) {
removeElement(this.hiddenInput);
this.emitDropzoneError(error);
} else {
this.hiddenInput.value = attributes.signed_id;
this.emitDropzoneSuccess();
}
});
}

createHiddenInput() {
const input = document.createElement("input");
input.type = "hidden";
input.name = this.source.inputTarget.name;
insertAfter(input, this.source.inputTarget);
return input;
}

directUploadWillStoreFileWithXHR(xhr) {
this.bindProgressEvent(xhr);
this.emitDropzoneUploading();
}

bindProgressEvent(xhr) {
this.xhr = xhr;
this.xhr.upload.addEventListener("progress", event =>
this.uploadRequestDidProgress(event)
);
}

uploadRequestDidProgress(event) {
const element = this.source.element;
const progress = (event.loaded / event.total) * 100;
findElement(
this.file.previewTemplate,
".dz-upload"
).style.width = `${progress}%`;
}

emitDropzoneUploading() {
this.file.status = Dropzone.UPLOADING;
this.source.dropZone.emit("processing", this.file);
}

emitDropzoneError(error) {
this.file.status = Dropzone.ERROR;
this.source.dropZone.emit("error", this.file, error);
this.source.dropZone.emit("complete", this.file);
}

emitDropzoneSuccess() {
this.file.status = Dropzone.SUCCESS;
this.source.dropZone.emit("success", this.file);
this.source.dropZone.emit("complete", this.file);
}
}

function createDirectUploadController(source, file) {
return new DirectUploadController(source, file);
}

function createDirectUpload(file, url, controller) {
return new DirectUpload(file, url, controller);
}

function createDropZone(controller) {
return new Dropzone(controller.element, {
url: controller.url,
headers: controller.headers,
maxFiles: controller.maxFiles,
maxFilesize: controller.maxFileSize,
acceptedFiles: controller.acceptedFiles,
addRemoveLinks: controller.addRemoveLinks,
autoQueue: false
});
}
18 changes: 0 additions & 18 deletions app/javascript/controllers/hello_controller.js

This file was deleted.

12 changes: 6 additions & 6 deletions app/javascript/controllers/index.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
// Load all the controllers within this directory and all subdirectories.
// Load all the controllers within this directory and all subdirectories.
// Controller files must be named *_controller.js.

import { Application } from "stimulus"
import { definitionsFromContext } from "stimulus/webpack-helpers"
import { Application } from "stimulus";
import { definitionsFromContext } from "stimulus/webpack-helpers";

const application = Application.start()
const context = require.context("controllers", true, /_controller\.js$/)
application.load(definitionsFromContext(context))
const application = Application.start();
const context = require.context("controllers", true, /_controller\.js$/);
application.load(definitionsFromContext(context));
34 changes: 34 additions & 0 deletions app/javascript/helpers/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
export function getMetaValue(name) {
const element = findElement(document.head, `meta[name="${name}"]`);
if (element) {
return element.getAttribute("content");
}
}

export function findElement(root, selector) {
if (typeof root == "string") {
selector = root;
root = document;
}
return root.querySelector(selector);
}

export function toArray(value) {
if (Array.isArray(value)) {
return value;
} else if (Array.from) {
return Array.from(value);
} else {
return [].slice.call(value);
}
}

export function removeElement(el) {
if (el && el.parentNode) {
el.parentNode.removeChild(el);
}
}

export function insertAfter(el, referenceNode) {
return referenceNode.parentNode.insertBefore(el, referenceNode.nextSibling);
}
18 changes: 16 additions & 2 deletions app/javascript/stylesheets/components/_forms.scss
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
/* Forms */
@import "dropzone/dist/min/dropzone.min.css";
@import "dropzone/dist/min/basic.min.css";

.input {
@apply appearance-none block w-full bg-gray-100 text-gray-700 border border-gray-300 rounded py-3 px-4 leading-tight;
}
Expand All @@ -14,9 +16,21 @@
.select {
@apply appearance-none py-3 px-4 pr-8 block w-full bg-gray-100 border border-gray-300 text-gray-700
rounded leading-tight;
-webkit-appearance: none;
-webkit-appearance: none;
}

.select:focus {
@apply outline-none bg-white border-gray-400;
}

.dropzone {
@apply border-2 rounded-lg border-gray-400 border-dashed;

&.dz-drag-hover {
@apply border-2 rounded-lg border-gray-200 border-dashed;

.dz-message {
opacity: 0.9;
}
}
}
4 changes: 4 additions & 0 deletions app/models/post.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
class Post < ApplicationRecord
belongs_to :user
has_one_attached :feature_image
end
38 changes: 38 additions & 0 deletions app/views/posts/_form.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<%= form_with(model: post, local: true, multipart: true) do |form| %>
<% if post.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(post.errors.count, "error") %> prohibited this post from being saved:</h2>

<ul>
<% post.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>

<div class="mb-6">
<%= form.label :title, class: "label" %>
<%= form.text_field :title, class: "input" %>
</div>

<div class="mb-6">
<%= form.label :body, class: "label" %>
<%= form.text_area :body, class: "input" %>
</div>

<div class="mb-6">
<%= form.label :feature_image, class: "label" %>
<div class="dropzone dropzone-default dz-clickable" data-controller="dropzone" data-dropzone-max-file-size="2" data-dropzone-max-files="1">
<%= form.file_field :feature_image, direct_upload: true, data: { target: 'dropzone.input' } %>
<div class="dropzone-msg dz-message needsclick text-gray-600">
<h3 class="dropzone-msg-title">Drag here to upload or click here to browse</h3>
<span class="dropzone-msg-desc text-sm">2 MB file size maximum. Allowed file types png, jpg.</span>
</div>
</div>
</div>

<div class="mb-6">
<%= form.submit class: "btn-default btn" %>
</div>
<% end %>
2 changes: 2 additions & 0 deletions app/views/posts/_post.json.jbuilder
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
json.extract! post, :id, :title, :body, :user_id, :created_at, :updated_at
json.url post_url(post, format: :json)
5 changes: 5 additions & 0 deletions app/views/posts/edit.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<div class="max-w-2xl m-auto">
<h1 class="text-3xl font-bold text-black mb-6">Edit Post</h1>

<%= render 'form', post: @post %>
</div>
Loading

0 comments on commit f5181a4

Please sign in to comment.