dynamic_text 0.0.6 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +55 -4
- data/app/assets/javascripts/dynamic_text/dynamic_text.js +2 -2
- data/app/assets/javascripts/dynamic_text/dynamic_text_preparer.js +58 -51
- data/lib/dynamic_text/version.rb +1 -1
- data/lib/dynamic_text.rb +1 -1
- data/spec/dummy/log/test.log +54 -0
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c5bf76fb6450fa76db95c4bc477593b344b3da892344b76d94390dace1dca5cf
|
4
|
+
data.tar.gz: bd631cb8b05cb8b33414939be1ad8d3f5008bc007f63de0d81a66c068d33ba11
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cb6c3bcbb282ee2b2740128b8da05453ed36456c3a7818d3a5370a571c9fb741555518d2d9e6df745ef24807c1b42fa80902c332243302ab9d568f7e9a706ff3
|
7
|
+
data.tar.gz: a6e60da0f931c54cf8038b8599603f4e242dc0c5e75d002b2377cffe2e114a62a302dd77170ff04590a284c3082657fd53c3599988f847aa4861df144c0c1b4c
|
data/README.md
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
#
|
2
|
-
|
1
|
+
# Welcome to Dynamic Text
|
2
|
+
Create a more seamless integration between displaying information and editing it! With Dynamic Text, you can allow users to easily update elements of a resource in your app just by clicking on the text and changing it, no separate edit page needed!
|
3
3
|
|
4
|
-
##
|
5
|
-
|
4
|
+
## Build Status
|
5
|
+
[![Build Status](https://travis-ci.org/JoshHadik/dynamic_text.svg?branch=master)](https://travis-ci.org/JoshHadik/dynamic_text)
|
6
6
|
|
7
7
|
## Installation
|
8
8
|
Add this line to your application's Gemfile:
|
@@ -21,5 +21,56 @@ Or install it yourself as:
|
|
21
21
|
$ gem install dynamic_text
|
22
22
|
```
|
23
23
|
|
24
|
+
## What does it do?
|
25
|
+
|
26
|
+
Dynamic Text allows you to do two main things:
|
27
|
+
|
28
|
+
### 1 - Render Editable Content Based on a Resource and Attribute
|
29
|
+
|
30
|
+
With the dynamic_text gem, you can easily create a hybrid HTML element that acts as both the display text for a specific attribute of a resource, and the text box for updating that attribute.
|
31
|
+
|
32
|
+
```html
|
33
|
+
<div>
|
34
|
+
<%= editable_text_for(@article, :title) %>
|
35
|
+
</div>
|
36
|
+
```
|
37
|
+
|
38
|
+
### 2 - Render Dynamic Content that Updates In Real Time with Editable Content
|
39
|
+
|
40
|
+
You might not want all of the text for a specific attribute of a specific resource to be editable. For example, you might want to display the title for a blog post in both an 'h1' tag above the body of the post, as well as the navigation bar on the top of the screen.
|
41
|
+
|
42
|
+
|
43
|
+
In this case, you might want the text to be editable when pressed on in the main article section of the page, but not in the header. However, you probably still want the text in the header to change in real time if a user edits the title from within the article section.
|
44
|
+
|
45
|
+
You can use the following method to identify content that isn't editable but updates in real time when changes are made to the attribute of the resource somewhere else on the page.
|
46
|
+
|
47
|
+
```html
|
48
|
+
<div>
|
49
|
+
<%= dynamic_text_for(@article, :title) %>
|
50
|
+
</div>
|
51
|
+
```
|
52
|
+
|
53
|
+
### Why Does It Do It?
|
54
|
+
|
55
|
+
Long ago, in the Wild West of software, the key ingredient for a successful app was functionality. Every idea was unique back then, and the potential of apps and websites was virtually untapped.
|
56
|
+
|
57
|
+
Nowadays, almost everything has been done. In order to gain an edge on competitors, one of the best thing you can do is to look for ways to provide a better user experience.
|
58
|
+
|
59
|
+
I believe the days of pure CRUD apps in consumer facing applications are numbered, users no longer want to navigate through completely separate pages for specific actions on specific resources. Users want pages that provide information and actions for many different resources at once in an intuitive and easy-to-navigate manner (think 'dashboard' pages).
|
60
|
+
|
61
|
+
This gem is built as a way to merge the 'edit' page and the 'show' page for a given resource, so users can update content in real time just by clicking on the text that displays that information.
|
62
|
+
|
63
|
+
For example, you could use this gem to merge the display text and edit field for the title of a blog post, so the H1 tag on the show page merges with the <input type='text'> tag in the edit form, removing the necessity for a separate edit page to update that information.
|
64
|
+
|
65
|
+
|
66
|
+
### How Can You Use It?
|
67
|
+
|
68
|
+
1. Dynamic Text
|
69
|
+
2. Editable Text
|
70
|
+
|
71
|
+
### Configuration
|
72
|
+
|
73
|
+
1. AJAX
|
74
|
+
|
24
75
|
## License
|
25
76
|
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
@@ -90,8 +90,8 @@ const DynamicText = {
|
|
90
90
|
},
|
91
91
|
|
92
92
|
// Update a specific attribute of a resource.
|
93
|
-
patchResource(
|
94
|
-
const editableText =
|
93
|
+
patchResource(target) {
|
94
|
+
const editableText = target;
|
95
95
|
const editableTextContainer = editableText.parentNode;
|
96
96
|
const action = editableTextContainer.querySelector("[name='_action']");
|
97
97
|
|
@@ -1,62 +1,69 @@
|
|
1
|
+
const delegateToEditableText = (eventType, callback) => {
|
2
|
+
document.addEventListener(eventType, (event) => {
|
3
|
+
if (event.target.classList.contains('editable-text')) {
|
4
|
+
callback(event);
|
5
|
+
}
|
6
|
+
});
|
7
|
+
}
|
8
|
+
|
1
9
|
const prepareDynamicText = () => {
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
});
|
10
|
+
// Exit editable text editor mode (focus) on enter instead of adding a new line.
|
11
|
+
delegateToEditableText('keydown', (event) => {
|
12
|
+
if (event.keyCode === 13) {
|
13
|
+
event.preventDefault();
|
14
|
+
event.target.blur();
|
15
|
+
}
|
16
|
+
});
|
10
17
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
18
|
+
// Properly paste text into editable text
|
19
|
+
delegateToEditableText('paste', (event) => {
|
20
|
+
event.preventDefault();
|
21
|
+
DynamicText.handleContentEditablePaste(event)
|
22
|
+
});
|
16
23
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
});
|
24
|
+
// Disable dragging and dropping text/images into editable text.
|
25
|
+
["dragover", "drop"].forEach((evt) => {
|
26
|
+
delegateToEditableText(evt, (event) => {
|
27
|
+
event.preventDefault();
|
28
|
+
return false;
|
23
29
|
});
|
30
|
+
});
|
24
31
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
32
|
+
// Store original value when focusing in on specific editable text (used to determine if text was changed and patch request should be sent on focusout.)
|
33
|
+
delegateToEditableText('focus', (event) => {
|
34
|
+
const target = event.target;
|
35
|
+
target.setAttribute('data-original-value', target.innerText);
|
36
|
+
});
|
30
37
|
|
31
|
-
|
32
|
-
|
33
|
-
|
38
|
+
// Send patch request for resource if content was changed.
|
39
|
+
delegateToEditableText('focusout', (event) => {
|
40
|
+
const target = event.target;
|
34
41
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
42
|
+
// Empty all content of text if editable text is empty (otherwise certain browsers fill in a default <br> or <p> value.)
|
43
|
+
if (!target.innerText.trim().length) {
|
44
|
+
target.innerText = null;
|
45
|
+
}
|
39
46
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
47
|
+
// TODO: Change patchResource to accept the target
|
48
|
+
// Send patch request if text was changed.
|
49
|
+
if (target.getAttribute('data-original-value') != target.innerText) {
|
50
|
+
DynamicText.patchResource(target);
|
51
|
+
}
|
44
52
|
|
45
|
-
|
46
|
-
|
53
|
+
target.removeAttribute('data-original-value')
|
54
|
+
});
|
47
55
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
})
|
56
|
+
// Update all other divs tagged with the same dynamic-tag as the current text being edited. (So if you have two elements on one page that display the same property of a resource, both will be updated in real time when you edit the text of one.)
|
57
|
+
delegateToEditableText('input', (event) => {
|
58
|
+
const target = event.target;
|
59
|
+
const newValue = target.innerText;
|
60
|
+
const dynamicTag = target.getAttribute('data-dynamic-tag');
|
61
|
+
|
62
|
+
document.querySelectorAll(`[data-dynamic-tag='${dynamicTag}']`)
|
63
|
+
.forEach((dynamicTextElement) => {
|
64
|
+
if(dynamicTextElement !== target) {
|
65
|
+
dynamicTextElement.innerText = newValue;
|
66
|
+
}
|
67
|
+
});
|
68
|
+
});
|
62
69
|
}
|
data/lib/dynamic_text/version.rb
CHANGED
data/lib/dynamic_text.rb
CHANGED
@@ -2,8 +2,8 @@ require 'dynamic_text/engine'
|
|
2
2
|
require 'dynamic_text/view_renderer'
|
3
3
|
require 'dynamic_text/locals_setter'
|
4
4
|
require 'configuron'
|
5
|
+
require_relative 'dynamic_text/configuration'
|
5
6
|
|
6
7
|
module DynamicText
|
7
8
|
extend Configuron::Configurable
|
8
|
-
require_relative 'dynamic_text/configuration'
|
9
9
|
end
|
data/spec/dummy/log/test.log
CHANGED
@@ -1644,3 +1644,57 @@ DynamicText::Test: test_truth
|
|
1644
1644
|
[1m[35m (0.1ms)[0m [1m[31mROLLBACK[0m
|
1645
1645
|
[1m[35m (0.1ms)[0m [1m[35mBEGIN[0m
|
1646
1646
|
[1m[35m (0.1ms)[0m [1m[31mROLLBACK[0m
|
1647
|
+
[1m[35m (0.8ms)[0m [1m[34mSELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC[0m
|
1648
|
+
[1m[35m (0.7ms)[0m [1m[34mSELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC[0m
|
1649
|
+
[1m[35m (0.3ms)[0m [1m[34mSELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC[0m
|
1650
|
+
[1m[35m (203.0ms)[0m [1m[35mDROP DATABASE IF EXISTS "dynamic_text_test"[0m
|
1651
|
+
[1m[35m (483.1ms)[0m [1m[35mCREATE DATABASE "dynamic_text_test" ENCODING = 'unicode'[0m
|
1652
|
+
[1m[35mSQL (0.4ms)[0m [1m[35mCREATE EXTENSION IF NOT EXISTS "plpgsql"[0m
|
1653
|
+
[1m[35m (7.0ms)[0m [1m[35mCREATE TABLE "schema_migrations" ("version" character varying NOT NULL PRIMARY KEY)[0m
|
1654
|
+
[1m[35m (0.8ms)[0m [1m[34mSELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC[0m
|
1655
|
+
[1m[35m (0.8ms)[0m [1m[32mINSERT INTO "schema_migrations" (version) VALUES (0)[0m
|
1656
|
+
[1m[35m (47.0ms)[0m [1m[35mCREATE TABLE "ar_internal_metadata" ("key" character varying NOT NULL PRIMARY KEY, "value" character varying, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL)[0m
|
1657
|
+
[1m[36mActiveRecord::InternalMetadata Load (0.5ms)[0m [1m[34mSELECT "ar_internal_metadata".* FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = $1 LIMIT $2[0m [["key", "environment"], ["LIMIT", 1]]
|
1658
|
+
[1m[35m (0.1ms)[0m [1m[35mBEGIN[0m
|
1659
|
+
[1m[36mActiveRecord::InternalMetadata Create (0.4ms)[0m [1m[32mINSERT INTO "ar_internal_metadata" ("key", "value", "created_at", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "key"[0m [["key", "environment"], ["value", "test"], ["created_at", "2019-01-25 03:53:35.094422"], ["updated_at", "2019-01-25 03:53:35.094422"]]
|
1660
|
+
[1m[35m (20.8ms)[0m [1m[35mCOMMIT[0m
|
1661
|
+
[1m[36mActiveRecord::InternalMetadata Load (0.4ms)[0m [1m[34mSELECT "ar_internal_metadata".* FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = $1 LIMIT $2[0m [["key", "environment"], ["LIMIT", 1]]
|
1662
|
+
[1m[35m (0.3ms)[0m [1m[35mBEGIN[0m
|
1663
|
+
[1m[35m (0.2ms)[0m [1m[35mCOMMIT[0m
|
1664
|
+
[1m[35m (0.9ms)[0m [1m[34mSELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC[0m
|
1665
|
+
[1m[35m (0.2ms)[0m [1m[35mBEGIN[0m
|
1666
|
+
[1m[35m (0.2ms)[0m [1m[31mROLLBACK[0m
|
1667
|
+
[1m[35m (0.2ms)[0m [1m[35mBEGIN[0m
|
1668
|
+
[1m[35m (0.2ms)[0m [1m[31mROLLBACK[0m
|
1669
|
+
[1m[35m (0.1ms)[0m [1m[35mBEGIN[0m
|
1670
|
+
[1m[35m (0.1ms)[0m [1m[31mROLLBACK[0m
|
1671
|
+
[1m[35m (0.1ms)[0m [1m[35mBEGIN[0m
|
1672
|
+
[1m[35m (0.1ms)[0m [1m[31mROLLBACK[0m
|
1673
|
+
[1m[35m (0.1ms)[0m [1m[35mBEGIN[0m
|
1674
|
+
[1m[35m (0.1ms)[0m [1m[31mROLLBACK[0m
|
1675
|
+
[1m[35m (0.1ms)[0m [1m[35mBEGIN[0m
|
1676
|
+
[1m[35m (0.1ms)[0m [1m[31mROLLBACK[0m
|
1677
|
+
[1m[35m (0.1ms)[0m [1m[35mBEGIN[0m
|
1678
|
+
[1m[35m (0.1ms)[0m [1m[31mROLLBACK[0m
|
1679
|
+
[1m[35m (0.1ms)[0m [1m[35mBEGIN[0m
|
1680
|
+
[1m[35m (0.1ms)[0m [1m[31mROLLBACK[0m
|
1681
|
+
[1m[35m (0.1ms)[0m [1m[35mBEGIN[0m
|
1682
|
+
[1m[35m (0.1ms)[0m [1m[31mROLLBACK[0m
|
1683
|
+
[1m[35m (0.1ms)[0m [1m[35mBEGIN[0m
|
1684
|
+
[1m[35m (0.1ms)[0m [1m[31mROLLBACK[0m
|
1685
|
+
[1m[35m (0.1ms)[0m [1m[35mBEGIN[0m
|
1686
|
+
[1m[35m (0.1ms)[0m [1m[31mROLLBACK[0m
|
1687
|
+
[1m[35m (0.1ms)[0m [1m[35mBEGIN[0m
|
1688
|
+
[1m[35m (0.1ms)[0m [1m[31mROLLBACK[0m
|
1689
|
+
[1m[35m (0.1ms)[0m [1m[35mBEGIN[0m
|
1690
|
+
[1m[35m (0.1ms)[0m [1m[31mROLLBACK[0m
|
1691
|
+
[1m[35m (0.1ms)[0m [1m[35mBEGIN[0m
|
1692
|
+
[1m[35m (0.1ms)[0m [1m[31mROLLBACK[0m
|
1693
|
+
[1m[35m (0.1ms)[0m [1m[35mBEGIN[0m
|
1694
|
+
[1m[35m (0.2ms)[0m [1m[31mROLLBACK[0m
|
1695
|
+
[1m[35m (0.1ms)[0m [1m[35mBEGIN[0m
|
1696
|
+
[1m[35m (0.1ms)[0m [1m[31mROLLBACK[0m
|
1697
|
+
[1m[35m (0.1ms)[0m [1m[35mBEGIN[0m
|
1698
|
+
[1m[35m (0.1ms)[0m [1m[31mROLLBACK[0m
|
1699
|
+
[1m[35m (0.1ms)[0m [1m[35mBEGIN[0m
|
1700
|
+
[1m[35m (0.1ms)[0m [1m[31mROLLBACK[0m
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dynamic_text
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Josh Hadik
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-02-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -196,7 +196,7 @@ files:
|
|
196
196
|
- spec/lib/view_renderer.rb
|
197
197
|
- spec/rails_helper.rb
|
198
198
|
- spec/spec_helper.rb
|
199
|
-
homepage:
|
199
|
+
homepage: https://github.com/JoshHadik/dynamic_text
|
200
200
|
licenses:
|
201
201
|
- MIT
|
202
202
|
metadata:
|