MinsoftK

setting react ui

Showing 360 changed files with 214 additions and 4560 deletions
1 -{
2 - "presets": ["es2015"],
3 - "plugins": [
4 - ["transform-es2015-destructuring", { "loose": true }],
5 - ["transform-es2015-for-of", { "loose": true }],
6 - ["transform-es2015-spread", { "loose": true }]
7 - ]
8 -}
1 -[*]
2 -charset = utf-8
3 -indent_style = space
4 -indent_size = 4
5 -end_of_line = lf
...\ No newline at end of file ...\ No newline at end of file
1 -# Ignore polyfill
2 -src/js/polyfill.js
1 module.exports = { 1 module.exports = {
2 - extends: ['tui/es6', 'plugin:prettier/recommended'], 2 + parser: 'babel-eslint',
3 - plugins: ['prettier'],
4 - env: {
5 - browser: true,
6 - amd: true,
7 - node: true,
8 - jasmine: true,
9 - jquery: true,
10 - es6: true,
11 - },
12 - globals: {
13 - fabric: true,
14 - tui: true,
15 - loadFixtures: true,
16 - },
17 parserOptions: { 3 parserOptions: {
4 + ecmaVersion: 7,
18 sourceType: 'module', 5 sourceType: 'module',
6 + ecmaFeatures: {
7 + jsx: true
8 + }
19 }, 9 },
10 + extends: ['tui/es6', 'plugin:react/recommended', 'plugin:prettier/recommended'],
11 + plugins: ['react', 'prettier'],
20 rules: { 12 rules: {
21 - 'prefer-destructuring': [ 13 + 'react/prop-types': 0
22 - 'error',
23 - {
24 - VariableDeclarator: { array: true, object: true },
25 - AssignmentExpression: { array: false, object: false },
26 - },
27 - ],
28 - 'prettier/prettier': 'error',
29 }, 14 },
30 -}; 15 + settings: {
16 + react: {
17 + version: 'detect'
18 + }
19 + }
20 +};
...\ No newline at end of file ...\ No newline at end of file
......
1 -# Logs
2 -logs
3 -*.log
4 -
5 -# Runtime data
6 -pids
7 -*.pid
8 -*.seed
9 -
10 -# Directory for instrumented libs generated by jscoverage/JSCover
11 -lib-cov
12 -
13 -# Coverage directory used by tools like istanbul
14 -coverage
15 -
16 -# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
17 -.grunt
18 -
19 -# Compiled binary addons (http://nodejs.org/api/addons.html)
20 -build/Release
21 -
22 -# Dependency directory
23 -# Deployed apps should consider commenting this line out:
24 -# see https://npmjs.org/doc/faq.html#Should-I-check-my-node_modules-folder-into-git
25 node_modules 1 node_modules
26 - 2 +.DS_Store
27 -# Bower Components
28 -bower_components
29 -lib
30 -
31 -# IDEA
32 -.idea
33 -*.iml
34 -
35 -# Window
36 Thumbs.db 3 Thumbs.db
37 Desktop.ini 4 Desktop.ini
38 -
39 -# MAC
40 -.DS_Store
41 -
42 -# SVN
43 -.svn
44 -
45 -# eclipse
46 -.project
47 -.metadata
48 -
49 -# etc
50 -temp
51 -doc
52 -demo
53 -report
54 -*.vim
55 -test.html
56 -
57 -# Compiled files
58 dist 5 dist
6 +.idea
7 +storybook-static
...\ No newline at end of file ...\ No newline at end of file
......
1 { 1 {
2 - "singleQuote": true,
3 "printWidth": 100, 2 "printWidth": 100,
4 - "tabWidth": 2, 3 + "singleQuote": true,
5 - "useTabs": false, 4 + "bracketSpacing": false,
6 - "semi": true, 5 + "arrowParens": "always"
7 - "quoteProps": "as-needed", 6 +}
8 - "trailingComma": "es5",
9 - "arrowParens": "always",
10 - "endOfLine": "lf",
11 - "bracketSpacing": true,
12 - "proseWrap": "preserve"
13 -}
...\ No newline at end of file ...\ No newline at end of file
......
1 +import {configure} from '@storybook/react';
2 +
3 +// automatically import all files ending in *.stories.js
4 +const req = require.context('../stories', true, /.stories.js$/);
5 +
6 +function loadStories() {
7 + req.keys().forEach(filename => req(filename));
8 +}
9 +
10 +configure(loadStories, module);
1 +module.exports = {
2 + plugins: [],
3 + module: {
4 + rules: [
5 + {
6 + test: /\.css$/,
7 + loaders: ['style-loader', 'css-loader']
8 + }
9 + ]
10 + }
11 +};
...@@ -14,21 +14,21 @@ religion, or sexual identity and orientation. ...@@ -14,21 +14,21 @@ religion, or sexual identity and orientation.
14 Examples of behavior that contributes to creating a positive environment 14 Examples of behavior that contributes to creating a positive environment
15 include: 15 include:
16 16
17 -- Using welcoming and inclusive language 17 +* Using welcoming and inclusive language
18 -- Being respectful of differing viewpoints and experiences 18 +* Being respectful of differing viewpoints and experiences
19 -- Gracefully accepting constructive criticism 19 +* Gracefully accepting constructive criticism
20 -- Focusing on what is best for the community 20 +* Focusing on what is best for the community
21 -- Showing empathy towards other community members 21 +* Showing empathy towards other community members
22 22
23 Examples of unacceptable behavior by participants include: 23 Examples of unacceptable behavior by participants include:
24 24
25 -- The use of sexualized language or imagery and unwelcome sexual attention or 25 +* The use of sexualized language or imagery and unwelcome sexual attention or
26 advances 26 advances
27 -- Trolling, insulting/derogatory comments, and personal or political attacks 27 +* Trolling, insulting/derogatory comments, and personal or political attacks
28 -- Public or private harassment 28 +* Public or private harassment
29 -- Publishing others' private information, such as a physical or electronic 29 +* Publishing others' private information, such as a physical or electronic
30 address, without explicit permission 30 address, without explicit permission
31 -- Other conduct which could reasonably be considered inappropriate in a 31 +* Other conduct which could reasonably be considered inappropriate in a
32 professional setting 32 professional setting
33 33
34 ## Our Responsibilities 34 ## Our Responsibilities
...@@ -70,4 +70,4 @@ members of the project's leadership. ...@@ -70,4 +70,4 @@ members of the project's leadership.
70 This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 70 This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71 available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 71 available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
72 72
73 -[homepage]: https://www.contributor-covenant.org 73 +[homepage]: https://www.contributor-covenant.org
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -5,103 +5,87 @@ First off, thanks for taking the time to contribute! 🎉 😘 ✨ ...@@ -5,103 +5,87 @@ First off, thanks for taking the time to contribute! 🎉 😘 ✨
5 The following is a set of guidelines for contributing to TOAST UI. These are mostly guidelines, not rules. Use your best judgment, and feel free to propose changes to this document in a pull request. 5 The following is a set of guidelines for contributing to TOAST UI. These are mostly guidelines, not rules. Use your best judgment, and feel free to propose changes to this document in a pull request.
6 6
7 ## Reporting Bugs 7 ## Reporting Bugs
8 -
9 Bugs are tracked as GitHub issues. Search the list and try reproduce on [demo][demo] before you create an issue. When you create an issue, please provide the following information by filling in the template. 8 Bugs are tracked as GitHub issues. Search the list and try reproduce on [demo][demo] before you create an issue. When you create an issue, please provide the following information by filling in the template.
10 9
11 Explain the problem and include additional details to help maintainers reproduce the problem: 10 Explain the problem and include additional details to help maintainers reproduce the problem:
12 11
13 -- **Use a clear and descriptive title** for the issue to identify the problem. 12 +* **Use a clear and descriptive title** for the issue to identify the problem.
14 -- **Describe the exact steps which reproduce the problem** in as many details as possible. Don't just say what you did, but explain how you did it. For example, if you moved the cursor to the end of a line, explain if you used a mouse or a keyboard. 13 +* **Describe the exact steps which reproduce the problem** in as many details as possible. Don't just say what you did, but explain how you did it. For example, if you moved the cursor to the end of a line, explain if you used a mouse or a keyboard.
15 -- **Provide specific examples to demonstrate the steps.** Include links to files or GitHub projects, or copy/pasteable snippets, which you use in those examples. If you're providing snippets on the issue, use Markdown code blocks. 14 +* **Provide specific examples to demonstrate the steps.** Include links to files or GitHub projects, or copy/pasteable snippets, which you use in those examples. If you're providing snippets on the issue, use Markdown code blocks.
16 -- **Describe the behavior you observed after following the steps** and point out what exactly is the problem with that behavior. 15 +* **Describe the behavior you observed after following the steps** and point out what exactly is the problem with that behavior.
17 -- **Explain which behavior you expected to see instead and why.** 16 +* **Explain which behavior you expected to see instead and why.**
18 -- **Include screenshots and animated GIFs** which show you following the described steps and clearly demonstrate the problem. 17 +* **Include screenshots and animated GIFs** which show you following the described steps and clearly demonstrate the problem.
19 18
20 ## Suggesting Enhancements 19 ## Suggesting Enhancements
21 -
22 In case you want to suggest for TOAST UI ImageEditor, please follow this guideline to help maintainers and the community understand your suggestion. 20 In case you want to suggest for TOAST UI ImageEditor, please follow this guideline to help maintainers and the community understand your suggestion.
23 -Before creating suggestions, please check [issue list](../../labels/enhancement) if there's already a request. 21 +Before creating suggestions, please check [issue list](../../labels/feature%20request) if there's already a request.
24 22
25 Create an issue and provide the following information: 23 Create an issue and provide the following information:
26 24
27 -- **Use a clear and descriptive title** for the issue to identify the suggestion. 25 +* **Use a clear and descriptive title** for the issue to identify the suggestion.
28 -- **Provide a step-by-step description of the suggested enhancement** in as many details as possible. 26 +* **Provide a step-by-step description of the suggested enhancement** in as many details as possible.
29 -- **Provide specific examples to demonstrate the steps.** Include copy/pasteable snippets which you use in those examples, as Markdown code blocks. 27 +* **Provide specific examples to demonstrate the steps.** Include copy/pasteable snippets which you use in those examples, as Markdown code blocks.
30 -- **Include screenshots and animated GIFs** which helps demonstrate the steps or point out the part of TOAST UI ImageEditor which the suggestion is related to. 28 +* **Include screenshots and animated GIFs** which helps demonstrate the steps or point out the part of TOAST UI ImageEditor which the suggestion is related to.
31 -- **Explain why this enhancement would be useful** to most TOAST UI users. 29 +* **Explain why this enhancement would be useful** to most TOAST UI users.
32 -- **List some other image editors or applications where this enhancement exists.** 30 +* **List some other image editors or applications where this enhancement exists.**
33 31
34 ## First Code Contribution 32 ## First Code Contribution
35 33
36 Unsure where to begin contributing to TOAST UI? You can start by looking through these `document`, `good first issue` and `help wanted` issues: 34 Unsure where to begin contributing to TOAST UI? You can start by looking through these `document`, `good first issue` and `help wanted` issues:
37 35
38 -- **document issues**: issues which should be reviewed or improved. 36 +* **document issues**: issues which should be reviewed or improved.
39 -- **good first issues**: issues which should only require a few lines of code, and a test or two. 37 +* **good first issues**: issues which should only require a few lines of code, and a test or two.
40 -- **help wanted issues**: issues which should be a bit more involved than beginner issues. 38 +* **help wanted issues**: issues which should be a bit more involved than beginner issues.
41 39
42 ## Pull Requests 40 ## Pull Requests
43 41
44 ### Development WorkFlow 42 ### Development WorkFlow
45 -
46 - Set up your development environment 43 - Set up your development environment
47 - Make change from a right branch 44 - Make change from a right branch
48 - Be sure the code passes `npm run lint`, `npm run test` 45 - Be sure the code passes `npm run lint`, `npm run test`
49 - Make a pull request 46 - Make a pull request
50 47
51 ### Development environment 48 ### Development environment
52 -
53 - Prepare your machine node and it's packages installed. 49 - Prepare your machine node and it's packages installed.
54 - Checkout our repository 50 - Checkout our repository
55 - Install dependencies by `npm install && bower install` 51 - Install dependencies by `npm install && bower install`
56 - Start webpack-dev-server by `npm run serve` 52 - Start webpack-dev-server by `npm run serve`
57 53
58 ### Make changes 54 ### Make changes
59 -
60 #### Checkout a branch 55 #### Checkout a branch
61 -
62 - **develop**: PR base branch. merge features, updates for next minor or major release 56 - **develop**: PR base branch. merge features, updates for next minor or major release
63 - **master**: bug fix or document update for next patch release. develop branch will rebase every time master branch update. so keep code change to a minimum. 57 - **master**: bug fix or document update for next patch release. develop branch will rebase every time master branch update. so keep code change to a minimum.
64 - **production**: lastest release branch with distribution files. never make a PR on this 58 - **production**: lastest release branch with distribution files. never make a PR on this
65 - **gh-pages**: API docs, examples and demo 59 - **gh-pages**: API docs, examples and demo
66 60
67 #### Check Code Style 61 #### Check Code Style
68 -
69 Run `npm run eslint` and make sure all the tests pass. 62 Run `npm run eslint` and make sure all the tests pass.
70 63
71 #### Test 64 #### Test
72 -
73 Run `npm run test` and verify all the tests pass. 65 Run `npm run test` and verify all the tests pass.
74 If you are adding new commands or features, they must include tests. 66 If you are adding new commands or features, they must include tests.
75 If you are changing functionality, update the tests if you need to. 67 If you are changing functionality, update the tests if you need to.
76 68
77 #### Commit 69 #### Commit
78 -
79 Follow our [commit message conventions](./docs/COMMIT_MESSAGE_CONVENTION.md). 70 Follow our [commit message conventions](./docs/COMMIT_MESSAGE_CONVENTION.md).
80 71
81 ### Yes! Pull request 72 ### Yes! Pull request
82 -
83 Make your pull request, then describe your changes. 73 Make your pull request, then describe your changes.
84 -
85 #### Title 74 #### Title
86 -
87 Follow other PR title format on below. 75 Follow other PR title format on below.
88 -
89 ``` 76 ```
90 <Type>: Short Description (fix #111) 77 <Type>: Short Description (fix #111)
91 <Type>: Short Description (fix #123, #111, #122) 78 <Type>: Short Description (fix #123, #111, #122)
92 <Type>: Short Description (ref #111) 79 <Type>: Short Description (ref #111)
93 ``` 80 ```
94 - 81 +* capitalize first letter of Type
95 -- capitalize first letter of Type 82 +* use present tense: 'change' not 'changed' or 'changes'
96 -- use present tense: 'change' not 'changed' or 'changes'
97 83
98 #### Description 84 #### Description
99 -
100 If it has related to issues, add links to the issues(like `#123`) in the description. 85 If it has related to issues, add links to the issues(like `#123`) in the description.
101 Fill in the [Pull Request Template](./docs/PULL_REQUEST_TEMPLATE.md) by check your case. 86 Fill in the [Pull Request Template](./docs/PULL_REQUEST_TEMPLATE.md) by check your case.
102 87
103 ## Code of Conduct 88 ## Code of Conduct
104 -
105 This project and everyone participating in it is governed by the [Code of Conduct](CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. Please report unacceptable behavior to dl_javascript@nhn.com. 89 This project and everyone participating in it is governed by the [Code of Conduct](CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. Please report unacceptable behavior to dl_javascript@nhn.com.
106 90
107 > This Guide is base on [atom contributing guide](https://github.com/atom/atom/blob/master/CONTRIBUTING.md), [CocoaPods](http://guides.cocoapods.org/contributing/contribute-to-cocoapods.html) and [ESLint](http://eslint.org/docs/developer-guide/contributing/pull-requests) 91 > This Guide is base on [atom contributing guide](https://github.com/atom/atom/blob/master/CONTRIBUTING.md), [CocoaPods](http://guides.cocoapods.org/contributing/contribute-to-cocoapods.html) and [ESLint](http://eslint.org/docs/developer-guide/contributing/pull-requests)
......
1 -<!--
2 -Thank you for your contribution.
3 -
4 -When it comes to write an issue, please, use the template below.
5 -To use the template is mandatory for submit new issue and we won't reply the issue that without the template.
6 -
7 -And you can write template's contents in Korean also.
8 --->
9 -
10 -<!-- TEMPLATE -->
11 -
12 -## Version
13 -
14 -<!-- Write the version of the grid you are currently using. -->
15 -
16 -## Development Environment
17 -
18 -<!-- Write the browser type, OS and so on -->
19 -
20 -## Current Behavior
21 -
22 -<!-- Write a description of the current operation. You can add example code, 'CodePen' or 'jsfiddle' links. -->
23 -
24 -```js
25 -// Write example code
26 -```
27 -
28 -## Expected Behavior
29 -
30 -<!-- Write a description of the future action. -->
1 - 1 +MIT License
2 -The MIT License
3 2
4 Copyright (c) 2019 NHN Corp. 3 Copyright (c) 2019 NHN Corp.
5 4
...@@ -19,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ...@@ -19,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 -THE SOFTWARE. 21 +THE SOFTWARE.
...\ No newline at end of file ...\ No newline at end of file
......
This diff is collapsed. Click to expand it.
1 +module.exports = (api) => {
2 + api.cache(true);
3 +
4 + return {
5 + presets: [
6 + [
7 + '@babel/preset-env',
8 + {
9 + modules: false,
10 + useBuiltIns: 'entry'
11 + }
12 + ],
13 + '@babel/preset-react'
14 + ],
15 + plugins: [
16 + '@babel/plugin-proposal-class-properties',
17 + '@babel/plugin-proposal-object-rest-spread'
18 + ]
19 + };
20 +};
...\ No newline at end of file ...\ No newline at end of file
1 -{
2 - "name": "tui-image-editor",
3 - "authors": ["NHN FE Dev Lab <dl_javascript@nhn.com>"],
4 - "license": "MIT",
5 - "main": ["dist/tui-image-editor.js"],
6 - "ignore": [
7 - "**/.*",
8 - "node_modules",
9 - "bower_components",
10 - "test",
11 - "tests",
12 - "src",
13 - "server",
14 - "data.js",
15 - "Gruntfile.js",
16 - "gulpfile.js",
17 - "karma.*.js",
18 - "conf.json",
19 - "package.json",
20 - ".gitignore",
21 - "samples",
22 - "index.js",
23 - "jsdoc.conf.json",
24 - "webpack.*.js"
25 - ],
26 - "dependencies": {
27 - "fabric": "4.2.0",
28 - "tui-code-snippet": "^1.5.0",
29 - "tui-color-picker": "^2.2.0"
30 - },
31 - "devDependencies": {
32 - "tui-component-colorpicker": "~1.0.1",
33 - "filesaver": "*"
34 - },
35 - "resolutions": {
36 - "tui-code-snippet": "^1.5.0",
37 - "tui-color-picker": "^2.2.0"
38 - }
39 -}
1 -const fs = require('fs');
2 -const path = require('path');
3 -const config = require(path.resolve(process.cwd(), 'tuidoc.config.json'));
4 -const examples = config.examples || {};
5 -const { filePath, globalErrorLogVariable } = examples;
6 -
7 -/**
8 - * Get Examples Url
9 - */
10 -function getTestUrls() {
11 - if (!filePath) {
12 - throw Error('not exist examples path at tuidoc.config.json');
13 - }
14 -
15 - const urlPrefix = 'http://nhn.github.io/tui.image-editor/latest';
16 -
17 - const testUrls = fs.readdirSync(filePath).reduce((urls, fileName) => {
18 - if (/html$/.test(fileName)) {
19 - urls.push(`${urlPrefix}/${filePath}/${fileName}`);
20 - }
21 -
22 - return urls;
23 - }, []);
24 -
25 - fs.writeFileSync('url.txt', testUrls.join(', '));
26 -}
27 -
28 -function getGlobalVariable() {
29 - if (!globalErrorLogVariable) {
30 - throw Error('not exist examples path at tuidoc.config.json');
31 - }
32 -
33 - fs.writeFileSync('errorVariable.txt', globalErrorLogVariable);
34 -}
35 -
36 -getTestUrls();
37 -getGlobalVariable();
1 +[1214/032025.223:ERROR:directory_reader_win.cc(43)] FindFirstFile: 지정된 경로를 찾을 수 없습니다. (0x3)
1 -.border {
2 - border: 1px solid black;
3 -}
4 -.body-container {
5 - width: 1000px;
6 -}
7 -.tui-image-editor-controls {
8 - min-height: 250px;
9 -}
10 -.menu {
11 - padding: 0;
12 - margin-bottom: 5px;
13 - text-align: center;
14 - color: #544b61;
15 - font-weight: 400;
16 - list-style-type: none;
17 - user-select: none;
18 - -moz-user-select: none;
19 - -ms-user-select: none;
20 - -webkit-user-select: none;
21 -}
22 -.logo {
23 - margin: 0 auto;
24 - width: 300px;
25 - vertical-align: middle;
26 -}
27 -.header .name {
28 - padding: 10px;
29 - line-height: 50px;
30 - font-size: 30px;
31 - font-weight: 100;
32 - vertical-align: middle;
33 -}
34 -.header .menu {
35 - display: inline-block;
36 -}
37 -.menu-item {
38 - padding: 10px;
39 - display: inline-block;
40 - cursor: pointer;
41 - vertical-align: middle;
42 -}
43 -.menu-item a {
44 - text-decoration: none;
45 -}
46 -.menu-item.no-pointer {
47 - cursor: default;
48 -}
49 -.menu-item.active,
50 -.menu-item:hover {
51 - background-color: #f3f3f3;
52 -}
53 -.menu-item.disabled {
54 - cursor: default;
55 - color: #bfbebe;
56 -}
57 -.align-left-top {
58 - text-align: left;
59 - vertical-align: top;
60 -}
61 -.range-narrow {
62 - width: 80px;
63 -}
64 -.sub-menu-container {
65 - font-size: 14px;
66 - margin-bottom: 1em;
67 - display: none;
68 -}
69 -.tui-image-editor {
70 - height: 500px;
71 -}
72 -.tui-image-editor-canvas-container {
73 - margin: 0 auto;
74 - top: 50%;
75 - transform: translateY(-50%);
76 - -ms-transform: translateY(-50%);
77 - -moz-transform: translateY(-50%);
78 - -webkit-transform: translateY(-50%);
79 - border: 1px dashed black;
80 - overflow: hidden;
81 -}
82 -.tui-colorpicker-container {
83 - margin: 5px auto 0;
84 -}
85 -.tui-colorpicker-palette-toggle-slider {
86 - display: none;
87 -}
88 -.input-wrapper {
89 - position: relative;
90 -}
91 -.input-wrapper input {
92 - cursor: pointer;
93 - position: absolute;
94 - font-size: 999px;
95 - left: 0;
96 - top: 0;
97 - opacity: 0;
98 - width: 100%;
99 - height: 100%;
100 - overflow: hidden;
101 -}
102 -.btn-text-style {
103 - padding: 5px;
104 - margin: 3px 1px;
105 - border: 1px dashed #bfbebe;
106 - outline: 0;
107 - background-color: #eee;
108 - cursor: pointer;
109 -}
110 -.icon-text {
111 - font-size: 20px;
112 -}
113 -.select-line-type {
114 - outline: 0;
115 - vertical-align: middle;
116 -}
117 -#tui-color-picker {
118 - display: inline-block;
119 - vertical-align: middle;
120 -}
121 -#tui-text-palette {
122 - display: none;
123 - position: absolute;
124 - padding: 10px;
125 - border: 1px solid #bfbebe;
126 - background-color: #fff;
127 - z-index: 9999;
128 -}
1 -html,
2 -body {
3 - margin: 0;
4 - padding: 0;
5 - height: 100%;
6 - overflow: hidden;
7 - background-color: #383838;
8 - font-family: Sans-Serif;
9 -}
10 -ul,
11 -li {
12 - list-style: none;
13 - margin: 0;
14 - padding: 0;
15 -}
16 -input[type='button'],
17 -button {
18 - -webkit-appearance: none;
19 - -moz-appearance: none;
20 - background-color: #fff;
21 -}
22 -input[type='file'] {
23 - position: absolute;
24 - margin: 0;
25 - padding: 0;
26 - top: 0;
27 - left: 0;
28 - width: 100%;
29 - height: 100%;
30 - cursor: pointer;
31 - opacity: 0;
32 - filter: alpha(opacity=0);
33 -}
34 -.header {
35 - position: fixed;
36 - left: 0;
37 - top: 0;
38 - width: 100%;
39 - background-color: #fff;
40 - text-align: center;
41 - z-index: 9999;
42 -}
43 -.header .logo {
44 - margin: 10px 5px;
45 - width: 180px;
46 - vertical-align: middle;
47 -}
48 -.header .name {
49 - font-size: 16px;
50 - font-weight: bold;
51 -}
52 -.header .menu {
53 - padding: 10px;
54 - background-color: #000;
55 -}
56 -.header .menu input {
57 - opacity: 0;
58 -}
59 -.header .menu img {
60 - width: 20px;
61 - height: 20px;
62 - vertical-align: middle;
63 -}
64 -.header .button {
65 - position: relative;
66 - display: inline-block;
67 - margin: 0 5px;
68 - padding: 0;
69 - border-radius: 5px 5px;
70 - width: 30px;
71 - height: 30px;
72 - border: 0;
73 - background-color: #fff;
74 - vertical-align: middle;
75 -}
76 -.header .button.disabled img {
77 - opacity: 0.5;
78 -}
79 -.tui-image-editor {
80 - height: 100%;
81 -}
82 -.tui-image-editor-canvas-container {
83 - margin: 0 auto;
84 - top: 50%;
85 - transform: translateY(-50%);
86 - -ms-transform: translateY(-50%);
87 - -moz-transform: translateY(-50%);
88 - -webkit-transform: translateY(-50%);
89 - overflow: hidden;
90 -}
91 -.tui-image-editor-controls {
92 - position: fixed;
93 - width: 100%;
94 - left: 0;
95 - bottom: 0;
96 - background-color: #fff;
97 -}
98 -.tui-image-editor-controls .scrollable {
99 - display: inline-block;
100 - overflow-x: auto;
101 - width: 100%;
102 - height: 100%;
103 - white-space: nowrap;
104 - font-size: 0;
105 - background-color: #000;
106 - vertical-align: middle;
107 -}
108 -.tui-image-editor-controls .no-scrollable {
109 - overflow-x: hidden;
110 -}
111 -.tui-image-editor-controls .menu-item {
112 - display: inline-block;
113 - height: 80px;
114 - border-right: 1px solid #383838;
115 - background-color: #ddd;
116 - vertical-align: middle;
117 -}
118 -.tui-image-editor-controls .menu-button {
119 - width: 80px;
120 - height: 80px;
121 - border: none;
122 - vertical-align: middle;
123 - background-color: #000;
124 - color: #fff;
125 - font-size: 12px;
126 - font-weight: bold;
127 - outline: 0;
128 -}
129 -.tui-image-editor-controls .submenu-button {
130 - width: 80px;
131 - height: 80px;
132 - border: none;
133 - background-color: #ddd;
134 - vertical-align: middle;
135 -}
136 -.tui-image-editor-controls .hiddenmenu-button {
137 - margin: 0 10px;
138 - padding: 5px;
139 - border: none;
140 - color: #fff;
141 - background-color: rgba(255, 255, 255, 0);
142 -}
143 -.tui-image-editor-controls .submenu {
144 - display: none;
145 - position: absolute;
146 - top: 0;
147 - left: 0;
148 - width: 100%;
149 - font-size: 0;
150 -}
151 -.tui-image-editor-controls .submenu.show {
152 - display: block;
153 -}
154 -.tui-image-editor-controls .submenu .menu-item:last-child {
155 - margin-right: 50px;
156 -}
157 -.tui-image-editor-controls .hiddenmenu {
158 - position: absolute;
159 - display: none;
160 - padding: 40px;
161 - width: 100%;
162 - left: 0;
163 - bottom: 80px;
164 - background-color: rgba(0, 0, 0, 0.7);
165 - text-align: center;
166 - -webkit-box-sizing: border-box;
167 - -moz-box-sizing: border-box;
168 - box-sizing: border-box;
169 - z-index: 9999;
170 -}
171 -.tui-image-editor-controls .hiddenmenu.show {
172 - display: block;
173 -}
174 -.tui-image-editor-controls .hiddenmenu .top {
175 - font-size: 12px;
176 - color: #fff;
177 - margin-bottom: 20px;
178 -}
179 -.tui-image-editor-controls .btn-prev {
180 - display: inline-block;
181 - width: 30px;
182 - height: 80px;
183 - background-color: #000;
184 - color: #fff;
185 - border: none;
186 - vertical-align: middle;
187 -}
188 -.tui-image-editor-controls .tui-colorpicker-container {
189 - display: inline-block;
190 -}
191 -.tui-image-editor-controls .msg {
192 - position: absolute;
193 - margin-left: 50%;
194 - padding: 5px 10px;
195 - left: -86px;
196 - top: -50px;
197 - border-radius: 5px 5px;
198 - background-color: rgba(255, 255, 255, 0.5);
199 - font-size: 12px;
200 -}
201 -.tui-image-editor-controls .msg.hide {
202 - display: none;
203 -}
1 -body {
2 - margin: 0;
3 - padding: 0;
4 -}
5 -
6 -.code-description {
7 - padding: 22px 52px;
8 - background-color: rgba(81, 92, 230, 0.1);
9 - line-height: 1.4em;
10 -}
11 -
12 -.code-description,
13 -.code-description a {
14 - font-family: Arial;
15 - font-size: 14px;
16 - color: #515ce6;
17 -}
18 -
19 -.code-html {
20 - padding: 20px 52px;
21 -}
1 -<!DOCTYPE html>
2 -<html>
3 - <head>
4 - <meta charset="UTF-8" />
5 - <title>0. Design</title>
6 - <link
7 - type="text/css"
8 - href="https://uicdn.toast.com/tui-color-picker/v2.2.6/tui-color-picker.css"
9 - rel="stylesheet"
10 - />
11 - <link type="text/css" href="../dist/tui-image-editor.css" rel="stylesheet" />
12 - <style>
13 - @import url(http://fonts.googleapis.com/css?family=Noto+Sans);
14 - html,
15 - body {
16 - height: 100%;
17 - margin: 0;
18 - }
19 - </style>
20 - </head>
21 - <body>
22 - <div id="tui-image-editor-container"></div>
23 - <script
24 - type="text/javascript"
25 - src="https://api-storage.cloud.toast.com/v1/AUTH_e18353c4ea5746c097143946d0644e61/toast-ui-cdn/tui-image-editor/v3.11.0/example/fabric-v4.2.0.js"
26 - ></script>
27 - <script
28 - type="text/javascript"
29 - src="https://uicdn.toast.com/tui.code-snippet/v1.5.0/tui-code-snippet.min.js"
30 - ></script>
31 - <script
32 - type="text/javascript"
33 - src="https://uicdn.toast.com/tui-color-picker/v2.2.6/tui-color-picker.js"
34 - ></script>
35 - <script
36 - type="text/javascript"
37 - src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/1.3.3/FileSaver.min.js"
38 - ></script>
39 - <script type="text/javascript" src="../dist/tui-image-editor.js"></script>
40 - <script type="text/javascript" src="./js/theme/white-theme.js"></script>
41 - <script type="text/javascript" src="./js/theme/black-theme.js"></script>
42 - <script>
43 - // Image editor
44 - var imageEditor = new tui.ImageEditor('#tui-image-editor-container', {
45 - includeUI: {
46 - loadImage: {
47 - path: 'img/sampleImage2.png',
48 - name: 'SampleImage',
49 - },
50 - theme: blackTheme, // or whiteTheme
51 - initMenu: 'filter',
52 - menuBarPosition: 'bottom',
53 - },
54 - cssMaxWidth: 700,
55 - cssMaxHeight: 500,
56 - usageStatistics: false,
57 - });
58 - window.onresize = function () {
59 - imageEditor.ui.resizeEditor();
60 - };
61 - </script>
62 - </body>
63 -</html>
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
1 -{
2 - "example01-includeUi": {
3 - "title": "1. Include ui"
4 - },
5 - "example02-useApiDirect": {
6 - "title": "2. Use api direct (basic)"
7 - },
8 - "example03-mobile": {
9 - "title": "3. Mobile"
10 - }
11 -}
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
1 -var blackTheme = {
2 - 'common.bi.image': 'https://uicdn.toast.com/toastui/img/tui-image-editor-bi.png',
3 - 'common.bisize.width': '251px',
4 - 'common.bisize.height': '21px',
5 - 'common.backgroundImage': 'none',
6 - 'common.backgroundColor': '#1e1e1e',
7 - 'common.border': '0px',
8 -
9 - // header
10 - 'header.backgroundImage': 'none',
11 - 'header.backgroundColor': 'transparent',
12 - 'header.border': '0px',
13 -
14 - // load button
15 - 'loadButton.backgroundColor': '#fff',
16 - 'loadButton.border': '1px solid #ddd',
17 - 'loadButton.color': '#222',
18 - 'loadButton.fontFamily': "'Noto Sans', sans-serif",
19 - 'loadButton.fontSize': '12px',
20 -
21 - // download button
22 - 'downloadButton.backgroundColor': '#fdba3b',
23 - 'downloadButton.border': '1px solid #fdba3b',
24 - 'downloadButton.color': '#fff',
25 - 'downloadButton.fontFamily': "'Noto Sans', sans-serif",
26 - 'downloadButton.fontSize': '12px',
27 -
28 - // main icons
29 - 'menu.normalIcon.color': '#8a8a8a',
30 - 'menu.activeIcon.color': '#555555',
31 - 'menu.disabledIcon.color': '#434343',
32 - 'menu.hoverIcon.color': '#e9e9e9',
33 - 'menu.iconSize.width': '24px',
34 - 'menu.iconSize.height': '24px',
35 -
36 - // submenu icons
37 - 'submenu.normalIcon.color': '#8a8a8a',
38 - 'submenu.activeIcon.color': '#e9e9e9',
39 - 'submenu.iconSize.width': '32px',
40 - 'submenu.iconSize.height': '32px',
41 -
42 - // submenu primary color
43 - 'submenu.backgroundColor': '#1e1e1e',
44 - 'submenu.partition.color': '#3c3c3c',
45 -
46 - // submenu labels
47 - 'submenu.normalLabel.color': '#8a8a8a',
48 - 'submenu.normalLabel.fontWeight': 'lighter',
49 - 'submenu.activeLabel.color': '#fff',
50 - 'submenu.activeLabel.fontWeight': 'lighter',
51 -
52 - // checkbox style
53 - 'checkbox.border': '0px',
54 - 'checkbox.backgroundColor': '#fff',
55 -
56 - // range style
57 - 'range.pointer.color': '#fff',
58 - 'range.bar.color': '#666',
59 - 'range.subbar.color': '#d1d1d1',
60 -
61 - 'range.disabledPointer.color': '#414141',
62 - 'range.disabledBar.color': '#282828',
63 - 'range.disabledSubbar.color': '#414141',
64 -
65 - 'range.value.color': '#fff',
66 - 'range.value.fontWeight': 'lighter',
67 - 'range.value.fontSize': '11px',
68 - 'range.value.border': '1px solid #353535',
69 - 'range.value.backgroundColor': '#151515',
70 - 'range.title.color': '#fff',
71 - 'range.title.fontWeight': 'lighter',
72 -
73 - // colorpicker style
74 - 'colorpicker.button.border': '1px solid #1e1e1e',
75 - 'colorpicker.title.color': '#fff',
76 -};
1 -var whiteTheme = {
2 - 'common.bi.image': 'https://uicdn.toast.com/toastui/img/tui-image-editor-bi.png',
3 - 'common.bisize.width': '251px',
4 - 'common.bisize.height': '21px',
5 - 'common.backgroundImage': './img/bg.png',
6 - 'common.backgroundColor': '#fff',
7 - 'common.border': '1px solid #c1c1c1',
8 -
9 - // header
10 - 'header.backgroundImage': 'none',
11 - 'header.backgroundColor': 'transparent',
12 - 'header.border': '0px',
13 -
14 - // load button
15 - 'loadButton.backgroundColor': '#fff',
16 - 'loadButton.border': '1px solid #ddd',
17 - 'loadButton.color': '#222',
18 - 'loadButton.fontFamily': "'Noto Sans', sans-serif",
19 - 'loadButton.fontSize': '12px',
20 -
21 - // download button
22 - 'downloadButton.backgroundColor': '#fdba3b',
23 - 'downloadButton.border': '1px solid #fdba3b',
24 - 'downloadButton.color': '#fff',
25 - 'downloadButton.fontFamily': "'Noto Sans', sans-serif",
26 - 'downloadButton.fontSize': '12px',
27 -
28 - // main icons
29 - 'menu.normalIcon.color': '#8a8a8a',
30 - 'menu.activeIcon.color': '#555555',
31 - 'menu.disabledIcon.color': '#434343',
32 - 'menu.hoverIcon.color': '#e9e9e9',
33 - 'menu.iconSize.width': '24px',
34 - 'menu.iconSize.height': '24px',
35 -
36 - // submenu icons
37 - 'submenu.normalIcon.color': '#8a8a8a',
38 - 'submenu.activeIcon.color': '#555555',
39 - 'submenu.iconSize.width': '32px',
40 - 'submenu.iconSize.height': '32px',
41 -
42 - // submenu primary color
43 - 'submenu.backgroundColor': 'transparent',
44 - 'submenu.partition.color': '#e5e5e5',
45 -
46 - // submenu labels
47 - 'submenu.normalLabel.color': '#858585',
48 - 'submenu.normalLabel.fontWeight': 'normal',
49 - 'submenu.activeLabel.color': '#000',
50 - 'submenu.activeLabel.fontWeight': 'normal',
51 -
52 - // checkbox style
53 - 'checkbox.border': '1px solid #ccc',
54 - 'checkbox.backgroundColor': '#fff',
55 -
56 - // rango style
57 - 'range.pointer.color': '#333',
58 - 'range.bar.color': '#ccc',
59 - 'range.subbar.color': '#606060',
60 -
61 - 'range.disabledPointer.color': '#d3d3d3',
62 - 'range.disabledBar.color': 'rgba(85,85,85,0.06)',
63 - 'range.disabledSubbar.color': 'rgba(51,51,51,0.2)',
64 -
65 - 'range.value.color': '#000',
66 - 'range.value.fontWeight': 'normal',
67 - 'range.value.fontSize': '11px',
68 - 'range.value.border': '0',
69 - 'range.value.backgroundColor': '#f5f5f5',
70 - 'range.title.color': '#000',
71 - 'range.title.fontWeight': 'lighter',
72 -
73 - // colorpicker style
74 - 'colorpicker.button.border': '0px',
75 - 'colorpicker.title.color': '#000',
76 -};
1 -// Type definitions for TOAST UI Image Editor v3.9.0
2 -// TypeScript Version: 3.2.2
3 -
4 -declare namespace tuiImageEditor {
5 - type AngleType = number;
6 -
7 - interface IThemeConfig {
8 - 'common.bi.image'?: string;
9 - 'common.bisize.width'?: string;
10 - 'common.bisize.height'?: string;
11 - 'common.backgroundImage'?: string;
12 - 'common.backgroundColor'?: string;
13 - 'common.border'?: string;
14 - 'header.backgroundImage'?: string;
15 - 'header.backgroundColor'?: string;
16 - 'header.border'?: string;
17 - 'loadButton.backgroundColor'?: string;
18 - 'loadButton.border'?: string;
19 - 'loadButton.color'?: string;
20 - 'loadButton.fontFamily'?: string;
21 - 'loadButton.fontSize'?: string;
22 - 'downloadButton.backgroundColor'?: string;
23 - 'downloadButton.border'?: string;
24 - 'downloadButton.color'?: string;
25 - 'downloadButton.fontFamily'?: string;
26 - 'downloadButton.fontSize'?: string;
27 - 'menu.normalIcon.path'?: string;
28 - 'menu.normalIcon.name'?: string;
29 - 'menu.activeIcon.path'?: string;
30 - 'menu.activeIcon.name'?: string;
31 - 'menu.iconSize.width'?: string;
32 - 'menu.iconSize.height'?: string;
33 - 'submenu.backgroundColor'?: string;
34 - 'submenu.partition.color'?: string;
35 - 'submenu.normalIcon.path'?: string;
36 - 'submenu.normalIcon.name'?: string;
37 - 'submenu.activeIcon.path'?: string;
38 - 'submenu.activeIcon.name'?: string;
39 - 'submenu.iconSize.width'?: string;
40 - 'submenu.iconSize.height'?: string;
41 - 'submenu.normalLabel.color'?: string;
42 - 'submenu.normalLabel.fontWeight'?: string;
43 - 'submenu.activeLabel.color'?: string;
44 - 'submenu.activeLabel.fontWeight'?: string;
45 - 'checkbox.border'?: string;
46 - 'checkbox.backgroundColor'?: string;
47 - 'range.pointer.color'?: string;
48 - 'range.bar.color'?: string;
49 - 'range.subbar.color'?: string;
50 - 'range.value.color'?: string;
51 - 'range.value.fontWeight'?: string;
52 - 'range.value.fontSize'?: string;
53 - 'range.value.border'?: string;
54 - 'range.value.backgroundColor'?: string;
55 - 'range.title.color'?: string;
56 - 'range.title.fontWeight'?: string;
57 - 'colorpicker.button.border'?: string;
58 - 'colorpicker.title.color'?: string;
59 - }
60 -
61 - interface IIconInfo {
62 - [propName: string]: string;
63 - }
64 -
65 - interface IIconOptions {
66 - fill?: string;
67 - left?: number;
68 - top?: number;
69 - }
70 -
71 - interface IShapeOptions {
72 - fill?: string;
73 - stroke?: string;
74 - strokeWidth?: number;
75 - width?: number;
76 - height?: number;
77 - rx?: number;
78 - ry?: number;
79 - left?: number;
80 - top?: number;
81 - isRegular?: boolean;
82 - }
83 -
84 - interface IGenerateTextOptions {
85 - styles?: ITextStyleConfig;
86 - position?: {
87 - x: number;
88 - y: number;
89 - };
90 - }
91 -
92 - interface ITextStyleConfig {
93 - fill?: string;
94 - fontFamily?: string;
95 - fontSize?: number;
96 - fontStyle?: string;
97 - fontWeight?: string;
98 - textAlign?: string;
99 - textDecoration?: string;
100 - }
101 -
102 - interface IRectConfig {
103 - left: number;
104 - top: number;
105 - width: number;
106 - height: number;
107 - }
108 -
109 - interface ICanvasSize {
110 - width: number;
111 - height: number;
112 - }
113 -
114 - interface IBrushOptions {
115 - width: number;
116 - color: string;
117 - }
118 -
119 - interface IPositionConfig {
120 - x: number;
121 - y: number;
122 - originX: string;
123 - originY: string;
124 - }
125 -
126 - interface IToDataURLOptions {
127 - format?: string;
128 - quality?: number;
129 - multiplier?: number;
130 - left?: number;
131 - top?: number;
132 - width?: number;
133 - height?: number;
134 - }
135 -
136 - interface IGraphicObjectProps {
137 - id?: number;
138 - type?: string;
139 - text?: string;
140 - left?: string | number;
141 - top?: string | number;
142 - width?: string | number;
143 - height?: string | number;
144 - fill?: string;
145 - stroke?: string;
146 - strokeWidth?: string | number;
147 - fontFamily?: string;
148 - fontSize?: number;
149 - fontStyle?: string;
150 - fontWeight?: string;
151 - textAlign?: string;
152 - textDecoration?: string;
153 - opacity?: number;
154 - [propName: string]: number | string | boolean | undefined;
155 - }
156 -
157 - interface IIncludeUIOptions {
158 - loadImage?: {
159 - path: string;
160 - name: string;
161 - };
162 - theme?: IThemeConfig;
163 - menu?: string[];
164 - initMenu?: string;
165 - uiSize?: {
166 - width: string;
167 - height: string;
168 - };
169 - menuBarPosition?: string;
170 - usageStatistics?: boolean;
171 - }
172 -
173 - interface ISelectionStyleConfig {
174 - cornerStyle?: string;
175 - cornerSize?: number;
176 - cornerColor?: string;
177 - cornerStrokeColor?: string;
178 - transparentCorners?: boolean;
179 - lineWidth?: number;
180 - borderColor?: string;
181 - rotatingPointOffset?: number;
182 - }
183 -
184 - interface IObjectProps {
185 - // icon, shape
186 - fill: string;
187 - height: number;
188 - id: number;
189 - left: number;
190 - opacity: number;
191 - stroke: string | null;
192 - strokeWidth: number | null;
193 - top: number;
194 - type: string;
195 - width: number;
196 - }
197 -
198 - interface ITextObjectProps extends IObjectProps {
199 - fontFamily: string;
200 - fontSize: string;
201 - fontStyle: string;
202 - text: string;
203 - textAlign: string;
204 - textDecoration: string;
205 - }
206 -
207 - interface IFilterResolveObject {
208 - type: string;
209 - action: string;
210 - }
211 -
212 - interface ICropResolveObject {
213 - oldWidth: number;
214 - oldHeight: number;
215 - newWidth: number;
216 - newHeight: number;
217 - }
218 -
219 - interface IFlipXYResolveObject {
220 - flipX: boolean;
221 - flipY: boolean;
222 - angle: AngleType;
223 - }
224 -
225 - interface IOptions {
226 - includeUI?: IIncludeUIOptions;
227 - cssMaxWidth?: number;
228 - cssMaxHeight?: number;
229 - usageStatistics?: boolean;
230 - selectionStyle?: ISelectionStyleConfig;
231 - }
232 -
233 - interface IUIDimension {
234 - height?: string;
235 - width?: string;
236 - }
237 -
238 - interface IImageDimension {
239 - oldHeight?: number;
240 - oldWidth?: number;
241 - newHeight?: number;
242 - newWidth?: number;
243 - }
244 -
245 - interface IEditorSize {
246 - uiSize?: IUIDimension;
247 - imageSize?: IImageDimension;
248 - }
249 -
250 - interface UI {
251 - resizeEditor(dimension: IEditorSize): Promise<void>;
252 - }
253 -
254 - class ImageEditor {
255 - constructor(wrapper: string | Element, options: IOptions);
256 - public ui: UI;
257 -
258 - public addIcon(type: string, options?: IIconOptions): Promise<IObjectProps>;
259 - public addImageObject(imgUrl: string): Promise<void>;
260 - public addShape(type: string, options?: IShapeOptions): Promise<IObjectProps>;
261 - public addText(text: string, options?: IGenerateTextOptions): Promise<ITextObjectProps>;
262 - public applyFilter(
263 - type: string,
264 - options?: {
265 - maskObjId: number;
266 - },
267 - isSilent?: boolean
268 - ): Promise<IFilterResolveObject>;
269 - public changeCursor(cursorType: string): void;
270 - public changeIconColor(id: number, color: string): Promise<void>;
271 - public changeSelectableAll(selectable: boolean): void;
272 - public changeShape(id: number, options?: IShapeOptions, isSilent?: boolean): Promise<void>;
273 - public changeText(id: number, text?: string): Promise<void>;
274 - public changeTextStyle(
275 - id: number,
276 - styleObj: ITextStyleConfig,
277 - isSilent?: boolean
278 - ): Promise<void>;
279 - public clearObjects(): Promise<void>;
280 - public clearRedoStack(): void;
281 - public clearUndoStack(): void;
282 - public crop(rect: IRectConfig): Promise<ICropResolveObject>;
283 - public deactivateAll(): void;
284 - public destroy(): void;
285 - public discardSelection(): void;
286 - public flipX(): Promise<IFlipXYResolveObject>;
287 - public flipY(): Promise<IFlipXYResolveObject>;
288 - public getCanvasSize(): ICanvasSize;
289 - public getCropzoneRect(): IRectConfig;
290 - public getDrawingMode(): string;
291 - public getImageName(): string;
292 - public getObjectPosition(id: number, originX: string, originY: string): ICanvasSize;
293 - public getObjectProperties(
294 - id: number,
295 - keys: string | string[] | IGraphicObjectProps
296 - ): IGraphicObjectProps;
297 - public hasFilter(type: string): boolean;
298 - public isEmptyRedoStack(): boolean;
299 - public isEmptyUndoStack(): boolean;
300 - public loadImageFromFile(imgFile: File, imageName?: string): Promise<ICropResolveObject>;
301 - public loadImageFromURL(url: string, imageName?: string): Promise<ICropResolveObject>;
302 - public redo(): Promise<any>;
303 - public registerIcons(infos: IIconInfo): void;
304 - public removeActiveObject(): void;
305 - public removeFilter(type?: string): Promise<IFilterResolveObject>;
306 - public removeObject(id: number): Promise<void>;
307 - public resetFlip(): Promise<IFlipXYResolveObject>;
308 - public resizeCanvasDimension(dimension: ICanvasSize): Promise<void>;
309 - public rotate(angle: AngleType, isSilent?: boolean): Promise<AngleType>;
310 - public setAngle(angle: AngleType, isSilent?: boolean): Promise<AngleType>;
311 - public setBrush(option: IBrushOptions): void;
312 - public setCropzoneRect(mode?: number): void;
313 - public setDrawingShape(type: string, options?: IShapeOptions): void;
314 - public setObjectPosition(id: number, posInfo?: IPositionConfig): Promise<void>;
315 - public setObjectProperties(id: number, keyValue?: IGraphicObjectProps): Promise<void>;
316 - public setObjectPropertiesQuietly(id: number, keyValue?: IGraphicObjectProps): Promise<void>;
317 - public startDrawingMode(mode: string, option?: { width?: number; color?: string }): boolean;
318 - public stopDrawingMode(): void;
319 - public toDataURL(options?: IToDataURLOptions): string;
320 - public undo(): Promise<any>;
321 - public on(eventName: string, handler: (...args: any[]) => void): void;
322 - }
323 -}
324 -
325 -declare module 'tui-image-editor' {
326 - export = tuiImageEditor.ImageEditor;
327 -}
1 -{
2 - "source": {
3 - "include": ["src", "README.md"],
4 - "exclude": [],
5 - "includePattern": ".+\\.js(doc)?$",
6 - "excludePattern": "(^|\\/|\\\\)_"
7 - },
8 - "plugins": ["plugins/markdown"],
9 - "templates": {
10 - "name": "ImageEditor",
11 - "logo": {
12 - "url": "https://user-images.githubusercontent.com/35218826/40895380-0b9f4cd6-67ea-11e8-982f-18121daa3a04.png",
13 - "width": "150px",
14 - "height": "13px",
15 - "link": "https://github.com/nhn/tui.jsdoc-template"
16 - }
17 - },
18 - "opts": {
19 - "private": false,
20 - "recurse": true,
21 - "destination": "doc",
22 - "tutorials": "examples",
23 - "template": "./node_modules/tui-jsdoc-template",
24 - "package": "package.json"
25 - }
26 -}
1 -/* eslint-disable consts-on-top, no-process-env, require-jsdoc */
2 -/* eslint-disable no-process-env, require-jsdoc */
3 -const webdriverConfig = {
4 - hostname: 'fe.nhnent.com',
5 - port: 4444,
6 - remoteHost: true,
7 -};
8 -
9 -function setConfig(defaultConfig, server) {
10 - if (server === 'ne') {
11 - defaultConfig.customLaunchers = {
12 - IE9: {
13 - base: 'WebDriver',
14 - config: webdriverConfig,
15 - browserName: 'internet explorer',
16 - version: '9',
17 - },
18 - IE10: {
19 - base: 'WebDriver',
20 - config: webdriverConfig,
21 - browserName: 'internet explorer',
22 - version: '10',
23 - },
24 - IE11: {
25 - base: 'WebDriver',
26 - config: webdriverConfig,
27 - browserName: 'internet explorer',
28 - version: '11',
29 - },
30 - Edge: {
31 - base: 'WebDriver',
32 - config: webdriverConfig,
33 - browserName: 'MicrosoftEdge',
34 - },
35 - 'Chrome-WebDriver': {
36 - base: 'WebDriver',
37 - config: webdriverConfig,
38 - browserName: 'chrome',
39 - },
40 - 'Firefox-WebDriver': {
41 - base: 'WebDriver',
42 - config: webdriverConfig,
43 - browserName: 'firefox',
44 - },
45 - 'Safari-WebDriver': {
46 - base: 'WebDriver',
47 - config: webdriverConfig,
48 - browserName: 'safari',
49 - },
50 - };
51 - defaultConfig.browsers = [
52 - 'IE9',
53 - 'IE10',
54 - // 'IE11',
55 - // 'Edge',
56 - 'Chrome-WebDriver',
57 - 'Firefox-WebDriver',
58 - // 'Safari-WebDriver'
59 - ];
60 - defaultConfig.reporters.push('coverage');
61 - defaultConfig.reporters.push('junit');
62 - defaultConfig.coverageReporter = {
63 - dir: 'report/coverage/',
64 - reporters: [
65 - {
66 - type: 'html',
67 - subdir(browser) {
68 - return `report-html/${browser}`;
69 - },
70 - },
71 - {
72 - type: 'cobertura',
73 - subdir(browser) {
74 - return `report-cobertura/${browser}`;
75 - },
76 - file: 'cobertura.txt',
77 - },
78 - ],
79 - };
80 - defaultConfig.junitReporter = {
81 - outputDir: 'report/junit',
82 - suite: '',
83 - };
84 - } else {
85 - defaultConfig.browsers = ['ChromeHeadless'];
86 - }
87 -}
88 -
89 -module.exports = function (config) {
90 - const defaultConfig = {
91 - basePath: './',
92 - frameworks: ['jasmine', 'jquery-3.2.1', 'es5-shim'],
93 - files: [
94 - // reason for not using karma-jasmine-jquery framework is that including older jasmine-karma file
95 - // included jasmine-karma version is 2.0.5 and this version don't support ie8
96 - 'node_modules/jasmine-jquery/lib/jasmine-jquery.js',
97 - 'node_modules/fabric/dist/fabric.js',
98 - 'test/index.js',
99 - {
100 - pattern: 'test/fixtures/*.jpg',
101 - watched: false,
102 - included: false,
103 - served: true,
104 - },
105 - {
106 - pattern: 'test/fixtures/*.png',
107 - watched: false,
108 - included: false,
109 - served: true,
110 - },
111 - {
112 - pattern: 'test/fixtures/*.svg',
113 - watched: false,
114 - included: false,
115 - served: true,
116 - },
117 - ],
118 - preprocessors: {
119 - 'test/index.js': ['webpack', 'sourcemap'],
120 - },
121 - reporters: ['dots'],
122 - webpack: {
123 - mode: 'development',
124 - devtool: 'inline-source-map',
125 - externals: {
126 - fabric: 'fabric',
127 - },
128 - module: {
129 - rules: [
130 - {
131 - test: /\.js$/,
132 - include: /src/,
133 - exclude: /node_modules/,
134 - loader: 'eslint-loader',
135 - enforce: 'pre',
136 - },
137 - {
138 - test: /\.js$/,
139 - exclude: /(test|node_modules)/,
140 - loader: 'istanbul-instrumenter-loader',
141 - query: {
142 - esModules: true,
143 - },
144 - },
145 - {
146 - test: /\.js$/,
147 - exclude: /node_modules/,
148 - loader: 'babel-loader?cacheDirectory',
149 - options: {
150 - babelrc: true,
151 - },
152 - },
153 - {
154 - test: /\.styl$/,
155 - use: ['css-loader', 'stylus-loader'],
156 - },
157 - {
158 - test: /\.svg$/,
159 - loader: 'svg-inline-loader',
160 - },
161 - ],
162 - },
163 - },
164 - port: 9876,
165 - colors: true,
166 - logLevel: config.LOG_INFO,
167 - autoWatch: true,
168 - singleRun: true,
169 - };
170 -
171 - /* eslint-disable */
172 - setConfig(defaultConfig, process.env.KARMA_SERVER);
173 - config.set(defaultConfig);
174 -};
1 -const fs = require('fs');
2 -const mkdirp = require('mkdirp');
3 -const svgstore = require('svgstore');
4 -const svgDir = './src/svg';
5 -
6 -function getFileList(dir) {
7 - const targetDir = `${svgDir}/${dir}`;
8 - const sprites = svgstore();
9 - fs.readdir(targetDir, (err, files) => {
10 - if (!files) return;
11 - files.forEach((file) => {
12 - if (file.match(/^\./)) return;
13 - const id = `${dir}-${file.replace(/\.svg$/, '')}`;
14 - const svg = fs.readFileSync(`${targetDir}/${file}`);
15 - sprites.add(id, svg);
16 - });
17 - fs.writeFileSync(`./dist/svg/${dir}.svg`, sprites);
18 - });
19 -}
20 -
21 -mkdirp('./dist/svg', (mkdirpErr) => {
22 - if (mkdirpErr) {
23 - console.error(mkdirpErr);
24 - } else {
25 - fs.readdir(svgDir, (err, dirs) => {
26 - dirs.forEach((dir) => {
27 - getFileList(dir);
28 - });
29 - });
30 - }
31 -});
This diff could not be displayed because it is too large.
1 { 1 {
2 - "name": "tui-image-editor", 2 + "name": "@toast-ui/react-image-editor",
3 - "author": "NHN FE Development Lab <dl_javascript@nhn.com>", 3 + "version": "1.3.0",
4 - "version": "3.11.0", 4 + "description": "React wrapper component for tui.imageEditor",
5 - "license": "MIT", 5 + "main": "dist/toastui-react-image-editor.js",
6 - "repository": {
7 - "type": "git",
8 - "url": "https://github.com/nhn/tui.image-editor.git"
9 - },
10 - "main": "dist/tui-image-editor.js",
11 "files": [ 6 "files": [
12 - "src",
13 "dist", 7 "dist",
14 - "index.d.ts" 8 + "src"
15 - ],
16 - "description": "TOAST UI Component: ImageEditor",
17 - "keywords": [
18 - "nhn",
19 - "nhnent",
20 - "tui",
21 - "component",
22 - "image",
23 - "editor",
24 - "canvas",
25 - "fabric"
26 ], 9 ],
27 - "devDependencies": {
28 - "babel-core": "^6.26.3",
29 - "babel-eslint": "^10.0.3",
30 - "babel-loader": "^7.1.2",
31 - "babel-preset-es2015": "^6.24.1",
32 - "css-loader": "^3.4.1",
33 - "dtslint": "^0.4.2",
34 - "es5-shim": "^4.5.9",
35 - "eslint": "^4.5.0",
36 - "eslint-config-prettier": "^6.15.0",
37 - "eslint-config-tui": "^1.0.1",
38 - "eslint-loader": "^2.0.0",
39 - "eslint-plugin-prettier": "^3.1.4",
40 - "file-saver": "^1.3.3",
41 - "istanbul-instrumenter-loader": "^1.0.0",
42 - "jasmine-core": "^2.4.1",
43 - "jasmine-jquery": "^2.1.1",
44 - "jquery": "^3.4.0",
45 - "jsdoc": "^3.5.4",
46 - "karma": "^4.4.1",
47 - "karma-chrome-launcher": "^2.2.0",
48 - "karma-coverage": "^2.0.1",
49 - "karma-edge-launcher": "^0.4.2",
50 - "karma-es5-shim": "0.0.4",
51 - "karma-firefox-launcher": "^1.1.0",
52 - "karma-ie-launcher": "^1.0.0",
53 - "karma-jasmine": "^1.1.1",
54 - "karma-jasmine-jquery-2": "^0.1.1",
55 - "karma-jquery": "^0.2.4",
56 - "karma-junit-reporter": "^1.2.0",
57 - "karma-sourcemap-loader": "^0.3.7",
58 - "karma-webdriver-launcher": "git+https://github.com/nhn/karma-webdriver-launcher.git#v1.2.0",
59 - "karma-webpack": "^4.0.2",
60 - "mini-css-extract-plugin": "^0.9.0",
61 - "mkdirp": "^0.5.1",
62 - "optimize-css-assets-webpack-plugin": "^5.0.3",
63 - "prettier": "^2.2.1",
64 - "safe-umd-webpack-plugin": "^4.0.0",
65 - "selenium-webdriver": "^4.0.0-alpha.7",
66 - "simulant": "^0.2.2",
67 - "stylus": "^0.54.5",
68 - "stylus-loader": "^3.0.2",
69 - "svg-inline-loader": "^0.8.2",
70 - "svgstore": "^2.0.3",
71 - "tslint": "^5.12.0",
72 - "tui-jsdoc-template": "^1.0.4",
73 - "typescript": "^3.2.2",
74 - "uglifyjs-webpack-plugin": "^2.2.0",
75 - "webpack": "^4.41.5",
76 - "webpack-cli": "^3.3.10",
77 - "webpack-dev-server": "^3.10.1"
78 - },
79 "scripts": { 10 "scripts": {
80 - "test": "karma start --no-single-run", 11 + "build:dev": "webpack --mode development",
81 - "test:ne": "KARMA_SERVER=ne karma start", 12 + "build": "webpack --mode production",
82 - "test:types": "tsc --project test/types",
83 - "bundle": "webpack && webpack -p && npm run bundle:svg && node tsBannerGenerator.js",
84 - "bundle:svg": "node makesvg.js",
85 "serve": "webpack-dev-server", 13 "serve": "webpack-dev-server",
86 - "doc:dev": "tuidoc --dev", 14 + "storybook": "start-storybook -s ./node_modules/tui-image-editor/dist/svg,.storybook -p 6006",
87 - "doc": "tuidoc", 15 + "build-storybook": "build-storybook"
88 - "tslint": "tslint index.d.ts" 16 + },
17 + "homepage": "https://github.com/nhn/toast-ui.react-image-editor",
18 + "bugs": "https://github.com/nhn/toast-ui.react-image-editor/issues",
19 + "author": "NHN. FE Development Lab <dl_javascript@nhn.com>",
20 + "repository": "https://github.com/nhn/toast-ui.react-image-editor.git",
21 + "license": "MIT",
22 + "browserslist": "last 2 versions, ie 9",
23 + "peerDependencies": {
24 + "react": "^16.0.0"
25 + },
26 + "devDependencies": {
27 + "@babel/core": "^7.2.2",
28 + "@babel/plugin-proposal-class-properties": "^7.2.3",
29 + "@babel/plugin-proposal-object-rest-spread": "^7.2.0",
30 + "@babel/preset-env": "^7.2.3",
31 + "@babel/preset-react": "^7.0.0",
32 + "@storybook/addon-actions": "^4.1.7",
33 + "@storybook/addon-knobs": "^4.1.7",
34 + "@storybook/addon-links": "^4.1.7",
35 + "@storybook/addons": "^4.1.7",
36 + "@storybook/react": "^4.1.7",
37 + "babel-eslint": "^10.0.1",
38 + "babel-loader": "^8.0.5",
39 + "css-loader": "^2.1.0",
40 + "eslint": "^5.12.1",
41 + "eslint-config-prettier": "^3.6.0",
42 + "eslint-config-tui": "^2.1.0",
43 + "eslint-plugin-prettier": "^3.0.1",
44 + "eslint-plugin-react": "^7.12.4",
45 + "jquery-mockjax": "^2.5.0",
46 + "prettier": "^1.16.0",
47 + "react": "^16.7.0",
48 + "react-dom": "^16.7.0",
49 + "storybook": "^5.3.13",
50 + "style-loader": "^0.23.1",
51 + "webpack": "^4.29.0",
52 + "webpack-cli": "^3.2.1",
53 + "webpack-dev-server": "^3.1.14"
89 }, 54 },
90 "dependencies": { 55 "dependencies": {
91 - "core-js-pure": "^3.6.4",
92 "fabric": "4.2.0", 56 "fabric": "4.2.0",
93 - "tui-code-snippet": "^1.5.0", 57 + "tui-image-editor": "^3.11.0"
94 - "tui-color-picker": "^2.2.6"
95 } 58 }
96 } 59 }
......
1 -/* ICON BUTTON */
2 -.tie-icon-add-button
3 - &.icon-bubble .{prefix}-button[data-icontype="icon-bubble"] svg > use.active,
4 - &.icon-heart .{prefix}-button[data-icontype="icon-heart"] svg > use.active,
5 - &.icon-location .{prefix}-button[data-icontype="icon-location"] svg > use.active,
6 - &.icon-polygon .{prefix}-button[data-icontype="icon-polygon"] svg > use.active,
7 - &.icon-star .{prefix}-button[data-icontype="icon-star"] svg > use.active,
8 - &.icon-star-2 .{prefix}-button[data-icontype="icon-star-2"] svg > use.active,
9 - &.icon-arrow-3 .{prefix}-button[data-icontype="icon-arrow-3"] svg > use.active,
10 - &.icon-arrow-2 .{prefix}-button[data-icontype="icon-arrow-2"] svg > use.active,
11 - &.icon-arrow .{prefix}-button[data-icontype="icon-arrow"] svg > use.active,
12 - &.icon-bubble .{prefix}-button[data-icontype="icon-bubble"] svg > use.active
13 - display: block;
14 -
15 -/* DRAW BUTTON */
16 -.tie-draw-line-select-button
17 - &.line .{prefix}-button.line svg > use.normal,
18 - &.free .{prefix}-button.free svg > use.normal
19 - display: none;
20 -
21 - &.line .{prefix}-button.line svg > use.active,
22 - &.free .{prefix}-button.free svg > use.active
23 - display: block;
24 -
25 -/* FLIP BUTTON */
26 -.tie-flip-button
27 - &.resetFlip .{prefix}-button.resetFlip,
28 - &.flipX .{prefix}-button.flipX,
29 - &.flipY .{prefix}-button.flipY
30 - svg > use.normal
31 - display: none;
32 - svg > use.active
33 - display: block;
34 -
35 -/* MASK BUTTON */
36 -.tie-mask-apply.apply.active .{prefix}-button.apply
37 - label
38 - color: #fff;
39 - svg > use.active
40 - display: block;
41 -
42 -/* CROP BUTTON */
43 -.tie-crop-button,
44 -.tie-crop-preset-button
45 - .{prefix}-button.apply
46 - margin-right: 24px;
47 - .{prefix}-button.preset.active svg > use.active
48 - display: block;
49 - .{prefix}-button.apply.active svg > use.active
50 - display: block;
51 -
52 -
53 -/* SHAPE BUTTON */
54 -.tie-shape-button
55 - &.rect .{prefix}-button.rect,
56 - &.circle .{prefix}-button.circle,
57 - &.triangle .{prefix}-button.triangle
58 - svg > use.normal
59 - display: none;
60 - svg > use.active
61 - display: block;
62 -
63 -/* TEXT BUTTON */
64 -.tie-text-effect-button
65 - .{prefix}-button.active svg > use.active
66 - display: block;
67 -.tie-text-align-button
68 - &.left .{prefix}-button.left svg > use.active,
69 - &.center .{prefix}-button.center svg > use.active,
70 - &.right .{prefix}-button.right svg > use.active
71 - display: block;
72 -.tie-mask-image-file,
73 -.tie-icon-image-file
74 - opacity: 0;
75 - position: absolute;
76 - width: 100%;
77 - height: 100%;
78 - border: 1px solid green;
79 - cursor: inherit;
80 - left: 0;
81 - top: 0;
1 -/* VIRTUAL CHECKBOX */
2 -.{prefix}-container
3 - .filter-color-item
4 - display: inline-block;
5 - .tui-image-editor-checkbox
6 - display: block;
7 - .{prefix}-checkbox-wrap
8 - display: inline-block !important;
9 - text-align: left;
10 - .{prefix}-checkbox-wrap.fixed-width
11 - width: 187px;
12 - white-space: normal;
13 - .{prefix}-checkbox
14 - display: inline-block;
15 - margin: 1px 0 1px 0;
16 - input
17 - width: 14px;
18 - height: 14px;
19 - opacity: 0;
20 - > label > span
21 - color: #fff;
22 - height: 14px;
23 - position: relative;
24 - input + label:before,
25 - > label > span:before
26 - content: '';
27 - position: absolute;
28 - width: 14px;
29 - height: 14px;
30 - background-color: #fff;
31 - top: 6px;
32 - left: -19px;
33 - display: inline-block;
34 - margin: 0;
35 - text-align: center;
36 - font-size: 11px;
37 - border: 0;
38 - border-radius: 2px;
39 - padding-top: 1px;
40 - box-sizing: border-box;
41 - input[type='checkbox']:checked + span:before
42 - background-size: cover;
43 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAAAXNSR0IArs4c6QAAAMBJREFUKBWVkjEOwjAMRe2WgZW7IIHEDdhghhuwcQ42rlJugAQS54Cxa5cq1QM5TUpByZfS2j9+dlJVt/tX5ZxbS4ZU9VLkQvSHKTIGRaVJYFmKrBbTCJxE2UgCdDzMZDkHrOV6b95V0US6UmgKodujEZbJg0B0ZgEModO5lrY1TMQf1TpyJGBEjD+E2NPN7ukIUDiF/BfEXgRiGEw8NgkffYGYwCi808fpn/6OvfUfsDr/Vc1IfRf8sKnFVqeiVQfDu0tf/nWH9gAAAABJRU5ErkJggg==');
44 -
45 - .{prefix}-selectlist-wrap
46 - position: relative;
47 - select
48 - width: 100%;
49 - height: 28px;
50 - margin-top: 4px;
51 - border: 0;
52 - outline: 0;
53 - border-radius: 0;
54 - border: 1px solid #cbdbdb;
55 - background-color: #fff;
56 - -webkit-appearance: none;
57 - -moz-appearance: none;
58 - appearance: none;
59 - padding: 0 7px 0 10px;
60 - .{prefix}-selectlist
61 - display: none;
62 - position: relative;
63 - top: -1px;
64 - border: 1px solid #ccc;
65 - background-color: #fff;
66 - border-top: 0px;
67 - padding: 4px 0;
68 - li
69 - display: block;
70 - text-align: left;
71 - padding: 7px 10px;
72 - font-family: 'Noto Sans', sans-serif;
73 - li:hover
74 - background-color: rgba(81, 92, 230, 0.05);
75 - .{prefix}-selectlist-wrap:before
76 - content: '';
77 - position: absolute;
78 - display: inline-block;
79 - width: 14px;
80 - height: 14px;
81 - right: 5px;
82 - top: 10px;
83 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAAAXNSR0IArs4c6QAAAHlJREFUKBVjYBgFOEOAEVkmPDxc89+/f6eAYjzI4kD2FyYmJrOVK1deh4kzwRggGiQBVJCELAZig8SQNYHEmEEEMrh69eo1HR0dfqCYJUickZGxf9WqVf3IakBsFBthklpaWmVA9mEQhrJhUoTp0NBQCRAmrHL4qgAAuu4cWZOZIGsAAAAASUVORK5CYII=');
84 - background-size: cover;
85 - .{prefix}-selectlist-wrap select::-ms-expand
86 - display:none;
1 -/* COLOR PICKER */
2 -.{prefix}-container
3 - div.tui-colorpicker-clearfix
4 - width: 159px;
5 - height: 28px;
6 - border: 1px solid #d5d5d5;
7 - border-radius: 2px;
8 - background-color: #f5f5f5;
9 - margin-top: 6px;
10 - padding: 4px 7px 4px 7px;
11 - .tui-colorpicker-palette-hex
12 - width: 114px;
13 - background-color: #f5f5f5;
14 - border: 0;
15 - font-size: 11px;
16 - margin-top: 2px;
17 - font-family: 'Noto Sans', sans-serif;
18 - .tui-colorpicker-palette-hex[value='#ffffff'] + .tui-colorpicker-palette-preview,
19 - .tui-colorpicker-palette-hex[value=''] + .tui-colorpicker-palette-preview
20 - border: 1px solid #ccc;
21 - .tui-colorpicker-palette-hex[value=''] + .tui-colorpicker-palette-preview
22 - background-size: cover;
23 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAdBJREFUWAnFl0FuwjAQRZ0ukiugHqFSOQNdseuKW3ALzkA4BateICvUGyCxrtRFd4WuunH/TzykaYJrnLEYaTJJsP2+x8GZZCbQrLU5mj7Bn+EP8HvnCObd+R7xBV5lWfaNON4AnsA38E94qLEt+0yiFaBzAV/Bv+Cxxr4co7hKCDpw1q9wLeNYYdlAwyn8TYt8Hme3+8D5ozcTaMCZ68PXa2tnM2sbEcOZAJhrrpl2DAcTOGNjZPSfCdzkw6JrfbiMv+osBe4y9WOedhm4jZfhbENWuxS44H9Wz/xw4WzqLOAqh1+zycgAwzEMzr5k5gaHOa9ULBwuuDkFlHI1Kl4PJ66kgIpnoywOTmRFAYcbwYk9UMApWkD8zAV5ihcwHk4Rx7gl0IFTQL0EFc+CTQ9OZHWH3YhlVJiVpTHbrTGLhTHLZVgff6s9lyBsI9KduSS83oj+34rTwJutmBmCnMsvozRwZqB5GTkBw6/jdPDu69iJ6BYk6eCcfbcgcQIK/MByaaiMqm8rHcjol2TnpWDhyAKSGdA3FrxtJUToX0ODqatetfGE+8tyEUOV8GY5dGRwLP/MBS4RHQr4bT7NRAQjlcOTfZxmv2G+c4hI8nn+Ax5PG/zhI393AAAAAElFTkSuQmCC');
24 - .tui-colorpicker-palette-preview
25 - border-radius: 100%;
26 - float: left;
27 - width: 17px;
28 - height: 17px;
29 - border: 0;
30 - .color-picker-control
31 - position: absolute;
32 - display: none;
33 - z-index: 99;
34 - width: 192px;
35 - background-color: #fff;
36 - box-shadow: 0 3px 22px 6px rgba(0, 0, 0, .15);
37 - padding: 16px;
38 - border-radius: 2px;
39 - .tui-colorpicker-palette-toggle-slider
40 - display: none;
41 - .tui-colorpicker-palette-button
42 - border: 0;
43 - border-radius: 100%;
44 - margin: 2px;
45 - background-size: cover;
46 - font-size: 1px;
47 - &[title='#ffffff']
48 - border: 1px solid #ccc;
49 - &[title='']
50 - border: 1px solid #ccc;
51 - .triangle
52 - width: 0;
53 - height: 0;
54 - border-right: 7px solid transparent;
55 - border-top: 8px solid #fff;
56 - border-left: 7px solid transparent;
57 - position: absolute;
58 - bottom: -8px;
59 - left: 84px;
60 - .tui-colorpicker-container,
61 - .tui-colorpicker-palette-container ul,
62 - .tui-colorpicker-palette-container
63 - width: 100%;
64 - height: auto;
65 -
66 -
67 - .filter-color-item
68 - .color-picker-control label
69 - font-color: #333;
70 - font-weight: normal;
71 - margin-right: 7pxleft
72 - .tui-image-editor-checkbox
73 - margin-top: 0;
74 - input + label:before,
75 - > label:before
76 - left: -16px;
77 - .color-picker
78 - width: 100%;
79 - height: auto;
80 - .color-picker-value
81 - width: 32px;
82 - height: 32px;
83 - border: 0px;
84 - border-radius: 100%;
85 - margin: auto;
86 - margin-bottom: 1px;
87 - &.transparent
88 - border: 1px solid #cbcbcb;
89 - background-size: cover;
90 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAdBJREFUWAnFl0FuwjAQRZ0ukiugHqFSOQNdseuKW3ALzkA4BateICvUGyCxrtRFd4WuunH/TzykaYJrnLEYaTJJsP2+x8GZZCbQrLU5mj7Bn+EP8HvnCObd+R7xBV5lWfaNON4AnsA38E94qLEt+0yiFaBzAV/Bv+Cxxr4co7hKCDpw1q9wLeNYYdlAwyn8TYt8Hme3+8D5ozcTaMCZ68PXa2tnM2sbEcOZAJhrrpl2DAcTOGNjZPSfCdzkw6JrfbiMv+osBe4y9WOedhm4jZfhbENWuxS44H9Wz/xw4WzqLOAqh1+zycgAwzEMzr5k5gaHOa9ULBwuuDkFlHI1Kl4PJ66kgIpnoywOTmRFAYcbwYk9UMApWkD8zAV5ihcwHk4Rx7gl0IFTQL0EFc+CTQ9OZHWH3YhlVJiVpTHbrTGLhTHLZVgff6s9lyBsI9KduSS83oj+34rTwJutmBmCnMsvozRwZqB5GTkBw6/jdPDu69iJ6BYk6eCcfbcgcQIK/MByaaiMqm8rHcjol2TnpWDhyAKSGdA3FrxtJUToX0ODqatetfGE+8tyEUOV8GY5dGRwLP/MBS4RHQr4bT7NRAQjlcOTfZxmv2G+c4hI8nn+Ax5PG/zhI393AAAAAElFTkSuQmCC');
91 -
92 - .color-picker-value + label
93 - color: #fff;
94 -
95 - .{prefix}-submenu svg > use
96 - display: none;
97 - .{prefix}-submenu svg > use.normal
98 - display: block;
1 -/* GRID VISUAL OF FLIP AND ROTATE MENU */
2 -.{prefix}-container
3 - .{prefix}-grid-visual
4 - display: none;
5 - position: absolute;
6 - width: 100%;
7 - height: 100%;
8 - border: 1px solid rgba(255,255,255,0.7);
9 - .{prefix}-main.{prefix}-menu-flip,
10 - .{prefix}-main.{prefix}-menu-rotate
11 - .tui-image-editor
12 - transition: none;
13 - .{prefix}-main.{prefix}-menu-flip .{prefix}-grid-visual,
14 - .{prefix}-main.{prefix}-menu-rotate .{prefix}-grid-visual
15 - display: block;
16 - .{prefix}-grid-visual
17 - table
18 - width: 100%;
19 - height: 100%;
20 - border-collapse: collapse;
21 - td
22 - border: 1px solid rgba(255,255,255,0.3);
23 - td.dot:before
24 - content: '';
25 - position: absolute;
26 - box-sizing: border-box;
27 - width: 10px;
28 - height: 10px;
29 - border: 0;
30 - box-shadow: 0 0 1px 0 rgba(0,0,0,0.3);
31 - border-radius: 100%;
32 - background-color: #fff;
33 - td.dot.left-top:before
34 - top: -5px;
35 - left: -5px;
36 - td.dot.right-top:before
37 - top: -5px;
38 - right: -5px;
39 - td.dot.left-bottom:before
40 - bottom: -5px;
41 - left: -5px;
42 - td.dot.right-bottom:before
43 - bottom: -5px;
44 - right: -5px;
1 -/* ICON */
2 -.{prefix}-container
3 - .tie-icon-add-button .{prefix}-button
4 - min-width: 42px;
5 - .svg_ic-menu
6 - .svg_ic-helpmenu
7 - width: 24px;
8 - height: 24px;
9 - .svg_ic-submenu
10 - width: 32px;
11 - height: 32px;
12 - .svg_img-bi
13 - width: 257px;
14 - height: 26px;
15 -
16 - .{prefix}-controls
17 - svg > use
18 - display: none;
19 - .enabled svg:hover > use.hover
20 - .normal svg:hover > use.hover
21 - display: block;
22 - .active svg:hover > use.hover
23 - display: none;
24 - svg > use.normal
25 - display: block;
26 - .active svg > use.active
27 - display: block;
28 - .enabled svg > use.enabled
29 - display: block;
30 - .active svg > use.normal,
31 - .enabled svg > use.normal
32 - display: none;
33 - .help svg > use.disabled,
34 - .help.enabled svg > use.normal
35 - display: block;
36 - .help.enabled svg > use.disabled
37 - display: none;
38 -
39 - .{prefix}-controls:hover
40 - z-index: 3;
1 -prefix = 'tui-image-editor'
2 -
3 -@import 'main.styl'
4 -@import 'gridtable.styl'
5 -@import 'submenu.styl'
6 -@import 'checkbox.styl'
7 -@import 'range.styl'
8 -@import 'position.styl'
9 -@import 'icon.styl'
10 -@import 'colorpicker.styl'
11 -@import 'buttons.styl'
12 -.{prefix}-container.top
13 - &.{prefix}-top-optimization
14 - .{prefix}-controls ul
15 - text-align: right;
16 - .{prefix}-controls-logo
17 - display: none;
1 -body > textarea
2 - position: fixed !important;
3 -
4 -+prefix-classes(prefix)
5 - .-container
6 - margin: 0;
7 - padding: 0;
8 - box-sizing: border-box;
9 - min-height: 300px;
10 - height: 100%;
11 - position: relative;
12 - background-color: #282828;
13 - overflow: hidden;
14 - letter-spacing: 0.3px;
15 -
16 - div, ul, label, input, li
17 - box-sizing: border-box;
18 - margin: 0;
19 - padding: 0;
20 - -ms-user-select: none;
21 - -moz-user-select: -moz-none;
22 - -khtml-user-select: none;
23 - -webkit-user-select: none;
24 - user-select: none;
25 -
26 - .-header
27 - /* BUTTON AND LOGO */
28 - min-width: 533px;
29 - position: absolute;
30 - background-color: #151515;
31 - top: 0;
32 - width: 100%;
33 - .-header-buttons,
34 - .-controls-buttons
35 - float: right;
36 - margin: 8px;
37 -
38 - .-header-logo,
39 - .-controls-logo
40 - float: left;
41 - width: 30%;
42 - padding: 17px;
43 -
44 - .-controls-logo,
45 - .-controls-buttons
46 - width: 270px;
47 - height: 100%;
48 - display: none;
49 -
50 - .-header-buttons button,
51 - .-header-buttons div,
52 - .-controls-buttons button,
53 - .-controls-buttons div
54 - display: inline-block;
55 - position: relative;
56 - width: 120px;
57 - height: 40px;
58 - padding: 0;
59 - line-height: 40px;
60 - outline: none;
61 - border-radius: 20px;
62 - border: 1px solid #ddd;
63 - font-family: 'Noto Sans', sans-serif;
64 - font-size: 12px;
65 - font-weight: bold;
66 - cursor: pointer;
67 - vertical-align: middle;
68 - letter-spacing: 0.3px;
69 - text-align: center;
70 -
71 - .-download-btn
72 - background-color: #fdba3b;
73 - border-color: #fdba3b;
74 - color: #fff;
75 - .-load-btn
76 - position: absolute;
77 - left: 0;
78 - right: 0;
79 - display: inline-block;
80 - top: 0;
81 - bottom: 0;
82 - width: 100%;
83 - cursor: pointer;
84 - opacity: 0;
85 - .-main-container
86 - position: absolute;
87 - width: 100%;
88 - top: 0;
89 - bottom: 64px;
90 - .-main
91 - position: absolute;
92 - text-align: center;
93 - top: 64px;
94 - bottom: 0;
95 - right: 0;
96 - left: 0;
97 - .-wrap
98 - position: absolute;
99 - bottom: 0;
100 - width: 100%;
101 - overflow: auto;
102 - .-size-wrap
103 - display: table;
104 - width: 100%;
105 - height: 100%
106 - .-align-wrap
107 - display: table-cell;
108 - vertical-align: middle;
109 - .
110 - position: relative;
111 - display: inline-block;
112 -
113 -
114 -/* BIG MENU */
115 -.{prefix}-container
116 - .{prefix}-menu
117 - width: auto;
118 - list-style: none;
119 - padding: 0;
120 - margin: 0 auto;
121 - display: table-cell;
122 - text-align: center;
123 - vertical-align: middle;
124 - white-space: nowrap;
125 - > .{prefix}-item
126 - position: relative;
127 - display: inline-block;
128 - border-radius: 2px;
129 - padding: 7px 8px 3px 8px;
130 - cursor: pointer;
131 - margin: 0 4px;
132 - > .{prefix}-item[tooltip-content]:hover
133 - &:before
134 - content: '';
135 - position: absolute;
136 - display: inline-block;
137 - margin: 0 auto 0;
138 - width: 0;
139 - height: 0;
140 - border-right: 7px solid transparent;
141 - border-top: 7px solid #2f2f2f;
142 - border-left: 7px solid transparent;
143 - left: 13px;
144 - top: -2px;
145 - &:after
146 - content: attr(tooltip-content);
147 - position: absolute;
148 - display: inline-block;
149 - background-color: #2f2f2f;
150 - color: #fff;
151 - padding: 5px 8px;
152 - font-size: 11px;
153 - font-weight: lighter;
154 - border-radius: 3px;
155 - max-height: 23px;
156 - top: -25px;
157 - left: 0;
158 - min-width: 24px;
159 - > .{prefix}-item.active
160 - background-color: #fff;
161 - transition: all .3s ease;
162 - .{prefix}-wrap
163 - position: absolute;
1 -/* POSITION LEFT */
2 -.{prefix}-container
3 - &.left
4 - .{prefix}-menu
5 - > .{prefix}-item[tooltip-content]
6 - &:before
7 - left: 28px;
8 - top: 11px;
9 - border-right: 7px solid #2f2f2f;
10 - border-top: 7px solid transparent;
11 - border-bottom: 7px solid transparent;
12 - &:after
13 - top: 7px;
14 - left: 42px;
15 - white-space: nowrap;
16 - .{prefix}-submenu
17 - left: 0;
18 - height: 100%;
19 - width: 248px;
20 - .{prefix}-main-container
21 - left: 64px;
22 - width: calc(100% - 64px);
23 - height: 100%;
24 - .{prefix}-controls
25 - width: 64px;
26 - height: 100%;
27 - display: table;
28 -
29 -/* POSITION LEFT & RIGHT */
30 -.{prefix}-container
31 - &.left, &.right
32 - .{prefix}-menu
33 - white-space: inherit;
34 - .{prefix}-submenu
35 - white-space: normal;
36 - > div
37 - vertical-align: middle;
38 - .{prefix}-controls li
39 - display: inline-block;
40 - margin: 4px auto;
41 - .{prefix}-icpartition
42 - position: relative;
43 - top: -7px;
44 - width: 24px;
45 - height: 1px;
46 - .{prefix}-submenu
47 - .{prefix}-partition
48 - display: block;
49 - width: 75%;
50 - margin: auto;
51 - > div
52 - border-left: 0;
53 - height:10px;
54 - border-bottom: 1px solid #3c3c3c;
55 - width: 100%;
56 - margin: 0;
57 - .{prefix}-submenu-align
58 - margin-right: 0;
59 - .{prefix}-submenu-item
60 - li
61 - margin-top: 15px;
62 - .tui-colorpicker-clearfix li
63 - margin-top: 0;
64 -
65 - .{prefix}-checkbox-wrap.fixed-width
66 - width: 182px;
67 - white-space: normal;
68 - .{prefix}-range-wrap.{prefix}-newline label.range
69 - display: block;
70 - text-align: left;
71 - width: 75%;
72 - margin: auto;
73 - .{prefix}-range
74 - width: 136px;
75 -
76 -
77 -/* POSITION RIGIHT */
78 -.{prefix}-container
79 - &.right
80 - .{prefix}-menu
81 - > .{prefix}-item[tooltip-content]
82 - &:before
83 - left: -3px;
84 - top: 11px;
85 - border-left: 7px solid #2f2f2f;
86 - border-top: 7px solid transparent;
87 - border-bottom: 7px solid transparent;
88 - &:after
89 - top: 7px;
90 - left: unset;
91 - right: 43px;
92 - white-space: nowrap;
93 - .{prefix}-submenu
94 - right: 0;
95 - height: 100%;
96 - width: 248px;
97 - .{prefix}-main-container
98 - right: 64px;
99 - width: calc(100% - 64px);
100 - height: 100%;
101 - .{prefix}-controls
102 - right: 0;
103 - width: 64px;
104 - height: 100%;
105 - display: table;
106 -
107 -
108 -/* POSITION TOP & BOTTOM */
109 -.{prefix}-container
110 - &.top, &.bottom
111 - .{prefix}-submenu
112 - .{prefix}-partition.only-left-right
113 - display: none;
114 -
115 -
116 -/* POSITION BOTTOM */
117 -.{prefix}-container
118 - &.bottom .tui-image-editor-submenu > div
119 - padding-bottom: 24px;
120 -
121 -/* POSITION TOP */
122 -.{prefix}-container
123 - &.top
124 - .color-picker-control .triangle
125 - top: -8px;
126 - border-right: 7px solid transparent;
127 - border-top: 0px;
128 - border-left: 7px solid transparent;
129 - border-bottom: 8px solid #fff;
130 - .{prefix}-size-wrap
131 - height: 100%;
132 - .{prefix}-main-container
133 - bottom: 0;
134 - .{prefix}-menu
135 - > .{prefix}-item[tooltip-content]
136 - &:before
137 - left: 13px;
138 - border-top: 0;
139 - border-bottom: 7px solid #2f2f2f;
140 - top: 33px;
141 - &:after
142 - top: 38px;
143 - .{prefix}-submenu
144 - top: 0;
145 - bottom: auto;
146 - > div
147 - padding-top: 24px;
148 - vertical-align: top;
149 - .{prefix}-controls-logo
150 - display: table-cell;
151 - .{prefix}-controls-buttons
152 - display: table-cell;
153 - .{prefix}-main
154 - top: 64px;
155 - height: calc(100% - 64px);
156 - .{prefix}-controls
157 - top: 0;
158 - bottom: inherit;
159 -
1 -/* VIRTUAL RANGE */
2 -.{prefix}-container
3 -
4 - .{prefix}-virtual-range-bar
5 - .{prefix}-virtual-range-subbar
6 - .{prefix}-virtual-range-pointer
7 - .{prefix}-disabled
8 - backbround-color: red;
9 -
10 - .{prefix}-range
11 - position: relative;
12 - top: 5px;
13 - width: 166px;
14 - height: 17px;
15 - display: inline-block;
16 - .{prefix}-virtual-range-bar
17 - top: 7px;
18 - position: absolute;
19 - width: 100%;
20 - height: 2px;
21 - background-color: #666666;
22 - .{prefix}-virtual-range-subbar
23 - position: absolute;
24 - height: 100%;
25 - left: 0;
26 - right: 0;
27 - background-color: #d1d1d1;
28 - .{prefix}-virtual-range-pointer
29 - position: absolute;
30 - cursor: pointer;
31 - top: -5px;
32 - left: 0;
33 - width: 12px;
34 - height: 12px;
35 - background-color: #fff;
36 - border-radius: 100%;
37 - .{prefix}-range-wrap
38 - display: inline-block;
39 - margin-left: 4px;
40 - &.short .tui-image-editor-range
41 - width: 100px;
42 - .color-picker-control
43 - .{prefix}-range
44 - width: 108px;
45 - margin-left: 10px;
46 - .{prefix}-virtual-range-pointer
47 - background-color: #333;
48 - .{prefix}-virtual-range-bar
49 - background-color: #ccc;
50 - .{prefix}-virtual-range-subbar
51 - background-color: #606060;
52 - .{prefix}-range-wrap.{prefix}-newline.short
53 - margin-top: -2px;
54 - margin-left: 19px;
55 - label
56 - color: #8e8e8e;
57 - font-weight: normal;
58 - .{prefix}-range-wrap label
59 - vertical-align: baseline;
60 - font-size: 11px;
61 - margin-right: 7px;
62 - color: #fff;
63 - .{prefix}-range-value
64 - cursor: default;
65 - width: 40px;
66 - height: 24px;
67 - outline: none;
68 - border-radius: 2px;
69 - box-shadow: none;
70 - border: 1px solid #d5d5d5;
71 - text-align: center;
72 - background-color: #1c1c1c;
73 - color: #fff;
74 - font-weight: lighter;
75 - vertical-align: baseline;
76 - font-family: 'Noto Sans', sans-serif;
77 - margin-top: 21px;
78 - margin-left: 4px;
79 - .{prefix}-controls
80 - position: absolute;
81 - background-color: #151515;
82 - width: 100%;
83 - height: 64px;
84 - display: table;
85 - bottom: 0;
86 - z-index: 2;
87 - .{prefix}-icpartition
88 - display: inline-block;
89 - background-color: #282828;
90 - width: 1px;
91 - height: 24px;
...\ No newline at end of file ...\ No newline at end of file
1 -/* SUBMENU */
2 -.{prefix}-container
3 - .{prefix}-submenu
4 - display: none;
5 - position: absolute;
6 - bottom: 0;
7 - width:100%;
8 - height: 150px;
9 - white-space: nowrap;
10 - z-index: 2;
11 - .{prefix}-button:hover svg > use.active
12 - display: block;
13 - .{prefix}-submenu-item
14 - li
15 - display: inline-block;
16 - vertical-align: top;
17 - .{prefix}-newline
18 - display: block;
19 - margin-top: 0;
20 - .{prefix}-button
21 - position: relative;
22 - cursor: pointer;
23 - display: inline-block;
24 - font-weight: normal;
25 - font-size: 11px;
26 - margin: 0 9px 0 9px;
27 - .{prefix}-button.preset
28 - margin: 0 9px 20px 5px;
29 - label > span
30 - display: inline-block;
31 - cursor: pointer;
32 - padding-top: 5px;
33 - font-family: "Noto Sans", sans-serif;
34 - font-size: 11px;
35 - .{prefix}-button.apply label,
36 - .{prefix}-button.cancel label
37 - vertical-align: 7px;
38 - > div
39 - display: none;
40 - vertical-align: bottom;
41 - .{prefix}-submenu-style
42 - opacity: 0.95;
43 - z-index: -1;
44 - position: absolute;
45 - top: 0;
46 - bottom: 0;
47 - left: 0;
48 - right: 0;
49 - display: block;
50 -
51 - .{prefix}-partition > div
52 - width: 1px;
53 - height: 52px;
54 - border-left: 1px solid #3c3c3c;
55 - margin: 0 8px 0 8px;
56 - .{prefix}-main.{prefix}-menu-filter .{prefix}-partition > div
57 - height: 108px;
58 - margin: 0 29px 0 0px;
59 - .{prefix}-submenu-align
60 - text-align: left;
61 - margin-right: 30px;
62 - label > span
63 - width: 55px;
64 - white-space: nowrap;
65 - .{prefix}-submenu-align:first-child
66 - margin-right: 0;
67 - label > span
68 - width: 70px;
69 - .{prefix}-main.{prefix}-menu-crop .{prefix}-submenu > div.{prefix}-menu-crop,
70 - .{prefix}-main.{prefix}-menu-flip .{prefix}-submenu > div.{prefix}-menu-flip,
71 - .{prefix}-main.{prefix}-menu-rotate .{prefix}-submenu > div.{prefix}-menu-rotate,
72 - .{prefix}-main.{prefix}-menu-shape .{prefix}-submenu > div.{prefix}-menu-shape,
73 - .{prefix}-main.{prefix}-menu-text .{prefix}-submenu > div.{prefix}-menu-text,
74 - .{prefix}-main.{prefix}-menu-mask .{prefix}-submenu > div.{prefix}-menu-mask,
75 - .{prefix}-main.{prefix}-menu-icon .{prefix}-submenu > div.{prefix}-menu-icon,
76 - .{prefix}-main.{prefix}-menu-draw .{prefix}-submenu > div.{prefix}-menu-draw,
77 - .{prefix}-main.{prefix}-menu-filter .{prefix}-submenu > div.{prefix}-menu-filter
78 - display: table-cell;
79 - .{prefix}-main.{prefix}-menu-crop,
80 - .{prefix}-main.{prefix}-menu-flip,
81 - .{prefix}-main.{prefix}-menu-rotate,
82 - .{prefix}-main.{prefix}-menu-shape,
83 - .{prefix}-main.{prefix}-menu-text,
84 - .{prefix}-main.{prefix}-menu-mask,
85 - .{prefix}-main.{prefix}-menu-icon,
86 - .{prefix}-main.{prefix}-menu-draw,
87 - .{prefix}-main.{prefix}-menu-filter
88 - .{prefix}-submenu
89 - display: table;
90 -
1 -import './js/polyfill'; 1 +/**
2 -import ImageEditor from './js/imageEditor'; 2 + * @fileoverview TOAST UI Image-Editor React wrapper component
3 -import './css/index.styl'; 3 + * @author NHN. FE Development Lab <dl_javascript@nhn.com>
4 - 4 + */
5 -// commands 5 +import React from 'react';
6 -import './js/command/addIcon'; 6 +import TuiImageEditor from 'tui-image-editor';
7 -import './js/command/addImageObject'; 7 +
8 -import './js/command/addObject'; 8 +export default class ImageEditor extends React.Component {
9 -import './js/command/addShape'; 9 + rootEl = React.createRef();
10 -import './js/command/addText'; 10 +
11 -import './js/command/applyFilter'; 11 + imageEditorInst = null;
12 -import './js/command/changeIconColor'; 12 +
13 -import './js/command/changeShape'; 13 + componentDidMount() {
14 -import './js/command/changeText'; 14 + this.imageEditorInst = new TuiImageEditor(this.rootEl.current, {
15 -import './js/command/changeTextStyle'; 15 + ...this.props
16 -import './js/command/clearObjects'; 16 + });
17 -import './js/command/flip'; 17 +
18 -import './js/command/loadImage'; 18 + this.bindEventHandlers(this.props);
19 -import './js/command/removeFilter'; 19 + }
20 -import './js/command/removeObject'; 20 +
21 -import './js/command/resizeCanvasDimension'; 21 + componentWillUnmount() {
22 -import './js/command/rotate'; 22 + this.unbindEventHandlers();
23 -import './js/command/setObjectProperties'; 23 +
24 -import './js/command/setObjectPosition'; 24 + this.imageEditorInst.destroy();
25 -import './js/command/changeSelection'; 25 +
26 - 26 + this.imageEditorInst = null;
27 -module.exports = ImageEditor; 27 + }
28 +
29 + shouldComponentUpdate(nextProps) {
30 + this.bindEventHandlers(this.props, nextProps);
31 +
32 + return false;
33 + }
34 +
35 + getInstance() {
36 + return this.imageEditorInst;
37 + }
38 +
39 + getRootElement() {
40 + return this.rootEl.current;
41 + }
42 +
43 + bindEventHandlers(props, prevProps) {
44 + Object.keys(props)
45 + .filter(this.isEventHandlerKeys)
46 + .forEach((key) => {
47 + const eventName = key[2].toLowerCase() + key.slice(3);
48 + // For <ImageEditor onFocus={condition ? onFocus1 : onFocus2} />
49 + if (prevProps && prevProps[key] !== props[key]) {
50 + this.imageEditorInst.off(eventName);
51 + }
52 + this.imageEditorInst.on(eventName, props[key]);
53 + });
54 + }
55 +
56 + unbindEventHandlers() {
57 + Object.keys(this.props)
58 + .filter(this.isEventHandlerKeys)
59 + .forEach((key) => {
60 + const eventName = key[2].toLowerCase() + key.slice(3);
61 + this.imageEditorInst.off(eventName);
62 + });
63 + }
64 +
65 + isEventHandlerKeys(key) {
66 + return /on[A-Z][a-zA-Z]+/.test(key);
67 + }
68 +
69 + render() {
70 + return <div ref={this.rootEl} />;
71 + }
72 +}
......
This diff is collapsed. Click to expand it.
1 -/**
2 - * @author NHN Ent. FE Development Team <dl_javascript@nhn.com>
3 - * @fileoverview Add an icon
4 - */
5 -import commandFactory from '../factory/command';
6 -import { Promise } from '../util';
7 -import { componentNames, commandNames } from '../consts';
8 -
9 -const { ICON } = componentNames;
10 -
11 -const command = {
12 - name: commandNames.ADD_ICON,
13 -
14 - /**
15 - * Add an icon
16 - * @param {Graphics} graphics - Graphics instance
17 - * @param {string} type - Icon type ('arrow', 'cancel', custom icon name)
18 - * @param {Object} options - Icon options
19 - * @param {string} [options.fill] - Icon foreground color
20 - * @param {string} [options.left] - Icon x position
21 - * @param {string} [options.top] - Icon y position
22 - * @returns {Promise}
23 - */
24 - execute(graphics, type, options) {
25 - const iconComp = graphics.getComponent(ICON);
26 -
27 - return iconComp.add(type, options).then((objectProps) => {
28 - this.undoData.object = graphics.getObject(objectProps.id);
29 -
30 - return objectProps;
31 - });
32 - },
33 - /**
34 - * @param {Graphics} graphics - Graphics instance
35 - * @returns {Promise}
36 - */
37 - undo(graphics) {
38 - graphics.remove(this.undoData.object);
39 -
40 - return Promise.resolve();
41 - },
42 -};
43 -
44 -commandFactory.register(command);
45 -
46 -export default command;
1 -/**
2 - * @author NHN Ent. FE Development Team <dl_javascript@nhn.com>
3 - * @fileoverview Add an image object
4 - */
5 -import commandFactory from '../factory/command';
6 -import { Promise } from '../util';
7 -import { commandNames } from '../consts';
8 -
9 -const command = {
10 - name: commandNames.ADD_IMAGE_OBJECT,
11 -
12 - /**
13 - * Add an image object
14 - * @param {Graphics} graphics - Graphics instance
15 - * @param {string} imgUrl - Image url to make object
16 - * @returns {Promise}
17 - */
18 - execute(graphics, imgUrl) {
19 - return graphics.addImageObject(imgUrl).then((objectProps) => {
20 - this.undoData.object = graphics.getObject(objectProps.id);
21 -
22 - return objectProps;
23 - });
24 - },
25 - /**
26 - * @param {Graphics} graphics - Graphics instance
27 - * @returns {Promise}
28 - */
29 - undo(graphics) {
30 - graphics.remove(this.undoData.object);
31 -
32 - return Promise.resolve();
33 - },
34 -};
35 -
36 -commandFactory.register(command);
37 -
38 -export default command;
1 -/**
2 - * @author NHN Ent. FE Development Team <dl_javascript@nhn.com>
3 - * @fileoverview Add an object
4 - */
5 -import commandFactory from '../factory/command';
6 -import { Promise } from '../util';
7 -import { commandNames, rejectMessages } from '../consts';
8 -
9 -const command = {
10 - name: commandNames.ADD_OBJECT,
11 -
12 - /**
13 - * Add an object
14 - * @param {Graphics} graphics - Graphics instance
15 - * @param {Object} object - Fabric object
16 - * @returns {Promise}
17 - */
18 - execute(graphics, object) {
19 - return new Promise((resolve, reject) => {
20 - if (!graphics.contains(object)) {
21 - graphics.add(object);
22 - resolve(object);
23 - } else {
24 - reject(rejectMessages.addedObject);
25 - }
26 - });
27 - },
28 - /**
29 - * @param {Graphics} graphics - Graphics instance
30 - * @param {Object} object - Fabric object
31 - * @returns {Promise}
32 - */
33 - undo(graphics, object) {
34 - return new Promise((resolve, reject) => {
35 - if (graphics.contains(object)) {
36 - graphics.remove(object);
37 - resolve(object);
38 - } else {
39 - reject(rejectMessages.noObject);
40 - }
41 - });
42 - },
43 -};
44 -
45 -commandFactory.register(command);
46 -
47 -export default command;
1 -/**
2 - * @author NHN Ent. FE Development Team <dl_javascript@nhn.com>
3 - * @fileoverview Add a shape
4 - */
5 -import commandFactory from '../factory/command';
6 -import { Promise } from '../util';
7 -import { componentNames, commandNames } from '../consts';
8 -
9 -const { SHAPE } = componentNames;
10 -
11 -const command = {
12 - name: commandNames.ADD_SHAPE,
13 -
14 - /**
15 - * Add a shape
16 - * @param {Graphics} graphics - Graphics instance
17 - * @param {string} type - Shape type (ex: 'rect', 'circle', 'triangle')
18 - * @param {Object} options - Shape options
19 - * @param {string} [options.fill] - Shape foreground color (ex: '#fff', 'transparent')
20 - * @param {string} [options.stroke] - Shape outline color
21 - * @param {number} [options.strokeWidth] - Shape outline width
22 - * @param {number} [options.width] - Width value (When type option is 'rect', this options can use)
23 - * @param {number} [options.height] - Height value (When type option is 'rect', this options can use)
24 - * @param {number} [options.rx] - Radius x value (When type option is 'circle', this options can use)
25 - * @param {number} [options.ry] - Radius y value (When type option is 'circle', this options can use)
26 - * @param {number} [options.left] - Shape x position
27 - * @param {number} [options.top] - Shape y position
28 - * @param {number} [options.isRegular] - Whether resizing shape has 1:1 ratio or not
29 - * @returns {Promise}
30 - */
31 - execute(graphics, type, options) {
32 - const shapeComp = graphics.getComponent(SHAPE);
33 -
34 - return shapeComp.add(type, options).then((objectProps) => {
35 - this.undoData.object = graphics.getObject(objectProps.id);
36 -
37 - return objectProps;
38 - });
39 - },
40 - /**
41 - * @param {Graphics} graphics - Graphics instance
42 - * @returns {Promise}
43 - */
44 - undo(graphics) {
45 - graphics.remove(this.undoData.object);
46 -
47 - return Promise.resolve();
48 - },
49 -};
50 -
51 -commandFactory.register(command);
52 -
53 -export default command;
1 -/**
2 - * @author NHN Ent. FE Development Team <dl_javascript@nhn.com>
3 - * @fileoverview Add a text object
4 - */
5 -import commandFactory from '../factory/command';
6 -import { Promise } from '../util';
7 -import { componentNames, commandNames, rejectMessages } from '../consts';
8 -const { TEXT } = componentNames;
9 -
10 -const command = {
11 - name: commandNames.ADD_TEXT,
12 -
13 - /**
14 - * Add a text object
15 - * @param {Graphics} graphics - Graphics instance
16 - * @param {string} text - Initial input text
17 - * @param {Object} [options] Options for text styles
18 - * @param {Object} [options.styles] Initial styles
19 - * @param {string} [options.styles.fill] Color
20 - * @param {string} [options.styles.fontFamily] Font type for text
21 - * @param {number} [options.styles.fontSize] Size
22 - * @param {string} [options.styles.fontStyle] Type of inclination (normal / italic)
23 - * @param {string} [options.styles.fontWeight] Type of thicker or thinner looking (normal / bold)
24 - * @param {string} [options.styles.textAlign] Type of text align (left / center / right)
25 - * @param {string} [options.styles.textDecoration] Type of line (underline / line-through / overline)
26 - * @param {{x: number, y: number}} [options.position] - Initial position
27 - * @returns {Promise}
28 - */
29 - execute(graphics, text, options) {
30 - const textComp = graphics.getComponent(TEXT);
31 -
32 - if (this.undoData.object) {
33 - const undoObject = this.undoData.object;
34 -
35 - return new Promise((resolve, reject) => {
36 - if (!graphics.contains(undoObject)) {
37 - graphics.add(undoObject);
38 - resolve(undoObject);
39 - } else {
40 - reject(rejectMessages.redo);
41 - }
42 - });
43 - }
44 -
45 - return textComp.add(text, options).then((objectProps) => {
46 - const { id } = objectProps;
47 - const textObject = graphics.getObject(id);
48 -
49 - this.undoData.object = textObject;
50 -
51 - return objectProps;
52 - });
53 - },
54 - /**
55 - * @param {Graphics} graphics - Graphics instance
56 - * @returns {Promise}
57 - */
58 - undo(graphics) {
59 - graphics.remove(this.undoData.object);
60 -
61 - return Promise.resolve();
62 - },
63 -};
64 -
65 -commandFactory.register(command);
66 -
67 -export default command;
1 -/**
2 - * @author NHN Ent. FE Development Team <dl_javascript@nhn.com>
3 - * @fileoverview Apply a filter into an image
4 - */
5 -import snippet from 'tui-code-snippet';
6 -import commandFactory from '../factory/command';
7 -import { componentNames, rejectMessages, commandNames } from '../consts';
8 -
9 -const { FILTER } = componentNames;
10 -
11 -/**
12 - * Chched data for undo
13 - * @type {Object}
14 - */
15 -let chchedUndoDataForSilent = null;
16 -
17 -/**
18 - * Make undoData
19 - * @param {string} type - Filter type
20 - * @param {Object} prevfilterOption - prev Filter options
21 - * @param {Object} options - Filter options
22 - * @returns {object} - undo data
23 - */
24 -function makeUndoData(type, prevfilterOption, options) {
25 - const undoData = {};
26 -
27 - if (type === 'mask') {
28 - undoData.object = options.mask;
29 - }
30 -
31 - undoData.options = prevfilterOption;
32 -
33 - return undoData;
34 -}
35 -
36 -const command = {
37 - name: commandNames.APPLY_FILTER,
38 -
39 - /**
40 - * Apply a filter into an image
41 - * @param {Graphics} graphics - Graphics instance
42 - * @param {string} type - Filter type
43 - * @param {Object} options - Filter options
44 - * @param {number} options.maskObjId - masking image object id
45 - * @param {boolean} isSilent - is silent execution or not
46 - * @returns {Promise}
47 - */
48 - execute(graphics, type, options, isSilent) {
49 - const filterComp = graphics.getComponent(FILTER);
50 -
51 - if (type === 'mask') {
52 - const maskObj = graphics.getObject(options.maskObjId);
53 -
54 - if (!(maskObj && maskObj.isType('image'))) {
55 - return Promise.reject(rejectMessages.invalidParameters);
56 - }
57 -
58 - snippet.extend(options, { mask: maskObj });
59 - graphics.remove(options.mask);
60 - }
61 - if (!this.isRedo) {
62 - const prevfilterOption = filterComp.getOptions(type);
63 - const undoData = makeUndoData(type, prevfilterOption, options);
64 -
65 - chchedUndoDataForSilent = this.setUndoData(undoData, chchedUndoDataForSilent, isSilent);
66 - }
67 -
68 - return filterComp.add(type, options);
69 - },
70 - /**
71 - * @param {Graphics} graphics - Graphics instance
72 - * @param {string} type - Filter type
73 - * @returns {Promise}
74 - */
75 - undo(graphics, type) {
76 - const filterComp = graphics.getComponent(FILTER);
77 -
78 - if (type === 'mask') {
79 - const mask = this.undoData.object;
80 - graphics.add(mask);
81 - graphics.setActiveObject(mask);
82 -
83 - return filterComp.remove(type);
84 - }
85 -
86 - // options changed case
87 - if (this.undoData.options) {
88 - return filterComp.add(type, this.undoData.options);
89 - }
90 -
91 - // filter added case
92 - return filterComp.remove(type);
93 - },
94 -};
95 -
96 -commandFactory.register(command);
97 -
98 -export default command;
1 -/**
2 - * @author NHN Ent. FE Development Team <dl_javascript@nhn.com>
3 - * @fileoverview Change icon color
4 - */
5 -import commandFactory from '../factory/command';
6 -import { Promise } from '../util';
7 -import { componentNames, rejectMessages, commandNames } from '../consts';
8 -
9 -const { ICON } = componentNames;
10 -
11 -const command = {
12 - name: commandNames.CHANGE_ICON_COLOR,
13 -
14 - /**
15 - * Change icon color
16 - * @param {Graphics} graphics - Graphics instance
17 - * @param {number} id - object id
18 - * @param {string} color - Color for icon
19 - * @returns {Promise}
20 - */
21 - execute(graphics, id, color) {
22 - return new Promise((resolve, reject) => {
23 - const iconComp = graphics.getComponent(ICON);
24 - const targetObj = graphics.getObject(id);
25 -
26 - if (!targetObj) {
27 - reject(rejectMessages.noObject);
28 - }
29 -
30 - this.undoData.object = targetObj;
31 - this.undoData.color = iconComp.getColor(targetObj);
32 - iconComp.setColor(color, targetObj);
33 - resolve();
34 - });
35 - },
36 - /**
37 - * @param {Graphics} graphics - Graphics instance
38 - * @returns {Promise}
39 - */
40 - undo(graphics) {
41 - const iconComp = graphics.getComponent(ICON);
42 - const { object: icon, color } = this.undoData;
43 -
44 - iconComp.setColor(color, icon);
45 -
46 - return Promise.resolve();
47 - },
48 -};
49 -
50 -commandFactory.register(command);
51 -
52 -export default command;
1 -/**
2 - * @author NHN. FE Development Team <dl_javascript@nhn.com>
3 - * @fileoverview change selection
4 - */
5 -import commandFactory from '../factory/command';
6 -import { Promise } from '../util';
7 -import { commandNames } from '../consts';
8 -import { getCachedUndoDataForDimension } from '../helper/selectionModifyHelper';
9 -
10 -const command = {
11 - name: commandNames.CHANGE_SELECTION,
12 -
13 - execute(graphics, props) {
14 - if (this.isRedo) {
15 - props.forEach((prop) => {
16 - graphics.setObjectProperties(prop.id, prop);
17 - });
18 - } else {
19 - this.undoData = getCachedUndoDataForDimension();
20 - }
21 -
22 - return Promise.resolve();
23 - },
24 - undo(graphics) {
25 - this.undoData.forEach((datum) => {
26 - graphics.setObjectProperties(datum.id, datum);
27 - });
28 -
29 - return Promise.resolve();
30 - },
31 -};
32 -
33 -commandFactory.register(command);
34 -
35 -export default command;
1 -/**
2 - * @author NHN Ent. FE Development Team <dl_javascript@nhn.com>
3 - * @fileoverview change a shape
4 - */
5 -import snippet from 'tui-code-snippet';
6 -import { Promise } from '../util';
7 -import commandFactory from '../factory/command';
8 -import { componentNames, rejectMessages, commandNames } from '../consts';
9 -
10 -const { SHAPE } = componentNames;
11 -
12 -/**
13 - * Chched data for undo
14 - * @type {Object}
15 - */
16 -let chchedUndoDataForSilent = null;
17 -
18 -/**
19 - * Make undoData
20 - * @param {object} options - shape options
21 - * @param {Component} targetObj - shape component
22 - * @returns {object} - undo data
23 - */
24 -function makeUndoData(options, targetObj) {
25 - const undoData = {
26 - object: targetObj,
27 - options: {},
28 - };
29 -
30 - snippet.forEachOwnProperties(options, (value, key) => {
31 - undoData.options[key] = targetObj[key];
32 - });
33 -
34 - return undoData;
35 -}
36 -
37 -const command = {
38 - name: commandNames.CHANGE_SHAPE,
39 -
40 - /**
41 - * Change a shape
42 - * @param {Graphics} graphics - Graphics instance
43 - * @param {number} id - object id
44 - * @param {Object} options - Shape options
45 - * @param {string} [options.fill] - Shape foreground color (ex: '#fff', 'transparent')
46 - * @param {string} [options.stroke] - Shape outline color
47 - * @param {number} [options.strokeWidth] - Shape outline width
48 - * @param {number} [options.width] - Width value (When type option is 'rect', this options can use)
49 - * @param {number} [options.height] - Height value (When type option is 'rect', this options can use)
50 - * @param {number} [options.rx] - Radius x value (When type option is 'circle', this options can use)
51 - * @param {number} [options.ry] - Radius y value (When type option is 'circle', this options can use)
52 - * @param {number} [options.left] - Shape x position
53 - * @param {number} [options.top] - Shape y position
54 - * @param {number} [options.isRegular] - Whether resizing shape has 1:1 ratio or not
55 - * @param {boolean} isSilent - is silent execution or not
56 - * @returns {Promise}
57 - */
58 - execute(graphics, id, options, isSilent) {
59 - const shapeComp = graphics.getComponent(SHAPE);
60 - const targetObj = graphics.getObject(id);
61 -
62 - if (!targetObj) {
63 - return Promise.reject(rejectMessages.noObject);
64 - }
65 -
66 - if (!this.isRedo) {
67 - const undoData = makeUndoData(options, targetObj);
68 -
69 - chchedUndoDataForSilent = this.setUndoData(undoData, chchedUndoDataForSilent, isSilent);
70 - }
71 -
72 - return shapeComp.change(targetObj, options);
73 - },
74 - /**
75 - * @param {Graphics} graphics - Graphics instance
76 - * @returns {Promise}
77 - */
78 - undo(graphics) {
79 - const shapeComp = graphics.getComponent(SHAPE);
80 - const { object: shape, options } = this.undoData;
81 -
82 - return shapeComp.change(shape, options);
83 - },
84 -};
85 -
86 -commandFactory.register(command);
87 -
88 -export default command;
1 -/**
2 - * @author NHN Ent. FE Development Team <dl_javascript@nhn.com>
3 - * @fileoverview Change a text
4 - */
5 -import commandFactory from '../factory/command';
6 -import { Promise } from '../util';
7 -import { componentNames, rejectMessages, commandNames } from '../consts';
8 -
9 -const { TEXT } = componentNames;
10 -
11 -const command = {
12 - name: commandNames.CHANGE_TEXT,
13 -
14 - /**
15 - * Change a text
16 - * @param {Graphics} graphics - Graphics instance
17 - * @param {number} id - object id
18 - * @param {string} text - Changing text
19 - * @returns {Promise}
20 - */
21 - execute(graphics, id, text) {
22 - const textComp = graphics.getComponent(TEXT);
23 - const targetObj = graphics.getObject(id);
24 -
25 - if (!targetObj) {
26 - return Promise.reject(rejectMessages.noObject);
27 - }
28 -
29 - this.undoData.object = targetObj;
30 - this.undoData.text = textComp.getText(targetObj);
31 -
32 - return textComp.change(targetObj, text);
33 - },
34 - /**
35 - * @param {Graphics} graphics - Graphics instance
36 - * @returns {Promise}
37 - */
38 - undo(graphics) {
39 - const textComp = graphics.getComponent(TEXT);
40 - const { object: textObj, text } = this.undoData;
41 -
42 - return textComp.change(textObj, text);
43 - },
44 -};
45 -
46 -commandFactory.register(command);
47 -
48 -export default command;
1 -/**
2 - * @author NHN Ent. FE Development Team <dl_javascript@nhn.com>
3 - * @fileoverview Change text styles
4 - */
5 -import snippet from 'tui-code-snippet';
6 -import commandFactory from '../factory/command';
7 -import { Promise } from '../util';
8 -import { componentNames, rejectMessages, commandNames } from '../consts';
9 -
10 -const { TEXT } = componentNames;
11 -
12 -/**
13 - * Chched data for undo
14 - * @type {Object}
15 - */
16 -let chchedUndoDataForSilent = null;
17 -
18 -/**
19 - * Make undoData
20 - * @param {object} styles - text styles
21 - * @param {Component} targetObj - text component
22 - * @returns {object} - undo data
23 - */
24 -function makeUndoData(styles, targetObj) {
25 - const undoData = {
26 - object: targetObj,
27 - styles: {},
28 - };
29 - snippet.forEachOwnProperties(styles, (value, key) => {
30 - const undoValue = targetObj[key];
31 - undoData.styles[key] = undoValue;
32 - });
33 -
34 - return undoData;
35 -}
36 -
37 -const command = {
38 - name: commandNames.CHANGE_TEXT_STYLE,
39 -
40 - /**
41 - * Change text styles
42 - * @param {Graphics} graphics - Graphics instance
43 - * @param {number} id - object id
44 - * @param {Object} styles - text styles
45 - * @param {string} [styles.fill] Color
46 - * @param {string} [styles.fontFamily] Font type for text
47 - * @param {number} [styles.fontSize] Size
48 - * @param {string} [styles.fontStyle] Type of inclination (normal / italic)
49 - * @param {string} [styles.fontWeight] Type of thicker or thinner looking (normal / bold)
50 - * @param {string} [styles.textAlign] Type of text align (left / center / right)
51 - * @param {string} [styles.textDecoration] Type of line (underline / line-through / overline)
52 - * @param {boolean} isSilent - is silent execution or not
53 - * @returns {Promise}
54 - */
55 - execute(graphics, id, styles, isSilent) {
56 - const textComp = graphics.getComponent(TEXT);
57 - const targetObj = graphics.getObject(id);
58 -
59 - if (!targetObj) {
60 - return Promise.reject(rejectMessages.noObject);
61 - }
62 - if (!this.isRedo) {
63 - const undoData = makeUndoData(styles, targetObj);
64 -
65 - chchedUndoDataForSilent = this.setUndoData(undoData, chchedUndoDataForSilent, isSilent);
66 - }
67 -
68 - return textComp.setStyle(targetObj, styles);
69 - },
70 - /**
71 - * @param {Graphics} graphics - Graphics instance
72 - * @returns {Promise}
73 - */
74 - undo(graphics) {
75 - const textComp = graphics.getComponent(TEXT);
76 - const { object: textObj, styles } = this.undoData;
77 -
78 - return textComp.setStyle(textObj, styles);
79 - },
80 -};
81 -
82 -commandFactory.register(command);
83 -
84 -export default command;
1 -/**
2 - * @author NHN Ent. FE Development Team <dl_javascript@nhn.com>
3 - * @fileoverview Clear all objects
4 - */
5 -import commandFactory from '../factory/command';
6 -import { Promise } from '../util';
7 -import { commandNames } from '../consts';
8 -
9 -const command = {
10 - name: commandNames.CLEAR_OBJECTS,
11 -
12 - /**
13 - * Clear all objects without background (main) image
14 - * @param {Graphics} graphics - Graphics instance
15 - * @returns {Promise}
16 - */
17 - execute(graphics) {
18 - return new Promise((resolve) => {
19 - this.undoData.objects = graphics.removeAll();
20 - resolve();
21 - });
22 - },
23 - /**
24 - * @param {Graphics} graphics - Graphics instance
25 - * @returns {Promise}
26 - * @ignore
27 - */
28 - undo(graphics) {
29 - graphics.add(this.undoData.objects);
30 -
31 - return Promise.resolve();
32 - },
33 -};
34 -
35 -commandFactory.register(command);
36 -
37 -export default command;
1 -/**
2 - * @author NHN Ent. FE Development Team <dl_javascript@nhn.com>
3 - * @fileoverview Flip an image
4 - */
5 -import commandFactory from '../factory/command';
6 -import { componentNames, commandNames } from '../consts';
7 -
8 -const { FLIP } = componentNames;
9 -
10 -const command = {
11 - name: commandNames.FLIP_IMAGE,
12 -
13 - /**
14 - * flip an image
15 - * @param {Graphics} graphics - Graphics instance
16 - * @param {string} type - 'flipX' or 'flipY' or 'reset'
17 - * @returns {Promise}
18 - */
19 - execute(graphics, type) {
20 - const flipComp = graphics.getComponent(FLIP);
21 -
22 - this.undoData.setting = flipComp.getCurrentSetting();
23 -
24 - return flipComp[type]();
25 - },
26 - /**
27 - * @param {Graphics} graphics - Graphics instance
28 - * @returns {Promise}
29 - */
30 - undo(graphics) {
31 - const flipComp = graphics.getComponent(FLIP);
32 -
33 - return flipComp.set(this.undoData.setting);
34 - },
35 -};
36 -
37 -commandFactory.register(command);
38 -
39 -export default command;
1 -/**
2 - * @author NHN Ent. FE Development Team <dl_javascript@nhn.com>
3 - * @fileoverview Load a background (main) image
4 - */
5 -import commandFactory from '../factory/command';
6 -import { componentNames, commandNames } from '../consts';
7 -
8 -const { IMAGE_LOADER } = componentNames;
9 -
10 -const command = {
11 - name: commandNames.LOAD_IMAGE,
12 -
13 - /**
14 - * Load a background (main) image
15 - * @param {Graphics} graphics - Graphics instance
16 - * @param {string} imageName - Image name
17 - * @param {string} imgUrl - Image Url
18 - * @returns {Promise}
19 - */
20 - execute(graphics, imageName, imgUrl) {
21 - const loader = graphics.getComponent(IMAGE_LOADER);
22 - const prevImage = loader.getCanvasImage();
23 - const prevImageWidth = prevImage ? prevImage.width : 0;
24 - const prevImageHeight = prevImage ? prevImage.height : 0;
25 - const objects = graphics.removeAll(true).filter((objectItem) => objectItem.type !== 'cropzone');
26 -
27 - objects.forEach((objectItem) => {
28 - objectItem.evented = true;
29 - });
30 -
31 - this.undoData = {
32 - name: loader.getImageName(),
33 - image: prevImage,
34 - objects,
35 - };
36 -
37 - return loader.load(imageName, imgUrl).then((newImage) => ({
38 - oldWidth: prevImageWidth,
39 - oldHeight: prevImageHeight,
40 - newWidth: newImage.width,
41 - newHeight: newImage.height,
42 - }));
43 - },
44 -
45 - /**
46 - * @param {Graphics} graphics - Graphics instance
47 - * @returns {Promise}
48 - */
49 - undo(graphics) {
50 - const loader = graphics.getComponent(IMAGE_LOADER);
51 - const { objects, name, image } = this.undoData;
52 -
53 - graphics.removeAll(true);
54 - graphics.add(objects);
55 -
56 - return loader.load(name, image);
57 - },
58 -};
59 -
60 -commandFactory.register(command);
61 -
62 -export default command;
1 -/**
2 - * @author NHN Ent. FE Development Team <dl_javascript@nhn.com>
3 - * @fileoverview Remove a filter from an image
4 - */
5 -import commandFactory from '../factory/command';
6 -import { componentNames, commandNames } from '../consts';
7 -
8 -const { FILTER } = componentNames;
9 -
10 -const command = {
11 - name: commandNames.REMOVE_FILTER,
12 -
13 - /**
14 - * Remove a filter from an image
15 - * @param {Graphics} graphics - Graphics instance
16 - * @param {string} type - Filter type
17 - * @returns {Promise}
18 - */
19 - execute(graphics, type) {
20 - const filterComp = graphics.getComponent(FILTER);
21 -
22 - this.undoData.options = filterComp.getOptions(type);
23 -
24 - return filterComp.remove(type);
25 - },
26 - /**
27 - * @param {Graphics} graphics - Graphics instance
28 - * @param {string} type - Filter type
29 - * @returns {Promise}
30 - */
31 - undo(graphics, type) {
32 - const filterComp = graphics.getComponent(FILTER);
33 - const { options } = this.undoData;
34 -
35 - return filterComp.add(type, options);
36 - },
37 -};
38 -
39 -commandFactory.register(command);
40 -
41 -export default command;
1 -/**
2 - * @author NHN Ent. FE Development Team <dl_javascript@nhn.com>
3 - * @fileoverview Remove an object
4 - */
5 -import commandFactory from '../factory/command';
6 -import { Promise } from '../util';
7 -import { commandNames, rejectMessages } from '../consts';
8 -
9 -const command = {
10 - name: commandNames.REMOVE_OBJECT,
11 -
12 - /**
13 - * Remove an object
14 - * @param {Graphics} graphics - Graphics instance
15 - * @param {number} id - object id
16 - * @returns {Promise}
17 - */
18 - execute(graphics, id) {
19 - return new Promise((resolve, reject) => {
20 - this.undoData.objects = graphics.removeObjectById(id);
21 - if (this.undoData.objects.length) {
22 - resolve();
23 - } else {
24 - reject(rejectMessages.noObject);
25 - }
26 - });
27 - },
28 - /**
29 - * @param {Graphics} graphics - Graphics instance
30 - * @returns {Promise}
31 - */
32 - undo(graphics) {
33 - graphics.add(this.undoData.objects);
34 -
35 - return Promise.resolve();
36 - },
37 -};
38 -
39 -commandFactory.register(command);
40 -
41 -export default command;
1 -/**
2 - * @author NHN Ent. FE Development Team <dl_javascript@nhn.com>
3 - * @fileoverview Resize a canvas
4 - */
5 -import commandFactory from '../factory/command';
6 -import { Promise } from '../util';
7 -import { commandNames } from '../consts';
8 -
9 -const command = {
10 - name: commandNames.RESIZE_CANVAS_DIMENSION,
11 -
12 - /**
13 - * resize the canvas with given dimension
14 - * @param {Graphics} graphics - Graphics instance
15 - * @param {{width: number, height: number}} dimension - Max width & height
16 - * @returns {Promise}
17 - */
18 - execute(graphics, dimension) {
19 - return new Promise((resolve) => {
20 - this.undoData.size = {
21 - width: graphics.cssMaxWidth,
22 - height: graphics.cssMaxHeight,
23 - };
24 -
25 - graphics.setCssMaxDimension(dimension);
26 - graphics.adjustCanvasDimension();
27 - resolve();
28 - });
29 - },
30 - /**
31 - * @param {Graphics} graphics - Graphics instance
32 - * @returns {Promise}
33 - */
34 - undo(graphics) {
35 - graphics.setCssMaxDimension(this.undoData.size);
36 - graphics.adjustCanvasDimension();
37 -
38 - return Promise.resolve();
39 - },
40 -};
41 -
42 -commandFactory.register(command);
43 -
44 -export default command;
1 -/**
2 - * @author NHN Ent. FE Development Team <dl_javascript@nhn.com>
3 - * @fileoverview Rotate an image
4 - */
5 -import commandFactory from '../factory/command';
6 -import { componentNames, commandNames } from '../consts';
7 -
8 -const { ROTATION } = componentNames;
9 -
10 -/**
11 - * Chched data for undo
12 - * @type {Object}
13 - */
14 -let chchedUndoDataForSilent = null;
15 -
16 -/**
17 - * Make undo data
18 - * @param {Component} rotationComp - rotation component
19 - * @returns {object} - undodata
20 - */
21 -function makeUndoData(rotationComp) {
22 - return {
23 - angle: rotationComp.getCurrentAngle(),
24 - };
25 -}
26 -
27 -const command = {
28 - name: commandNames.ROTATE_IMAGE,
29 -
30 - /**
31 - * Rotate an image
32 - * @param {Graphics} graphics - Graphics instance
33 - * @param {string} type - 'rotate' or 'setAngle'
34 - * @param {number} angle - angle value (degree)
35 - * @param {boolean} isSilent - is silent execution or not
36 - * @returns {Promise}
37 - */
38 - execute(graphics, type, angle, isSilent) {
39 - const rotationComp = graphics.getComponent(ROTATION);
40 -
41 - if (!this.isRedo) {
42 - const undoData = makeUndoData(rotationComp);
43 -
44 - chchedUndoDataForSilent = this.setUndoData(undoData, chchedUndoDataForSilent, isSilent);
45 - }
46 -
47 - return rotationComp[type](angle);
48 - },
49 - /**
50 - * @param {Graphics} graphics - Graphics instance
51 - * @returns {Promise}
52 - */
53 - undo(graphics) {
54 - const rotationComp = graphics.getComponent(ROTATION);
55 - const [, type, angle] = this.args;
56 -
57 - if (type === 'setAngle') {
58 - return rotationComp[type](this.undoData.angle);
59 - }
60 -
61 - return rotationComp.rotate(-angle);
62 - },
63 -};
64 -
65 -commandFactory.register(command);
66 -
67 -export default command;
1 -/**
2 - * @author NHN Ent. FE Development Team <dl_javascript@nhn.com>
3 - * @fileoverview Set object properties
4 - */
5 -import commandFactory from '../factory/command';
6 -import { Promise } from '../util';
7 -import { commandNames, rejectMessages } from '../consts';
8 -
9 -const command = {
10 - name: commandNames.SET_OBJECT_POSITION,
11 -
12 - /**
13 - * Set object properties
14 - * @param {Graphics} graphics - Graphics instance
15 - * @param {number} id - object id
16 - * @param {Object} posInfo - position object
17 - * @param {number} posInfo.x - x position
18 - * @param {number} posInfo.y - y position
19 - * @param {string} posInfo.originX - can be 'left', 'center', 'right'
20 - * @param {string} posInfo.originY - can be 'top', 'center', 'bottom'
21 - * @returns {Promise}
22 - */
23 - execute(graphics, id, posInfo) {
24 - const targetObj = graphics.getObject(id);
25 -
26 - if (!targetObj) {
27 - return Promise.reject(rejectMessages.noObject);
28 - }
29 -
30 - this.undoData.objectId = id;
31 - this.undoData.props = graphics.getObjectProperties(id, ['left', 'top']);
32 -
33 - graphics.setObjectPosition(id, posInfo);
34 - graphics.renderAll();
35 -
36 - return Promise.resolve();
37 - },
38 - /**
39 - * @param {Graphics} graphics - Graphics instance
40 - * @returns {Promise}
41 - */
42 - undo(graphics) {
43 - const { objectId, props } = this.undoData;
44 -
45 - graphics.setObjectProperties(objectId, props);
46 - graphics.renderAll();
47 -
48 - return Promise.resolve();
49 - },
50 -};
51 -
52 -commandFactory.register(command);
53 -
54 -export default command;
1 -/**
2 - * @author NHN Ent. FE Development Team <dl_javascript@nhn.com>
3 - * @fileoverview Set object properties
4 - */
5 -import snippet from 'tui-code-snippet';
6 -import commandFactory from '../factory/command';
7 -import { Promise } from '../util';
8 -import { commandNames, rejectMessages } from '../consts';
9 -
10 -const command = {
11 - name: commandNames.SET_OBJECT_PROPERTIES,
12 -
13 - /**
14 - * Set object properties
15 - * @param {Graphics} graphics - Graphics instance
16 - * @param {number} id - object id
17 - * @param {Object} props - properties
18 - * @param {string} [props.fill] Color
19 - * @param {string} [props.fontFamily] Font type for text
20 - * @param {number} [props.fontSize] Size
21 - * @param {string} [props.fontStyle] Type of inclination (normal / italic)
22 - * @param {string} [props.fontWeight] Type of thicker or thinner looking (normal / bold)
23 - * @param {string} [props.textAlign] Type of text align (left / center / right)
24 - * @param {string} [props.textDecoration] Type of line (underline / line-through / overline)
25 - * @returns {Promise}
26 - */
27 - execute(graphics, id, props) {
28 - const targetObj = graphics.getObject(id);
29 -
30 - if (!targetObj) {
31 - return Promise.reject(rejectMessages.noObject);
32 - }
33 -
34 - this.undoData.props = {};
35 - snippet.forEachOwnProperties(props, (value, key) => {
36 - this.undoData.props[key] = targetObj[key];
37 - });
38 -
39 - graphics.setObjectProperties(id, props);
40 -
41 - return Promise.resolve();
42 - },
43 - /**
44 - * @param {Graphics} graphics - Graphics instance
45 - * @param {number} id - object id
46 - * @returns {Promise}
47 - */
48 - undo(graphics, id) {
49 - const { props } = this.undoData;
50 -
51 - graphics.setObjectProperties(id, props);
52 -
53 - return Promise.resolve();
54 - },
55 -};
56 -
57 -commandFactory.register(command);
58 -
59 -export default command;
1 -/**
2 - * @author NHN Ent. FE Development Team <dl_javascript@nhn.com>
3 - * @fileoverview Image crop module (start cropping, end cropping)
4 - */
5 -import snippet from 'tui-code-snippet';
6 -import fabric from 'fabric';
7 -import Component from '../interface/component';
8 -import Cropzone from '../extension/cropzone';
9 -import { keyCodes, componentNames, CROPZONE_DEFAULT_OPTIONS } from '../consts';
10 -import { clamp, fixFloatingPoint } from '../util';
11 -
12 -const MOUSE_MOVE_THRESHOLD = 10;
13 -const DEFAULT_OPTION = {
14 - presetRatio: null,
15 - top: -10,
16 - left: -10,
17 - height: 1,
18 - width: 1,
19 -};
20 -
21 -/**
22 - * Cropper components
23 - * @param {Graphics} graphics - Graphics instance
24 - * @extends {Component}
25 - * @class Cropper
26 - * @ignore
27 - */
28 -class Cropper extends Component {
29 - constructor(graphics) {
30 - super(componentNames.CROPPER, graphics);
31 -
32 - /**
33 - * Cropzone
34 - * @type {Cropzone}
35 - * @private
36 - */
37 - this._cropzone = null;
38 -
39 - /**
40 - * StartX of Cropzone
41 - * @type {number}
42 - * @private
43 - */
44 - this._startX = null;
45 -
46 - /**
47 - * StartY of Cropzone
48 - * @type {number}
49 - * @private
50 - */
51 - this._startY = null;
52 -
53 - /**
54 - * State whether shortcut key is pressed or not
55 - * @type {boolean}
56 - * @private
57 - */
58 - this._withShiftKey = false;
59 -
60 - /**
61 - * Listeners
62 - * @type {object.<string, function>}
63 - * @private
64 - */
65 - this._listeners = {
66 - keydown: this._onKeyDown.bind(this),
67 - keyup: this._onKeyUp.bind(this),
68 - mousedown: this._onFabricMouseDown.bind(this),
69 - mousemove: this._onFabricMouseMove.bind(this),
70 - mouseup: this._onFabricMouseUp.bind(this),
71 - };
72 - }
73 -
74 - /**
75 - * Start cropping
76 - */
77 - start() {
78 - if (this._cropzone) {
79 - return;
80 - }
81 - const canvas = this.getCanvas();
82 -
83 - canvas.forEachObject((obj) => {
84 - // {@link http://fabricjs.com/docs/fabric.Object.html#evented}
85 - obj.evented = false;
86 - });
87 -
88 - this._cropzone = new Cropzone(
89 - canvas,
90 - snippet.extend(
91 - {
92 - left: 0,
93 - top: 0,
94 - width: 0.5,
95 - height: 0.5,
96 - strokeWidth: 0, // {@link https://github.com/kangax/fabric.js/issues/2860}
97 - cornerSize: 10,
98 - cornerColor: 'black',
99 - fill: 'transparent',
100 - },
101 - CROPZONE_DEFAULT_OPTIONS,
102 - this.graphics.cropSelectionStyle
103 - )
104 - );
105 -
106 - canvas.discardActiveObject();
107 - canvas.add(this._cropzone);
108 - canvas.on('mouse:down', this._listeners.mousedown);
109 - canvas.selection = false;
110 - canvas.defaultCursor = 'crosshair';
111 -
112 - fabric.util.addListener(document, 'keydown', this._listeners.keydown);
113 - fabric.util.addListener(document, 'keyup', this._listeners.keyup);
114 - }
115 -
116 - /**
117 - * End cropping
118 - */
119 - end() {
120 - const canvas = this.getCanvas();
121 - const cropzone = this._cropzone;
122 -
123 - if (!cropzone) {
124 - return;
125 - }
126 - canvas.remove(cropzone);
127 - canvas.selection = true;
128 - canvas.defaultCursor = 'default';
129 - canvas.off('mouse:down', this._listeners.mousedown);
130 - canvas.forEachObject((obj) => {
131 - obj.evented = true;
132 - });
133 -
134 - this._cropzone = null;
135 -
136 - fabric.util.removeListener(document, 'keydown', this._listeners.keydown);
137 - fabric.util.removeListener(document, 'keyup', this._listeners.keyup);
138 - }
139 -
140 - /**
141 - * Change cropzone visible
142 - * @param {boolean} visible - cropzone visible state
143 - */
144 - changeVisibility(visible) {
145 - if (this._cropzone) {
146 - this._cropzone.set({ visible });
147 - }
148 - }
149 -
150 - /**
151 - * onMousedown handler in fabric canvas
152 - * @param {{target: fabric.Object, e: MouseEvent}} fEvent - Fabric event
153 - * @private
154 - */
155 - _onFabricMouseDown(fEvent) {
156 - const canvas = this.getCanvas();
157 -
158 - if (fEvent.target) {
159 - return;
160 - }
161 -
162 - canvas.selection = false;
163 - const coord = canvas.getPointer(fEvent.e);
164 -
165 - this._startX = coord.x;
166 - this._startY = coord.y;
167 -
168 - canvas.on({
169 - 'mouse:move': this._listeners.mousemove,
170 - 'mouse:up': this._listeners.mouseup,
171 - });
172 - }
173 -
174 - /**
175 - * onMousemove handler in fabric canvas
176 - * @param {{target: fabric.Object, e: MouseEvent}} fEvent - Fabric event
177 - * @private
178 - */
179 - _onFabricMouseMove(fEvent) {
180 - const canvas = this.getCanvas();
181 - const pointer = canvas.getPointer(fEvent.e);
182 - const { x, y } = pointer;
183 - const cropzone = this._cropzone;
184 -
185 - if (Math.abs(x - this._startX) + Math.abs(y - this._startY) > MOUSE_MOVE_THRESHOLD) {
186 - canvas.remove(cropzone);
187 - cropzone.set(this._calcRectDimensionFromPoint(x, y));
188 -
189 - canvas.add(cropzone);
190 - canvas.setActiveObject(cropzone);
191 - }
192 - }
193 -
194 - /**
195 - * Get rect dimension setting from Canvas-Mouse-Position(x, y)
196 - * @param {number} x - Canvas-Mouse-Position x
197 - * @param {number} y - Canvas-Mouse-Position Y
198 - * @returns {{left: number, top: number, width: number, height: number}}
199 - * @private
200 - */
201 - _calcRectDimensionFromPoint(x, y) {
202 - const canvas = this.getCanvas();
203 - const canvasWidth = canvas.getWidth();
204 - const canvasHeight = canvas.getHeight();
205 - const startX = this._startX;
206 - const startY = this._startY;
207 - let left = clamp(x, 0, startX);
208 - let top = clamp(y, 0, startY);
209 - let width = clamp(x, startX, canvasWidth) - left; // (startX <= x(mouse) <= canvasWidth) - left
210 - let height = clamp(y, startY, canvasHeight) - top; // (startY <= y(mouse) <= canvasHeight) - top
211 -
212 - if (this._withShiftKey) {
213 - // make fixed ratio cropzone
214 - if (width > height) {
215 - height = width;
216 - } else if (height > width) {
217 - width = height;
218 - }
219 -
220 - if (startX >= x) {
221 - left = startX - width;
222 - }
223 -
224 - if (startY >= y) {
225 - top = startY - height;
226 - }
227 - }
228 -
229 - return {
230 - left,
231 - top,
232 - width,
233 - height,
234 - };
235 - }
236 -
237 - /**
238 - * onMouseup handler in fabric canvas
239 - * @private
240 - */
241 - _onFabricMouseUp() {
242 - const cropzone = this._cropzone;
243 - const listeners = this._listeners;
244 - const canvas = this.getCanvas();
245 -
246 - canvas.setActiveObject(cropzone);
247 - canvas.off({
248 - 'mouse:move': listeners.mousemove,
249 - 'mouse:up': listeners.mouseup,
250 - });
251 - }
252 -
253 - /**
254 - * Get cropped image data
255 - * @param {Object} cropRect cropzone rect
256 - * @param {Number} cropRect.left left position
257 - * @param {Number} cropRect.top top position
258 - * @param {Number} cropRect.width width
259 - * @param {Number} cropRect.height height
260 - * @returns {?{imageName: string, url: string}} cropped Image data
261 - */
262 - getCroppedImageData(cropRect) {
263 - const canvas = this.getCanvas();
264 - const containsCropzone = canvas.contains(this._cropzone);
265 - if (!cropRect) {
266 - return null;
267 - }
268 -
269 - if (containsCropzone) {
270 - canvas.remove(this._cropzone);
271 - }
272 -
273 - const imageData = {
274 - imageName: this.getImageName(),
275 - url: canvas.toDataURL(cropRect),
276 - };
277 -
278 - if (containsCropzone) {
279 - canvas.add(this._cropzone);
280 - }
281 -
282 - return imageData;
283 - }
284 -
285 - /**
286 - * Get cropped rect
287 - * @returns {Object} rect
288 - */
289 - getCropzoneRect() {
290 - const cropzone = this._cropzone;
291 -
292 - if (!cropzone.isValid()) {
293 - return null;
294 - }
295 -
296 - return {
297 - left: cropzone.left,
298 - top: cropzone.top,
299 - width: cropzone.width,
300 - height: cropzone.height,
301 - };
302 - }
303 -
304 - /**
305 - * Set a cropzone square
306 - * @param {number} [presetRatio] - preset ratio
307 - */
308 - setCropzoneRect(presetRatio) {
309 - const canvas = this.getCanvas();
310 - const cropzone = this._cropzone;
311 -
312 - canvas.discardActiveObject();
313 - canvas.selection = false;
314 - canvas.remove(cropzone);
315 -
316 - cropzone.set(presetRatio ? this._getPresetPropertiesForCropSize(presetRatio) : DEFAULT_OPTION);
317 -
318 - canvas.add(cropzone);
319 - canvas.selection = true;
320 -
321 - if (presetRatio) {
322 - canvas.setActiveObject(cropzone);
323 - }
324 - }
325 -
326 - /**
327 - * get a cropzone square info
328 - * @param {number} presetRatio - preset ratio
329 - * @returns {{presetRatio: number, left: number, top: number, width: number, height: number}}
330 - * @private
331 - */
332 - _getPresetPropertiesForCropSize(presetRatio) {
333 - const canvas = this.getCanvas();
334 - const originalWidth = canvas.getWidth();
335 - const originalHeight = canvas.getHeight();
336 -
337 - const standardSize = originalWidth >= originalHeight ? originalWidth : originalHeight;
338 - const getScale = (value, orignalValue) => (value > orignalValue ? orignalValue / value : 1);
339 -
340 - let width = standardSize * presetRatio;
341 - let height = standardSize;
342 -
343 - const scaleWidth = getScale(width, originalWidth);
344 - [width, height] = snippet.map([width, height], (sizeValue) => sizeValue * scaleWidth);
345 -
346 - const scaleHeight = getScale(height, originalHeight);
347 - [width, height] = snippet.map([width, height], (sizeValue) =>
348 - fixFloatingPoint(sizeValue * scaleHeight)
349 - );
350 -
351 - return {
352 - presetRatio,
353 - top: (originalHeight - height) / 2,
354 - left: (originalWidth - width) / 2,
355 - width,
356 - height,
357 - };
358 - }
359 -
360 - /**
361 - * Keydown event handler
362 - * @param {KeyboardEvent} e - Event object
363 - * @private
364 - */
365 - _onKeyDown(e) {
366 - if (e.keyCode === keyCodes.SHIFT) {
367 - this._withShiftKey = true;
368 - }
369 - }
370 -
371 - /**
372 - * Keyup event handler
373 - * @param {KeyboardEvent} e - Event object
374 - * @private
375 - */
376 - _onKeyUp(e) {
377 - if (e.keyCode === keyCodes.SHIFT) {
378 - this._withShiftKey = false;
379 - }
380 - }
381 -}
382 -
383 -export default Cropper;
1 -/**
2 - * @author NHN Ent. FE Development Team <dl_javascript@nhn.com>
3 - * @fileoverview Add filter module
4 - */
5 -import { isUndefined, extend, forEach, filter } from 'tui-code-snippet';
6 -import { Promise } from '../util';
7 -import fabric from 'fabric';
8 -import Component from '../interface/component';
9 -import Mask from '../extension/mask';
10 -import { rejectMessages, componentNames } from '../consts';
11 -import Sharpen from '../extension/sharpen';
12 -import Emboss from '../extension/emboss';
13 -import ColorFilter from '../extension/colorFilter';
14 -
15 -const { filters } = fabric.Image;
16 -filters.Mask = Mask;
17 -filters.Sharpen = Sharpen;
18 -filters.Emboss = Emboss;
19 -filters.ColorFilter = ColorFilter;
20 -
21 -/**
22 - * Filter
23 - * @class Filter
24 - * @param {Graphics} graphics - Graphics instance
25 - * @extends {Component}
26 - * @ignore
27 - */
28 -class Filter extends Component {
29 - constructor(graphics) {
30 - super(componentNames.FILTER, graphics);
31 - }
32 -
33 - /**
34 - * Add filter to source image (a specific filter is added on fabric.js)
35 - * @param {string} type - Filter type
36 - * @param {Object} [options] - Options of filter
37 - * @returns {Promise}
38 - */
39 - add(type, options) {
40 - return new Promise((resolve, reject) => {
41 - const sourceImg = this._getSourceImage();
42 - const canvas = this.getCanvas();
43 - let imgFilter = this._getFilter(sourceImg, type);
44 - if (!imgFilter) {
45 - imgFilter = this._createFilter(sourceImg, type, options);
46 - }
47 -
48 - if (!imgFilter) {
49 - reject(rejectMessages.invalidParameters);
50 - }
51 -
52 - this._changeFilterValues(imgFilter, options);
53 -
54 - this._apply(sourceImg, () => {
55 - canvas.renderAll();
56 - resolve({
57 - type,
58 - action: 'add',
59 - options,
60 - });
61 - });
62 - });
63 - }
64 -
65 - /**
66 - * Remove filter to source image
67 - * @param {string} type - Filter type
68 - * @returns {Promise}
69 - */
70 - remove(type) {
71 - return new Promise((resolve, reject) => {
72 - const sourceImg = this._getSourceImage();
73 - const canvas = this.getCanvas();
74 - const options = this.getOptions(type);
75 -
76 - if (!sourceImg.filters.length) {
77 - reject(rejectMessages.unsupportedOperation);
78 - }
79 -
80 - this._removeFilter(sourceImg, type);
81 -
82 - this._apply(sourceImg, () => {
83 - canvas.renderAll();
84 - resolve({
85 - type,
86 - action: 'remove',
87 - options,
88 - });
89 - });
90 - });
91 - }
92 -
93 - /**
94 - * Whether this has the filter or not
95 - * @param {string} type - Filter type
96 - * @returns {boolean} true if it has the filter
97 - */
98 - hasFilter(type) {
99 - return !!this._getFilter(this._getSourceImage(), type);
100 - }
101 -
102 - /**
103 - * Get a filter options
104 - * @param {string} type - Filter type
105 - * @returns {Object} filter options or null if there is no that filter
106 - */
107 - getOptions(type) {
108 - const sourceImg = this._getSourceImage();
109 - const imgFilter = this._getFilter(sourceImg, type);
110 - if (!imgFilter) {
111 - return null;
112 - }
113 -
114 - return extend({}, imgFilter.options);
115 - }
116 -
117 - /**
118 - * Change filter values
119 - * @param {Object} imgFilter object of filter
120 - * @param {Object} options object
121 - * @private
122 - */
123 - _changeFilterValues(imgFilter, options) {
124 - forEach(options, (value, key) => {
125 - if (!isUndefined(imgFilter[key])) {
126 - imgFilter[key] = value;
127 - }
128 - });
129 - forEach(imgFilter.options, (value, key) => {
130 - if (!isUndefined(options[key])) {
131 - imgFilter.options[key] = options[key];
132 - }
133 - });
134 - }
135 -
136 - /**
137 - * Apply filter
138 - * @param {fabric.Image} sourceImg - Source image to apply filter
139 - * @param {function} callback - Executed function after applying filter
140 - * @private
141 - */
142 - _apply(sourceImg, callback) {
143 - sourceImg.filters.push();
144 - const result = sourceImg.applyFilters();
145 - if (result) {
146 - callback();
147 - }
148 - }
149 -
150 - /**
151 - * Get source image on canvas
152 - * @returns {fabric.Image} Current source image on canvas
153 - * @private
154 - */
155 - _getSourceImage() {
156 - return this.getCanvasImage();
157 - }
158 -
159 - /**
160 - * Create filter instance
161 - * @param {fabric.Image} sourceImg - Source image to apply filter
162 - * @param {string} type - Filter type
163 - * @param {Object} [options] - Options of filter
164 - * @returns {Object} Fabric object of filter
165 - * @private
166 - */
167 - _createFilter(sourceImg, type, options) {
168 - let filterObj;
169 - // capitalize first letter for matching with fabric image filter name
170 - const fabricType = this._getFabricFilterType(type);
171 - const ImageFilter = fabric.Image.filters[fabricType];
172 - if (ImageFilter) {
173 - filterObj = new ImageFilter(options);
174 - filterObj.options = options;
175 - sourceImg.filters.push(filterObj);
176 - }
177 -
178 - return filterObj;
179 - }
180 -
181 - /**
182 - * Get applied filter instance
183 - * @param {fabric.Image} sourceImg - Source image to apply filter
184 - * @param {string} type - Filter type
185 - * @returns {Object} Fabric object of filter
186 - * @private
187 - */
188 - _getFilter(sourceImg, type) {
189 - let imgFilter = null;
190 -
191 - if (sourceImg) {
192 - const fabricType = this._getFabricFilterType(type);
193 - const { length } = sourceImg.filters;
194 - let item, i;
195 -
196 - for (i = 0; i < length; i += 1) {
197 - item = sourceImg.filters[i];
198 - if (item.type === fabricType) {
199 - imgFilter = item;
200 - break;
201 - }
202 - }
203 - }
204 -
205 - return imgFilter;
206 - }
207 -
208 - /**
209 - * Remove applied filter instance
210 - * @param {fabric.Image} sourceImg - Source image to apply filter
211 - * @param {string} type - Filter type
212 - * @private
213 - */
214 - _removeFilter(sourceImg, type) {
215 - const fabricType = this._getFabricFilterType(type);
216 - sourceImg.filters = filter(sourceImg.filters, (value) => value.type !== fabricType);
217 - }
218 -
219 - /**
220 - * Change filter class name to fabric's, especially capitalizing first letter
221 - * @param {string} type - Filter type
222 - * @example
223 - * 'grayscale' -> 'Grayscale'
224 - * @returns {string} Fabric filter class name
225 - */
226 - _getFabricFilterType(type) {
227 - return type.charAt(0).toUpperCase() + type.slice(1);
228 - }
229 -}
230 -
231 -export default Filter;
1 -/**
2 - * @author NHN Ent. FE Development Team <dl_javascript@nhn.com>
3 - * @fileoverview Image flip module
4 - */
5 -import snippet from 'tui-code-snippet';
6 -import { Promise } from '../util';
7 -import Component from '../interface/component';
8 -import { componentNames, rejectMessages } from '../consts';
9 -
10 -/**
11 - * Flip
12 - * @class Flip
13 - * @param {Graphics} graphics - Graphics instance
14 - * @extends {Component}
15 - * @ignore
16 - */
17 -class Flip extends Component {
18 - constructor(graphics) {
19 - super(componentNames.FLIP, graphics);
20 - }
21 -
22 - /**
23 - * Get current flip settings
24 - * @returns {{flipX: Boolean, flipY: Boolean}}
25 - */
26 - getCurrentSetting() {
27 - const canvasImage = this.getCanvasImage();
28 -
29 - return {
30 - flipX: canvasImage.flipX,
31 - flipY: canvasImage.flipY,
32 - };
33 - }
34 -
35 - /**
36 - * Set flipX, flipY
37 - * @param {{flipX: Boolean, flipY: Boolean}} newSetting - Flip setting
38 - * @returns {Promise}
39 - */
40 - set(newSetting) {
41 - const setting = this.getCurrentSetting();
42 - const isChangingFlipX = setting.flipX !== newSetting.flipX;
43 - const isChangingFlipY = setting.flipY !== newSetting.flipY;
44 -
45 - if (!isChangingFlipX && !isChangingFlipY) {
46 - return Promise.reject(rejectMessages.flip);
47 - }
48 -
49 - snippet.extend(setting, newSetting);
50 - this.setImageProperties(setting, true);
51 - this._invertAngle(isChangingFlipX, isChangingFlipY);
52 - this._flipObjects(isChangingFlipX, isChangingFlipY);
53 -
54 - return Promise.resolve({
55 - flipX: setting.flipX,
56 - flipY: setting.flipY,
57 - angle: this.getCanvasImage().angle,
58 - });
59 - }
60 -
61 - /**
62 - * Invert image angle for flip
63 - * @param {boolean} isChangingFlipX - Change flipX
64 - * @param {boolean} isChangingFlipY - Change flipY
65 - */
66 - _invertAngle(isChangingFlipX, isChangingFlipY) {
67 - const canvasImage = this.getCanvasImage();
68 - let { angle } = canvasImage;
69 -
70 - if (isChangingFlipX) {
71 - angle *= -1;
72 - }
73 - if (isChangingFlipY) {
74 - angle *= -1;
75 - }
76 - canvasImage.rotate(parseFloat(angle)).setCoords(); // parseFloat for -0 to 0
77 - }
78 -
79 - /**
80 - * Flip objects
81 - * @param {boolean} isChangingFlipX - Change flipX
82 - * @param {boolean} isChangingFlipY - Change flipY
83 - * @private
84 - */
85 - _flipObjects(isChangingFlipX, isChangingFlipY) {
86 - const canvas = this.getCanvas();
87 -
88 - if (isChangingFlipX) {
89 - canvas.forEachObject((obj) => {
90 - obj
91 - .set({
92 - angle: parseFloat(obj.angle * -1), // parseFloat for -0 to 0
93 - flipX: !obj.flipX,
94 - left: canvas.width - obj.left,
95 - })
96 - .setCoords();
97 - });
98 - }
99 - if (isChangingFlipY) {
100 - canvas.forEachObject((obj) => {
101 - obj
102 - .set({
103 - angle: parseFloat(obj.angle * -1), // parseFloat for -0 to 0
104 - flipY: !obj.flipY,
105 - top: canvas.height - obj.top,
106 - })
107 - .setCoords();
108 - });
109 - }
110 - canvas.renderAll();
111 - }
112 -
113 - /**
114 - * Reset flip settings
115 - * @returns {Promise}
116 - */
117 - reset() {
118 - return this.set({
119 - flipX: false,
120 - flipY: false,
121 - });
122 - }
123 -
124 - /**
125 - * Flip x
126 - * @returns {Promise}
127 - */
128 - flipX() {
129 - const current = this.getCurrentSetting();
130 -
131 - return this.set({
132 - flipX: !current.flipX,
133 - flipY: current.flipY,
134 - });
135 - }
136 -
137 - /**
138 - * Flip y
139 - * @returns {Promise}
140 - */
141 - flipY() {
142 - const current = this.getCurrentSetting();
143 -
144 - return this.set({
145 - flipX: current.flipX,
146 - flipY: !current.flipY,
147 - });
148 - }
149 -}
150 -
151 -export default Flip;
1 -/**
2 - * @author NHN Ent. FE Development Team <dl_javascript@nhn.com>
3 - * @fileoverview Free drawing module, Set brush
4 - */
5 -import fabric from 'fabric';
6 -import Component from '../interface/component';
7 -import { componentNames } from '../consts';
8 -
9 -/**
10 - * FreeDrawing
11 - * @class FreeDrawing
12 - * @param {Graphics} graphics - Graphics instance
13 - * @extends {Component}
14 - * @ignore
15 - */
16 -class FreeDrawing extends Component {
17 - constructor(graphics) {
18 - super(componentNames.FREE_DRAWING, graphics);
19 -
20 - /**
21 - * Brush width
22 - * @type {number}
23 - */
24 - this.width = 12;
25 -
26 - /**
27 - * fabric.Color instance for brush color
28 - * @type {fabric.Color}
29 - */
30 - this.oColor = new fabric.Color('rgba(0, 0, 0, 0.5)');
31 - }
32 -
33 - /**
34 - * Start free drawing mode
35 - * @param {{width: ?number, color: ?string}} [setting] - Brush width & color
36 - */
37 - start(setting) {
38 - const canvas = this.getCanvas();
39 -
40 - canvas.isDrawingMode = true;
41 - this.setBrush(setting);
42 - }
43 -
44 - /**
45 - * Set brush
46 - * @param {{width: ?number, color: ?string}} [setting] - Brush width & color
47 - */
48 - setBrush(setting) {
49 - const brush = this.getCanvas().freeDrawingBrush;
50 -
51 - setting = setting || {};
52 - this.width = setting.width || this.width;
53 - if (setting.color) {
54 - this.oColor = new fabric.Color(setting.color);
55 - }
56 - brush.width = this.width;
57 - brush.color = this.oColor.toRgba();
58 - }
59 -
60 - /**
61 - * End free drawing mode
62 - */
63 - end() {
64 - const canvas = this.getCanvas();
65 -
66 - canvas.isDrawingMode = false;
67 - }
68 -}
69 -
70 -export default FreeDrawing;
1 -/**
2 - * @author NHN Ent. FE Development Team <dl_javascript@nhn.com>
3 - * @fileoverview Add icon module
4 - */
5 -import fabric from 'fabric';
6 -import snippet from 'tui-code-snippet';
7 -import { Promise } from '../util';
8 -import Component from '../interface/component';
9 -import { eventNames as events, rejectMessages, componentNames, fObjectOptions } from '../consts';
10 -
11 -const pathMap = {
12 - arrow: 'M 0 90 H 105 V 120 L 160 60 L 105 0 V 30 H 0 Z',
13 - cancel:
14 - 'M 0 30 L 30 60 L 0 90 L 30 120 L 60 90 L 90 120 L 120 90 ' +
15 - 'L 90 60 L 120 30 L 90 0 L 60 30 L 30 0 Z',
16 -};
17 -
18 -/**
19 - * Icon
20 - * @class Icon
21 - * @param {Graphics} graphics - Graphics instance
22 - * @extends {Component}
23 - * @ignore
24 - */
25 -class Icon extends Component {
26 - constructor(graphics) {
27 - super(componentNames.ICON, graphics);
28 -
29 - /**
30 - * Default icon color
31 - * @type {string}
32 - */
33 - this._oColor = '#000000';
34 -
35 - /**
36 - * Path value of each icon type
37 - * @type {Object}
38 - */
39 - this._pathMap = pathMap;
40 -
41 - /**
42 - * Type of the drawing icon
43 - * @type {string}
44 - * @private
45 - */
46 - this._type = null;
47 -
48 - /**
49 - * Color of the drawing icon
50 - * @type {string}
51 - * @private
52 - */
53 - this._iconColor = null;
54 -
55 - /**
56 - * Event handler list
57 - * @type {Object}
58 - * @private
59 - */
60 - this._handlers = {
61 - mousedown: this._onFabricMouseDown.bind(this),
62 - mousemove: this._onFabricMouseMove.bind(this),
63 - mouseup: this._onFabricMouseUp.bind(this),
64 - };
65 - }
66 -
67 - /**
68 - * Set states of the current drawing shape
69 - * @ignore
70 - * @param {string} type - Icon type ('arrow', 'cancel', custom icon name)
71 - * @param {string} iconColor - Icon foreground color
72 - */
73 - setStates(type, iconColor) {
74 - this._type = type;
75 - this._iconColor = iconColor;
76 - }
77 -
78 - /**
79 - * Start to draw the icon on canvas
80 - * @ignore
81 - */
82 - start() {
83 - const canvas = this.getCanvas();
84 - canvas.selection = false;
85 - canvas.on('mouse:down', this._handlers.mousedown);
86 - }
87 -
88 - /**
89 - * End to draw the icon on canvas
90 - * @ignore
91 - */
92 - end() {
93 - const canvas = this.getCanvas();
94 -
95 - canvas.selection = true;
96 - canvas.off({
97 - 'mouse:down': this._handlers.mousedown,
98 - });
99 - }
100 -
101 - /**
102 - * Add icon
103 - * @param {string} type - Icon type
104 - * @param {Object} options - Icon options
105 - * @param {string} [options.fill] - Icon foreground color
106 - * @param {string} [options.left] - Icon x position
107 - * @param {string} [options.top] - Icon y position
108 - * @returns {Promise}
109 - */
110 - add(type, options) {
111 - return new Promise((resolve, reject) => {
112 - const canvas = this.getCanvas();
113 - const path = this._pathMap[type];
114 - const selectionStyle = fObjectOptions.SELECTION_STYLE;
115 - const icon = path ? this._createIcon(path) : null;
116 - this._icon = icon;
117 -
118 - if (!icon) {
119 - reject(rejectMessages.invalidParameters);
120 - }
121 -
122 - icon.set(
123 - snippet.extend(
124 - {
125 - type: 'icon',
126 - fill: this._oColor,
127 - },
128 - selectionStyle,
129 - options,
130 - this.graphics.controlStyle
131 - )
132 - );
133 -
134 - canvas.add(icon).setActiveObject(icon);
135 -
136 - resolve(this.graphics.createObjectProperties(icon));
137 - });
138 - }
139 -
140 - /**
141 - * Register icon paths
142 - * @param {{key: string, value: string}} pathInfos - Path infos
143 - */
144 - registerPaths(pathInfos) {
145 - snippet.forEach(
146 - pathInfos,
147 - (path, type) => {
148 - this._pathMap[type] = path;
149 - },
150 - this
151 - );
152 - }
153 -
154 - /**
155 - * Set icon object color
156 - * @param {string} color - Color to set
157 - * @param {fabric.Path}[obj] - Current activated path object
158 - */
159 - setColor(color, obj) {
160 - this._oColor = color;
161 -
162 - if (obj && obj.get('type') === 'icon') {
163 - obj.set({ fill: this._oColor });
164 - this.getCanvas().renderAll();
165 - }
166 - }
167 -
168 - /**
169 - * Get icon color
170 - * @param {fabric.Path}[obj] - Current activated path object
171 - * @returns {string} color
172 - */
173 - getColor(obj) {
174 - return obj.fill;
175 - }
176 -
177 - /**
178 - * Create icon object
179 - * @param {string} path - Path value to create icon
180 - * @returns {fabric.Path} Path object
181 - */
182 - _createIcon(path) {
183 - return new fabric.Path(path);
184 - }
185 -
186 - /**
187 - * MouseDown event handler on canvas
188 - * @param {{target: fabric.Object, e: MouseEvent}} fEvent - Fabric event object
189 - * @private
190 - */
191 - _onFabricMouseDown(fEvent) {
192 - const canvas = this.getCanvas();
193 -
194 - this._startPoint = canvas.getPointer(fEvent.e);
195 - const { x: left, y: top } = this._startPoint;
196 -
197 - this.add(this._type, {
198 - left,
199 - top,
200 - fill: this._iconColor,
201 - }).then(() => {
202 - this.fire(events.ADD_OBJECT, this.graphics.createObjectProperties(this._icon));
203 - canvas.on('mouse:move', this._handlers.mousemove);
204 - canvas.on('mouse:up', this._handlers.mouseup);
205 - });
206 - }
207 -
208 - /**
209 - * MouseMove event handler on canvas
210 - * @param {{target: fabric.Object, e: MouseEvent}} fEvent - Fabric event object
211 - * @private
212 - */
213 - _onFabricMouseMove(fEvent) {
214 - const canvas = this.getCanvas();
215 -
216 - if (!this._icon) {
217 - return;
218 - }
219 - const moveOriginPointer = canvas.getPointer(fEvent.e);
220 -
221 - const scaleX = (moveOriginPointer.x - this._startPoint.x) / this._icon.width;
222 - const scaleY = (moveOriginPointer.y - this._startPoint.y) / this._icon.height;
223 -
224 - this._icon.set({
225 - scaleX: Math.abs(scaleX * 2),
226 - scaleY: Math.abs(scaleY * 2),
227 - });
228 -
229 - this._icon.setCoords();
230 - canvas.renderAll();
231 - }
232 -
233 - /**
234 - * MouseUp event handler on canvas
235 - * @private
236 - */
237 - _onFabricMouseUp() {
238 - const canvas = this.getCanvas();
239 -
240 - this.fire(events.OBJECT_ADDED, this.graphics.createObjectProperties(this._icon));
241 -
242 - this._icon = null;
243 -
244 - canvas.off('mouse:down', this._handlers.mousedown);
245 - canvas.off('mouse:move', this._handlers.mousemove);
246 - canvas.off('mouse:up', this._handlers.mouseup);
247 - }
248 -}
249 -
250 -export default Icon;
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.