1
0
mirror of https://github.com/ascribe/onion.git synced 2024-12-22 09:23:13 +01:00

Merge pull request #30 from ascribe/AD-1313-Attach-thumbnail-to-piece-in-register-form

Ad 1313 attach thumbnail to piece in register form
This commit is contained in:
Tim Daubenschütz 2015-12-07 17:17:19 +01:00
commit aba0747fe3
76 changed files with 980 additions and 1158 deletions

View File

@ -1,63 +0,0 @@
# Feature list
This list specifies all features in Onion that ought to be tested before actually pushing live:
- sign up & email activation
- login
- log out
- form input
+ reset
+ save
+ disabled state
- form checkbox
+ reset
+ save
+ disabled state
- create app
+ refresh token
- loan contract
+ upload
+ download
+ delete
- register work
+ with edition
+ without edition
+ correct encoding of video upload
- fineuploader
+ upload file
+ upload multiple files
+ delete file
+ cancel upload of file
- create editions
+ in piece list
+ in piece detail
- all notes in edition/piece detail
- transfer & consign & loan & share & delete
+ bulk
+ single
+ withdraw
- piece list
+ filter (also check for correct filtering of opened edition tables)
+ order
+ search
+ pagination
+ expandable edition list for piece
- download coa
## sluice
- hero landing page
- activation email
- submission (also check extra form fields)
+ of existing pieces
+ newly registered pieces
- rating
+ in piece list
+ in piece detail
- short listing (not yet implemented)
- piece list
+ order by rating
## Cyland
- hero landing page
- activation email
- submission (check states of submission (1,2,3))

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -3,7 +3,7 @@
<svg xmlns="http://www.w3.org/2000/svg">
<metadata>Generated by IcoMoon</metadata>
<defs>
<font id="ascribe-logo" horiz-adv-x="1024">
<font id="icomoon" horiz-adv-x="1024">
<font-face units-per-em="1024" ascent="960" descent="-64" />
<missing-glyph horiz-adv-x="1024" />
<glyph unicode="&#x20;" horiz-adv-x="512" d="" />
@ -12,8 +12,9 @@
<glyph unicode="&#xe802;" glyph-name="search" d="M1021.1-36.711l-305.914 305.583c67.615 73.406 108.95 171.391 108.95 279.060 0 227.579-184.49 412.068-412.068 412.068s-412.068-184.489-412.068-412.068c0-227.578 184.489-412.068 412.068-412.068 107.625 0 205.576 41.3 278.972 108.866l305.927-305.597 24.133 24.156zM412.068 169.997c-208.394 0-377.935 169.541-377.935 377.935s169.541 377.935 377.935 377.935 377.935-169.54 377.935-377.935c0-208.394-169.541-377.935-377.935-377.935z" />
<glyph unicode="&#xe803;" glyph-name="filter" d="M0 960l384.89-534.756 8.722-489.244 184.119 174.521 0.324 314.724 445.947 534.756h-1024zM551.839 447.106c-5.109-6.126-7.91-13.849-7.919-21.826l-0.308-300.068-117.253-111.141-7.341 411.782c-0.124 6.948-2.365 13.692-6.424 19.331l-345.97 480.683h884.467l-399.251-478.761z" />
<glyph unicode="&#xe804;" glyph-name="add-white" d="M510.103 923.822c263.415 0 477.719-214.304 477.719-477.719s-214.303-477.718-477.719-477.718c-263.415 0-477.718 214.304-477.718 477.718s214.303 477.719 477.718 477.719zM510.103 957.955c-282.688 0-511.851-229.164-511.851-511.852s229.163-511.851 511.851-511.851 511.852 229.164 511.852 511.851-229.164 511.852-511.852 511.852v0zM796.444 459.378h-273.067v273.067h-34.133v-273.067h-261.689v-34.133h261.689v-261.689h34.133v261.689h273.067z" />
<glyph unicode="&#xe805;" d="M512.148 959.852c-282.688 0-511.851-229.164-511.851-511.852s229.164-511.851 511.851-511.851 511.852 229.163 511.852 511.851-229.164 511.852-511.852 511.852z" />
<glyph unicode="&#xe806;" d="M796.444 459.378h-273.067v273.067h-34.133v-273.067h-261.689v-34.133h261.689v-261.689h34.133v261.689h273.067z" />
<glyph unicode="&#xe805;" glyph-name="uniE805" d="M512.148 959.852c-282.688 0-511.851-229.164-511.851-511.852s229.164-511.851 511.851-511.851 511.852 229.163 511.852 511.851-229.164 511.852-511.852 511.852z" />
<glyph unicode="&#xe806;" glyph-name="uniE806" d="M796.444 459.378h-273.067v273.067h-34.133v-273.067h-261.689v-34.133h261.689v-261.689h34.133v261.689h273.067z" />
<glyph unicode="&#xe807;" glyph-name="icon" d="M550.306 782.458h-75.373l-249.184-613.64h90.453l62.951 159.627h262.477l62.974-159.627h95.755l-250.053 613.64zM403.098 400.255l107.305 274.897 107.28-274.897h-214.586zM1024 448c0 286.204-225.796 512-511.999 512s-512.001-225.796-512.001-512c0-286.204 225.797-512 512.001-512s511.999 225.797 511.999 512v0zM962.165 448c0-245.94-204.249-450.164-450.164-450.164-245.941 0-450.161 204.224-450.161 450.164s204.221 450.164 450.161 450.164c245.915 0 450.164-204.224 450.164-450.164v0z" />
<glyph unicode="&#xe808;" glyph-name="logo" horiz-adv-x="4195" d="M499.718 326.19c0 109.528-24.641 157.448-61.607 198.517-38.336 41.077-95.832 71.191-191.673 71.191-95.832 0-171.135-36.957-212.212-64.34l27.382-52.031c13.695 10.954 88.998 54.764 187.571 54.764 99.943 0 177.978-57.505 177.978-173.876v-34.225l-173.876-6.843c-171.135-6.852-253.281-82.146-253.281-191.673s88.989-191.674 212.212-191.674c123.214 0 191.674 75.294 214.944 102.676v-88.989h72.562v376.503zM427.156 113.978c-30.114-47.92-98.573-116.371-201.258-116.371-102.676 0-154.707 61.607-154.707 130.066 0 68.45 42.448 125.955 175.246 132.798l180.719 10.955v-157.448zM1063.784 123.562c0 120.482-119.12 161.551-198.525 188.933-78.035 27.382-146.494 56.134-146.494 121.853s50.661 101.314 121.853 101.314c71.191 0 115.001-24.641 158.819-72.561l43.809 43.809c-49.291 56.134-106.795 88.989-199.887 88.989-93.1 0-193.044-54.764-193.044-169.765s119.112-156.078 173.876-175.246c54.764-19.168 168.394-47.92 168.394-130.066s-69.821-120.482-149.226-120.482c-79.413 0-142.391 39.707-183.46 99.952l-50.661-41.077c39.707-65.718 113.639-123.215 231.38-123.215s223.166 68.451 223.166 187.562v0zM1679.873 93.44c0 0-68.451-93.1-212.212-93.1-143.753 0-242.326 113.639-242.326 271.087s112.268 260.132 239.594 260.132c125.955 0 180.719-61.616 208.101-93.1l45.18 47.912c-13.687 17.798-82.146 109.528-250.548 109.528-167.024 0-317.628-132.798-317.628-328.583 0-194.406 139.65-331.315 310.785-331.315s236.853 82.146 260.133 109.528l-41.077 47.912zM2142.607 586.323c0 0-27.382 9.576-68.45 9.576-68.459 0-138.28-43.81-161.551-130.058v119.112h-71.2v-635.266h71.2v342.278c0 109.528 34.225 162.921 45.18 177.978 10.946 15.066 47.912 57.505 109.528 57.505 34.225 0 53.394-5.473 68.451-10.955l6.843 69.83zM2353.432 810.851c0 32.855-26.012 58.875-58.867 58.875-32.863 0-58.875-26.020-58.875-58.875s26.011-58.875 58.875-58.875c32.855 0 58.867 26.020 58.867 58.875v0zM2330.161 584.953h-71.191v-635.266h71.191v635.266zM3144.767 267.315c0 188.941-123.223 328.583-312.155 328.583-91.73 0-177.987-36.957-239.594-132.798v431.267h-71.191v-944.68h71.191v120.482c53.394-93.1 141.012-134.169 236.853-134.169 191.673 0 314.896 143.753 314.896 331.315v0zM3069.464 267.315c0-146.494-86.257-266.976-239.594-266.976-154.707 0-239.594 120.482-239.594 266.976 0 147.864 84.887 266.976 239.594 266.976 153.337 0 239.594-119.112 239.594-266.976v0zM3836.158 298.808c0 171.135-120.482 297.090-287.514 297.090-168.402 0-308.044-132.798-308.044-328.583 0-194.406 119.112-331.315 303.933-331.315 184.83 0 264.244 95.833 264.244 95.833l-34.234 50.661c0 0-79.405-82.154-223.158-82.154-143.761 0-228.64 99.952-235.491 250.548h516.154c0 0 4.111 27.382 4.111 47.92v0zM3318.633 312.495c4.111 88.998 68.459 221.796 225.899 221.796 157.449 0 219.065-139.65 219.065-221.796h-444.963zM4027.755 897.194h-26.663l-88.15-217.077h31.998l22.269 56.468h92.852l22.277-56.468h33.874l-88.457 217.077zM3975.68 761.989l37.96 97.245 37.951-97.245h-75.91zM4195.326 778.878c0 101.246-79.876 181.122-181.121 181.122s-181.122-79.876-181.122-181.122c0-101.245 79.876-181.122 181.122-181.122s181.121 79.876 181.121 181.122v0zM4173.452 778.878c0-87.002-72.254-159.247-159.247-159.247-87.002 0-159.246 72.245-159.246 159.247s72.244 159.247 159.246 159.247c86.993 0 159.247-72.245 159.247-159.247v0z" />
<glyph unicode="&#xe809;" glyph-name="ok" horiz-adv-x="1348" d="M436.706-64l-406.588 399.059 112.941 105.412 293.647-293.647 768 760.471 105.412-105.412z" />
</font></defs></svg>

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Binary file not shown.

View File

@ -1,83 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.4, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="595.28px" height="419.53px" viewBox="0 0 595.28 419.53" enable-background="new 0 0 595.28 419.53" xml:space="preserve">
<g>
<defs>
<rect id="SVGID_1_" x="6.973" y="169.602" width="580.536" height="116.927"/>
</defs>
<clipPath id="SVGID_2_">
<use xlink:href="#SVGID_1_" overflow="visible"/>
</clipPath>
<path clip-path="url(#SVGID_2_)" d="M415.848,234.446c1.263-7.152,7.572-14.584,17.247-14.584c9.114,0,15.564,6.59,15.705,14.584
H415.848z M448.519,258.002c-2.664,5.891-8.272,8.833-15.144,8.833c-10.797,0-18.509-8.833-18.368-20.47h42.767
c3.085,0,5.188-1.823,5.188-5.189v-4.486c-0.42-15.986-12.198-29.167-29.727-29.167c-19.91,0-32.11,15.986-32.11,35.476
c0,20.894,11.639,36.598,32.251,36.598c13.461,0,24.258-7.151,28.745-18.931c1.263-3.364-0.562-6.17-3.926-6.17h-4.207
C451.604,254.496,449.781,255.338,448.519,258.002 M340.692,229.818c3.225-4.627,8.833-9.255,15.984-9.255
c10.798,0,17.809,10.656,17.809,22.996c0,12.901-6.45,22.855-17.809,22.855c-7.151,0-12.76-5.188-15.984-10.096V229.818z
M340.552,272.585c4.628,4.067,10.096,7.012,16.266,7.012c19.49,0.14,31.409-15.565,31.55-36.178
c0.141-20.472-11.779-35.896-31.41-35.896c-6.31,0-12.059,2.945-16.265,6.311v-32.251c0-2.804-2.243-5.048-5.188-5.048h-3.645
c-2.806,0-4.909,2.244-4.909,5.048v91.843c0,2.806,2.104,5.048,4.909,5.048h3.505c2.944,0,4.627-2.104,5.048-4.907L340.552,272.585
z M285.587,187.612c0,5.329,3.926,9.114,9.115,9.114c5.188,0,9.255-3.785,9.255-9.114c0-5.328-4.067-9.254-9.255-9.254
C289.513,178.358,285.587,182.284,285.587,187.612 M287.971,273.426c0,2.806,2.104,5.048,4.908,5.048h3.505
c2.804,0,5.048-2.242,5.048-5.048v-59.733c0-2.804-1.823-5.047-4.908-5.047h-3.646c-2.804,0-4.908,2.244-4.908,5.047V273.426z
M233.566,273.426c0,2.806,2.244,5.048,5.048,5.048h3.646c3.226,0,5.048-2.242,5.048-5.048v-42.064
c2.665-5.189,8.694-10.377,16.827-10.377h2.524c2.944,0,5.188-2.103,5.188-5.048v-3.786c0-2.804-1.963-4.627-4.908-4.627h-2.524
c-6.45,0-13.602,4.346-17.107,9.254l-0.14-3.225c-0.28-2.804-1.963-4.908-4.908-4.908h-3.646c-2.804,0-5.048,2.244-5.048,5.047
V273.426z M201.036,231.361c0.982,2.805,3.646,3.646,6.311,2.805l3.785-1.263c3.085-0.981,3.787-3.505,2.945-5.89
c-3.926-11.498-13.32-19.491-28.043-19.491c-19.491,0-31.83,15.845-31.83,36.037c0,20.472,11.638,36.037,31.549,36.037
c14.864,0,26.923-9.815,30.007-22.716c0.702-2.945-1.122-5.328-4.066-5.328h-4.346c-2.665,0-4.768,1.401-5.469,3.926
c-2.104,6.73-8.133,10.937-15.565,11.078c-11.498,0.14-18.509-10.096-18.509-22.997c0-13.04,6.871-23.417,18.229-23.276
C193.324,220.424,198.513,224.63,201.036,231.361 M98.117,257.302c-0.281-2.664-2.384-4.768-5.188-4.768h-4.066
c-2.664,0-4.627,2.104-4.487,4.768c0.421,12.899,10.938,22.295,28.043,22.295c17.948,0,28.466-9.815,28.466-21.875
c0-10.937-7.012-17.247-17.107-19.21c-5.328-0.981-11.638-2.244-16.686-3.646c-3.646-0.982-6.45-3.366-6.45-6.591
c0-4.487,3.786-8.553,11.639-8.553c7.151,0,11.218,4.207,12.059,7.571c0.701,2.665,3.085,4.206,5.468,4.206h3.926
c2.804,0,4.908-1.823,4.487-4.767c-1.542-11.078-11.217-19.21-25.801-19.21c-15.003,0-25.519,8.553-25.519,20.893
c0,10.516,7.993,16.126,16.125,18.51c6.029,1.823,11.638,3.084,17.668,4.205c3.786,0.702,6.59,3.086,6.59,6.871
c0,5.328-5.048,9.255-14.723,9.115C104.146,266.977,98.537,262.63,98.117,257.302 M31.091,266.274
c-6.311-0.561-10.096-3.505-10.096-8.132c0-4.908,3.786-7.853,9.675-7.853c4.066,0,7.432-0.14,11.217-0.42
c3.225-0.28,6.59-0.843,8.834-2.805v10.656c-0.702,4.768-4.767,7.853-11.218,8.553C36.839,266.557,33.895,266.557,31.091,266.274
M8.095,228.836c-0.561,2.946,1.542,4.77,4.207,4.77h4.206c2.945,0,5.048-1.543,5.609-4.207c1.122-5.469,5.609-9.256,14.303-9.256
c9.675,0,14.443,5.749,14.302,13.741v0.702c-1.402,2.244-5.468,3.225-8.974,3.365c-3.506,0.14-6.45,0.28-10.797,0.28
c-14.022,0-23.978,6.73-23.978,20.051c0,13.04,9.535,20.332,24.118,21.034c2.664,0.14,5.188,0,7.572-0.142
c5.468-0.28,11.357-2.805,14.442-6.87c1.402,3.085,6.59,6.169,10.937,6.169h2.804c2.945,0,5.048-1.821,5.048-4.768v-3.925
c0-2.805-1.963-4.628-4.627-4.628c-1.682,0-2.944-1.122-2.944-2.804v-27.483c0-16.266-11.779-27.343-28.044-27.343
C21.696,207.523,10.338,215.655,8.095,228.836"/>
<path clip-path="url(#SVGID_2_)" d="M585.82,216.386c-1.271-5.163-3.195-10.098-5.719-14.665
c-2.625-4.757-5.823-9.102-9.505-12.903c-3.819-3.955-8.108-7.37-12.743-10.145c-4.785-2.876-9.9-5.098-15.215-6.607
c-5.469-1.545-11.072-2.373-16.666-2.459c-5.722-0.064-11.451,0.593-17.018,2c-3.65,0.935-7.178,2.193-10.572,3.696l5.607,11.476
c2.613-1.129,5.32-2.083,8.114-2.798c4.465-1.129,9.058-1.667,13.683-1.606c4.475,0.069,8.976,0.736,13.373,1.977
c4.221,1.199,8.297,2.972,12.125,5.271c3.681,2.204,7.086,4.916,10.131,8.07c2.902,2.998,5.428,6.429,7.508,10.198
c1.982,3.589,3.495,7.474,4.498,11.55c0.956,3.874,1.396,7.922,1.308,12.035c-0.081,3.898-0.695,7.834-1.822,11.685
c-1.088,3.69-2.67,7.248-4.702,10.571c-1.945,3.18-4.339,6.126-7.115,8.755c-2.651,2.512-5.652,4.679-8.921,6.443
c-3.127,1.688-6.502,2.961-10.041,3.791c-3.353,0.79-6.844,1.13-10.398,1.019c-3.349-0.108-6.726-0.675-10.024-1.679
c-3.139-0.96-6.166-2.348-8.997-4.125c-2.679-1.684-5.172-3.759-7.399-6.157c-2.093-2.262-3.897-4.834-5.366-7.643
c-1.388-2.658-2.427-5.525-3.092-8.532c-0.629-2.822-0.877-5.763-0.738-8.747c0.129-2.789,0.646-5.604,1.541-8.384
c0.809-2.536,2.031-5.097,3.538-7.408c1.419-2.182,3.214-4.268,5.194-6.04c1.871-1.675,4.012-3.124,6.349-4.3
c2.169-1.084,4.589-1.914,7.003-2.399c2.257-0.456,4.722-0.617,7.112-0.461c2.199,0.145,4.52,0.62,6.707,1.371
c1.995,0.688,4.024,1.712,5.873,2.966c1.666,1.129,3.276,2.582,4.669,4.218c1.261,1.469,2.379,3.212,3.244,5.052
c0.789,1.672,1.382,3.562,1.716,5.489c0.303,1.7,0.371,3.583,0.199,5.436c-0.155,1.646-0.567,3.397-1.178,5.021
c-0.578,1.512-1.393,3.004-2.357,4.319c-0.887,1.213-1.999,2.364-3.221,3.333c-1.078,0.854-2.41,1.643-3.735,2.207
c-1.185,0.5-2.586,0.877-3.921,1.057c-1.205,0.153-2.557,0.142-3.816-0.036c-1.102-0.155-2.298-0.497-3.362-0.963
c-0.92-0.404-1.919-1.023-2.747-1.704c-0.726-0.596-1.454-1.387-2.009-2.186c-0.47-0.672-0.905-1.536-1.206-2.409
c-0.23-0.66-0.395-1.526-0.438-2.34c-0.035-0.613,0.039-1.427,0.18-2.057c0.123-0.527,0.391-1.201,0.689-1.733
c0.202-0.363,0.578-0.844,0.977-1.229c0.217-0.215,0.638-0.514,0.948-0.675c0.198-0.104,0.651-0.261,0.896-0.311
c0.141-0.027,0.507-0.028,0.719-0.006c3.501,0.422,6.669-2.109,7.072-5.612c0.401-3.504-2.111-6.67-5.614-7.073
c-0.692-0.079-2.517-0.227-4.562,0.147c-1.505,0.3-3.101,0.852-4.392,1.52c-0.86,0.447-2.531,1.426-4.003,2.888
c-1.245,1.203-2.38,2.672-3.188,4.124c-0.876,1.564-1.578,3.355-1.988,5.111c-0.413,1.846-0.583,3.846-0.483,5.609
c0.075,1.411,0.334,3.571,1.127,5.829c0.678,1.971,1.648,3.886,2.795,5.523c1.221,1.756,2.735,3.396,4.372,4.742
c1.74,1.432,3.721,2.653,5.735,3.538c2.137,0.933,4.456,1.593,6.696,1.908c2.387,0.342,4.89,0.358,7.266,0.053
c2.495-0.334,4.997-1.01,7.251-1.964c2.396-1.023,4.706-2.392,6.678-3.955c2.104-1.67,4.038-3.674,5.588-5.793
c1.624-2.216,3.001-4.74,3.993-7.336c1.017-2.705,1.69-5.591,1.953-8.362c0.28-3.029,0.165-6.008-0.337-8.834
c-0.525-3.018-1.474-6.037-2.74-8.716c-1.358-2.896-3.076-5.563-5.088-7.908c-2.145-2.518-4.571-4.704-7.214-6.492
c-2.801-1.901-5.788-3.405-8.88-4.471c-3.294-1.132-6.666-1.818-10.036-2.041c-3.552-0.223-7.076,0.003-10.462,0.688
c-3.555,0.715-6.982,1.891-10.204,3.503c-3.358,1.688-6.436,3.777-9.141,6.2c-2.845,2.544-5.328,5.434-7.379,8.587
c-2.15,3.299-3.833,6.829-4.997,10.477c-1.237,3.84-1.956,7.774-2.138,11.692c-0.191,4.113,0.156,8.188,1.028,12.104
c0.906,4.095,2.332,8.022,4.24,11.679c1.992,3.812,4.453,7.311,7.319,10.409c2.993,3.225,6.348,6.012,9.974,8.29
c3.784,2.376,7.838,4.234,12.062,5.527c4.381,1.332,8.866,2.079,13.336,2.227c0.582,0.019,1.165,0.027,1.746,0.027
c4.078,0,8.107-0.464,11.988-1.38c4.626-1.085,9.061-2.761,13.182-4.981c4.257-2.297,8.174-5.128,11.641-8.411
c3.59-3.402,6.694-7.226,9.227-11.362c2.615-4.277,4.652-8.861,6.061-13.637c1.445-4.943,2.231-9.996,2.335-15.011
C587.607,226.516,587.045,221.347,585.82,216.386"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 8.2 KiB

View File

@ -1,110 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.4, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="595.279px" height="419.531px" viewBox="0 0 595.279 419.531" enable-background="new 0 0 595.279 419.531"
xml:space="preserve">
<g>
<defs>
<rect id="SVGID_1_" x="6.973" y="169.602" width="580.536" height="116.927"/>
</defs>
<clipPath id="SVGID_2_">
<use xlink:href="#SVGID_1_" overflow="visible"/>
</clipPath>
<path clip-path="url(#SVGID_2_)" d="M415.848,234.446c1.263-7.151,7.572-14.584,17.247-14.584c9.114,0,15.563,6.591,15.705,14.584
H415.848z M448.519,258.001c-2.664,5.892-8.272,8.834-15.144,8.834c-10.798,0-18.51-8.834-18.368-20.471h42.767
c3.085,0,5.188-1.822,5.188-5.189v-4.485c-0.421-15.985-12.198-29.167-29.728-29.167c-19.91,0-32.109,15.986-32.109,35.477
c0,20.894,11.639,36.598,32.25,36.598c13.462,0,24.259-7.15,28.745-18.932c1.264-3.363-0.562-6.17-3.926-6.17h-4.207
C451.604,254.496,449.781,255.337,448.519,258.001 M340.692,229.818c3.226-4.627,8.833-9.255,15.984-9.255
c10.798,0,17.809,10.655,17.809,22.996c0,12.901-6.449,22.854-17.809,22.854c-7.151,0-12.76-5.188-15.984-10.096V229.818z
M340.552,272.585c4.628,4.066,10.096,7.012,16.266,7.012c19.49,0.14,31.409-15.564,31.551-36.178
c0.141-20.473-11.779-35.896-31.41-35.896c-6.311,0-12.06,2.945-16.266,6.311v-32.25c0-2.804-2.243-5.048-5.188-5.048h-3.646
c-2.806,0-4.908,2.244-4.908,5.048v91.842c0,2.807,2.104,5.049,4.908,5.049h3.506c2.943,0,4.627-2.104,5.048-4.907L340.552,272.585
z M285.587,187.612c0,5.329,3.926,9.114,9.115,9.114c5.188,0,9.255-3.785,9.255-9.114c0-5.328-4.067-9.254-9.255-9.254
C289.513,178.358,285.587,182.284,285.587,187.612 M287.971,273.425c0,2.807,2.104,5.049,4.908,5.049h3.505
c2.804,0,5.048-2.242,5.048-5.049v-59.732c0-2.804-1.823-5.047-4.908-5.047h-3.646c-2.804,0-4.908,2.244-4.908,5.047
L287.971,273.425L287.971,273.425z M233.566,273.425c0,2.807,2.244,5.049,5.048,5.049h3.646c3.226,0,5.048-2.242,5.048-5.049
v-42.063c2.665-5.188,8.694-10.377,16.827-10.377h2.524c2.943,0,5.188-2.103,5.188-5.048v-3.786c0-2.804-1.963-4.627-4.908-4.627
h-2.523c-6.45,0-13.603,4.347-17.107,9.254l-0.14-3.226c-0.28-2.803-1.963-4.907-4.908-4.907h-3.646
c-2.804,0-5.048,2.244-5.048,5.047V273.425L233.566,273.425z M201.036,231.361c0.981,2.805,3.646,3.646,6.311,2.805l3.785-1.263
c3.085-0.981,3.787-3.505,2.945-5.89c-3.927-11.498-13.32-19.491-28.043-19.491c-19.491,0-31.83,15.845-31.83,36.037
c0,20.472,11.638,36.037,31.549,36.037c14.864,0,26.923-9.815,30.007-22.716c0.702-2.945-1.122-5.328-4.066-5.328h-4.346
c-2.665,0-4.768,1.4-5.469,3.926c-2.104,6.73-8.133,10.938-15.565,11.078c-11.498,0.14-18.509-10.096-18.509-22.997
c0-13.04,6.871-23.417,18.229-23.276C193.324,220.423,198.513,224.63,201.036,231.361 M98.117,257.302
c-0.281-2.664-2.385-4.768-5.188-4.768h-4.066c-2.664,0-4.627,2.104-4.486,4.768c0.421,12.898,10.938,22.295,28.043,22.295
c17.948,0,28.466-9.814,28.466-21.875c0-10.938-7.012-17.247-17.107-19.21c-5.327-0.981-11.638-2.244-16.686-3.646
c-3.646-0.982-6.45-3.367-6.45-6.592c0-4.486,3.786-8.553,11.639-8.553c7.151,0,11.219,4.207,12.06,7.57
c0.701,2.666,3.085,4.207,5.468,4.207h3.926c2.805,0,4.908-1.824,4.487-4.768c-1.542-11.078-11.217-19.21-25.801-19.21
c-15.003,0-25.52,8.554-25.52,20.894c0,10.516,7.993,16.125,16.125,18.51c6.029,1.822,11.639,3.084,17.668,4.205
c3.786,0.701,6.591,3.086,6.591,6.871c0,5.328-5.049,9.254-14.724,9.115C104.146,266.977,98.537,262.63,98.117,257.302
M31.091,266.274c-6.312-0.562-10.096-3.505-10.096-8.132c0-4.908,3.785-7.854,9.675-7.854c4.065,0,7.432-0.14,11.217-0.42
c3.225-0.279,6.59-0.843,8.834-2.805v10.656c-0.702,4.768-4.767,7.854-11.218,8.553C36.839,266.557,33.895,266.557,31.091,266.274
M8.095,228.835c-0.561,2.947,1.542,4.771,4.207,4.771h4.206c2.945,0,5.048-1.543,5.609-4.207
c1.121-5.469,5.608-9.256,14.303-9.256c9.675,0,14.442,5.749,14.302,13.741v0.701c-1.402,2.244-5.468,3.226-8.974,3.365
c-3.506,0.141-6.45,0.28-10.797,0.28c-14.022,0-23.979,6.729-23.979,20.052c0,13.039,9.535,20.332,24.118,21.033
c2.664,0.141,5.188,0,7.572-0.143c5.468-0.279,11.356-2.805,14.441-6.869c1.402,3.085,6.59,6.169,10.938,6.169h2.804
c2.945,0,5.048-1.821,5.048-4.769v-3.924c0-2.806-1.963-4.629-4.627-4.629c-1.682,0-2.944-1.121-2.944-2.804v-27.483
c0-16.266-11.778-27.343-28.044-27.343C21.696,207.523,10.338,215.655,8.095,228.835"/>
</g>
<g>
<defs>
<rect id="SVGID_3_" x="6.973" y="169.602" width="580.536" height="116.927"/>
</defs>
<clipPath id="SVGID_4_">
<use xlink:href="#SVGID_3_" overflow="visible"/>
</clipPath>
</g>
<g>
<path d="M519.088,182.75c1.375-0.154,2.759-0.25,4.148-0.297l-0.362-12.773c-1.799,0.062-3.593,0.197-5.381,0.404L519.088,182.75z
M527.134,220.031c-0.267-0.029-0.7-0.071-1.249-0.087c-0.88-0.028-2.051,0.002-3.311,0.233c-1.508,0.298-3.103,0.854-4.393,1.523
c-0.861,0.445-2.532,1.424-4.005,2.886c-1.244,1.203-2.38,2.673-3.188,4.123c-0.496,0.885-0.924,1.843-1.286,2.822l12.254,3.784
c0.061-0.126,0.114-0.264,0.182-0.379c0.2-0.364,0.574-0.844,0.976-1.228c0.217-0.217,0.636-0.514,0.948-0.676
c0.197-0.105,0.648-0.263,0.895-0.31c0.114-0.023,0.382-0.028,0.59-0.015c0.047,0.002,0.093,0.002,0.129,0.007
c3.502,0.422,6.671-2.107,7.073-5.613C533.15,223.599,530.636,220.434,527.134,220.031 M509.485,171.556
c-0.965,0.248-1.918,0.52-2.867,0.811l3.677,12.229c0.774-0.238,1.552-0.465,2.342-0.666c2.006-0.507,5.735-1.088,5.557-1.064
l-1.659-12.666C516.711,170.178,511.983,170.925,509.485,171.556 M574.729,231.505c-0.075,3.552-0.609,7.126-1.555,10.646
l12.34,3.361c1.215-4.536,1.887-9.148,1.982-13.733c0.025-1.19,0.01-2.376-0.033-3.558l-12.763,0.422
C574.735,229.595,574.749,230.547,574.729,231.505 M498.38,175.332l5.607,11.479c0.501-0.219,1.01-0.424,1.519-0.627l-4.727-11.859
C499.972,174.647,499.171,174.982,498.38,175.332 M561.09,262.52c-2.652,2.512-5.652,4.679-8.923,6.44
c-3.127,1.689-6.503,2.963-10.041,3.793c-3.351,0.79-6.843,1.133-10.397,1.018c-1.92-0.06-3.849-0.292-5.767-0.65l-2.308,12.554
c2.544,0.472,5.104,0.776,7.664,0.862c0.58,0.019,1.162,0.024,1.742,0.024c4.08,0,8.11-0.465,11.988-1.378
c4.625-1.086,9.062-2.764,13.184-4.982c4.258-2.295,8.175-5.127,11.641-8.409c0.533-0.507,1.034-1.042,1.55-1.567l-9.139-8.914
C561.889,261.717,561.502,262.127,561.09,262.52 M568.204,253.764c-1.188,1.943-2.562,3.789-4.072,5.536l9.695,8.305
c1.949-2.264,3.73-4.653,5.274-7.177c1.848-3.021,3.401-6.199,4.653-9.488l-11.935-4.569
C570.85,248.925,569.647,251.407,568.204,253.764 M585.971,217.079l-12.446,2.881c0.341,1.46,0.604,2.943,0.799,4.444l12.673-1.697
C586.747,220.808,586.404,218.927,585.971,217.079 M542.637,172.095c-1.34-0.377-2.687-0.713-4.038-1.004l-2.693,12.482
c1.091,0.237,2.175,0.505,3.253,0.809c0.679,0.194,1.349,0.426,2.023,0.649l4.046-12.131
C544.368,172.616,543.507,172.343,542.637,172.095 M528.501,169.732l-0.751,12.769c1.538,0.083,3.074,0.214,4.607,0.436
l1.805-12.643C532.281,170.021,530.393,169.835,528.501,169.732 M580.102,201.75c-2.626-4.757-5.824-9.101-9.507-12.903
c-3.818-3.953-8.107-7.369-12.74-10.146c-2.381-1.429-4.843-2.696-7.369-3.796l-5.08,11.717c2.012,0.878,3.975,1.888,5.878,3.032
c3.683,2.203,7.086,4.916,10.133,8.068c2.9,2.998,5.427,6.43,7.507,10.2c1.355,2.449,2.471,5.05,3.375,7.742l12.098-4.121
C583.249,208.139,581.818,204.859,580.102,201.75 M531.03,248.33c-0.688-0.098-1.407-0.274-2.113-0.499l-3.888,12.154
c1.395,0.446,2.816,0.789,4.215,0.987c0.933,0.136,1.886,0.204,2.842,0.236l0.135-12.767
C531.818,248.416,531.422,248.384,531.03,248.33 M538.768,247.306c-1.088,0.461-2.356,0.807-3.59,1.002l1.932,12.615
c2.294-0.358,4.577-0.985,6.653-1.863c0.313-0.135,0.623-0.288,0.931-0.436l-5.345-11.588
C539.156,247.128,538.963,247.225,538.768,247.306 M521.705,272.095c-3.141-0.959-6.169-2.349-8.997-4.127
c-2.683-1.684-5.173-3.757-7.402-6.157c-0.494-0.532-0.968-1.089-1.432-1.655l-9.938,8.017c0.644,0.794,1.312,1.569,2.007,2.318
c2.994,3.229,6.351,6.016,9.975,8.294c3.776,2.37,7.824,4.225,12.037,5.518l3.779-12.197
C521.725,272.098,521.715,272.096,521.705,272.095 M524.923,245.663c-0.729-0.596-1.46-1.387-2.013-2.187
c-0.47-0.671-0.903-1.533-1.205-2.407c-0.229-0.66-0.394-1.527-0.438-2.339c-0.002-0.009,0-0.016,0-0.021l-12.76,0.114
c0.005,0.202,0,0.41,0.011,0.608c0.076,1.411,0.333,3.571,1.128,5.828c0.677,1.972,1.648,3.887,2.795,5.524
c1.222,1.754,2.734,3.396,4.371,4.743c0.592,0.483,1.215,0.935,1.851,1.365l7.059-10.633
C525.446,246.069,525.173,245.869,524.923,245.663 M499.942,254.168c-1.387-2.659-2.426-5.527-3.093-8.531
c-0.631-2.822-0.876-5.763-0.738-8.749c0.13-2.788,0.646-5.605,1.542-8.384c0.81-2.537,2.03-5.098,3.537-7.408
c0.197-0.303,0.418-0.596,0.627-0.894l-10.385-7.42c-0.317,0.447-0.645,0.887-0.942,1.346c-2.149,3.297-3.832,6.831-4.995,10.477
c-1.237,3.84-1.958,7.774-2.139,11.692c-0.191,4.115,0.156,8.188,1.027,12.105c0.907,4.096,2.33,8.021,4.239,11.682
c0.576,1.099,1.197,2.159,1.851,3.204l10.814-6.779C500.815,255.746,500.361,254.972,499.942,254.168 M506.385,215.056
c1.871-1.675,4.013-3.124,6.35-4.301c0.679-0.338,1.389-0.642,2.109-0.93l-4.726-11.859c-1.057,0.419-2.097,0.868-3.108,1.375
c-3.357,1.688-6.437,3.778-9.142,6.199c-1.511,1.353-2.915,2.81-4.212,4.345l9.735,8.265
C504.323,217.053,505.324,216.006,506.385,215.056 M538.66,211.746l6.869-10.757c-1.771-1.12-3.602-2.104-5.488-2.904
l-4.987,11.759C536.281,210.365,537.496,211.015,538.66,211.746 M544.099,216.451c1.263,1.47,2.38,3.214,3.243,5.053
c0.788,1.67,1.383,3.564,1.719,5.489c0.302,1.7,0.369,3.582,0.196,5.438c-0.154,1.644-0.565,3.395-1.177,5.018
c-0.578,1.511-1.393,3.005-2.356,4.319c-0.889,1.215-2,2.365-3.224,3.335c-0.011,0.007-0.022,0.017-0.034,0.022l7.857,10.063
c0.039-0.026,0.079-0.057,0.116-0.084c2.104-1.669,4.038-3.673,5.587-5.794c1.624-2.215,3.002-4.738,3.994-7.335
c1.015-2.705,1.69-5.59,1.952-8.362c0.28-3.029,0.166-6.008-0.337-8.834c-0.525-3.018-1.476-6.039-2.74-8.718
c-1.358-2.895-3.075-5.562-5.09-7.907c-1.05-1.238-2.173-2.39-3.354-3.457l-8.577,9.463
C542.658,214.867,543.405,215.637,544.099,216.451 M518.809,208.576l-2.863-12.439c0.422-0.098,0.842-0.213,1.27-0.297
c3.387-0.686,6.912-0.911,10.459-0.687c2.167,0.142,4.326,0.497,6.471,1.016l-2.969,12.417c-1.45-0.353-2.91-0.595-4.326-0.69
c-2.391-0.156-4.854,0.005-7.113,0.461C519.429,208.419,519.117,208.503,518.809,208.576"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

View File

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<browserconfig>
<msapplication>
<tile>
<square70x70logo src="images/hq-favicons/mstile-70x70.png"/>
<square150x150logo src="images/hq-favicons/mstile-150x150.png"/>
<square310x310logo src="images/hq-favicons/mstile-310x310.png"/>
<wide310x150logo src="images/hq-favicons/mstile-310x150.png"/>
<TileColor>#00aba9</TileColor>
</tile>
</msapplication>
</browserconfig>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

View File

@ -1,35 +0,0 @@
{
"name": "Ascribe",
"icons": [
{
"src": "images\/hq-favicons\/android-chrome-36x36.png",
"sizes": "36x36",
"type": "image\/png",
"density": "0.75"
},
{
"src": "images\/hq-favicons\/android-chrome-48x48.png",
"sizes": "48x48",
"type": "image\/png",
"density": "1.0"
},
{
"src": "images\/hq-favicons\/android-chrome-72x72.png",
"sizes": "72x72",
"type": "image\/png",
"density": "1.5"
},
{
"src": "images\/hq-favicons\/android-chrome-96x96.png",
"sizes": "96x96",
"type": "image\/png",
"density": "2.0"
},
{
"src": "images\/hq-favicons\/android-chrome-144x144.png",
"sizes": "144x144",
"type": "image\/png",
"density": "3.0"
}
]
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

View File

@ -0,0 +1,58 @@
'use strict';
import React from 'react/addons';
const { string, object } = React.PropTypes;
/**
* Originally, this button was introduced for `RegisterPieceForm`.
* The underlying problem that lead to the implementation was that multiple `InputFineuploader`s
* where displayed in one form.
* For the form's submit button always to represent an applicable state we had to save
* the ready states of the multiple uploaders in `RegisterPieceForm`.
* However, on each invocation of `this.setState`, we were re-rendering the form again,
* which caused (if the user had the file-selector open) a detachment between user input and
* displayed page.
*
* This button helps to outsource the state of the form's readiness to another component,
* to solve the problem.
*/
const FormSubmitButton = React.createClass({
propTypes: {
defaultReadyStates: object.isRequired,
label: string.isRequired
},
getInitialState() {
return {
readyStates: this.props.defaultReadyStates
};
},
setReadyStateForKey(key, state) {
const readyStates = React.addons.update(this.state.readyStates, { [key]: { $set: state } });
this.setState({ readyStates });
},
render() {
const { label } = this.props;
const { readyStates } = this.state;
// Reduce all readyStates to a single boolean
const ready = Object.keys(readyStates)
.reduce((defaultState, stateKey) => {
return defaultState && readyStates[stateKey];
}, true);
return (
<button
type="submit"
className="btn btn-default btn-wide"
disabled={!ready}>
{label}
</button>
);
}
});
export default FormSubmitButton;

View File

@ -16,7 +16,6 @@ import { getLangText } from '../../utils/lang_utils';
let FurtherDetailsFileuploader = React.createClass({
propTypes: {
label: React.PropTypes.string,
uploadStarted: React.PropTypes.func,
pieceId: React.PropTypes.number,
otherData: React.PropTypes.arrayOf(React.PropTypes.object),
setIsUploadReady: React.PropTypes.func,
@ -50,7 +49,6 @@ let FurtherDetailsFileuploader = React.createClass({
name="other_data_key"
label={this.props.label}>
<ReactS3FineUploader
uploadStarted={this.props.uploadStarted}
keyRoutine={{
url: AppConstants.serverUrl + 's3/key/',
fileClass: 'otherdata',

View File

@ -130,7 +130,7 @@ let Form = React.createClass({
if (ref.state && 'value' in ref.state) {
// An input can also provide an `Object` as a value
// which we're going to merge with `data` (overwrites)
if(ref.state.value.constructor === Object) {
if(ref.state.value && ref.state.value.constructor === Object) {
Object.assign(data, ref.state.value);
} else {
data[ref.props.name] = ref.state.value;

View File

@ -51,9 +51,9 @@ let CreateContractForm = React.createClass({
this.refs.form.reset();
},
submitFileName(fileName) {
submitFile({ originalName }) {
this.setState({
contractName: fileName
contractName: originalName
});
this.refs.form.submit();
@ -69,7 +69,7 @@ let CreateContractForm = React.createClass({
name="blob"
label={getLangText('Contract file (*.pdf only, max. 50MB per contract)')}>
<InputFineUploader
submitFileName={this.submitFileName}
submitFile={this.submitFile}
keyRoutine={{
url: AppConstants.serverUrl + 's3/key/',
fileClass: 'contract'

View File

@ -8,6 +8,8 @@ import UserActions from '../../actions/user_actions';
import Form from './form';
import Property from './property';
import InputFineUploader from './input_fineuploader';
import UploadButton from '../ascribe_uploader/ascribe_upload_button/upload_button';
import FormSubmitButton from '../ascribe_buttons/form_submit_button';
import ApiUrls from '../../constants/api_urls';
import AppConstants from '../../constants/application_constants';
@ -47,7 +49,7 @@ let RegisterPieceForm = React.createClass({
getInitialState(){
return mergeOptions(
{
isUploadReady: false
digitalWorkFile: null
},
UserStore.getState()
);
@ -66,31 +68,88 @@ let RegisterPieceForm = React.createClass({
this.setState(state);
},
setIsUploadReady(isReady) {
this.setState({
isUploadReady: isReady
});
/**
* This method is overloaded so that we can track the ready-state
* of each uploader in the component
* @param {string} uploaderKey Name of the uploader's key to track
*/
setIsUploadReady(uploaderKey) {
return (isUploadReady) => {
// See documentation of `FormSubmitButton` for more detailed information
// on this.
this.refs.submitButton.setReadyStateForKey(uploaderKey, isUploadReady);
};
},
handleChangedDigitalWork(digitalWorkFile) {
if (digitalWorkFile &&
(digitalWorkFile.status === 'deleted' || digitalWorkFile.status === 'canceled')) {
this.refs.form.refs.thumbnail_file.reset();
// Manually we need to set the ready state for `thumbnailKeyReady` back
// to `true` as `ReactS3Fineuploader`'s `reset` method triggers
// `setIsUploadReady` with `false`
this.refs.submitButton.setReadyStateForKey('thumbnailKeyReady', true);
this.setState({ digitalWorkFile: null });
} else {
this.setState({ digitalWorkFile });
}
},
handleChangedThumbnail(thumbnailFile) {
const { digitalWorkFile } = this.state;
const { fineuploader } = this.refs.digitalWorkFineUploader.refs;
fineuploader.setThumbnailForFileId(
digitalWorkFile.id,
// if thumbnail was delete, we delete it from the display as well
thumbnailFile.status !== 'deleted' ? thumbnailFile.url : null
);
},
isThumbnailDialogExpanded() {
const { digitalWorkFile } = this.state;
if(digitalWorkFile) {
const { type: mimeType } = digitalWorkFile;
const mimeSubType = mimeType && mimeType.split('/').length ? mimeType.split('/')[1]
: 'unknown';
return AppConstants.supportedThumbnailFileFormats.indexOf(mimeSubType) === -1;
} else {
return false;
}
},
render() {
let currentUser = this.state.currentUser;
let enableLocalHashing = currentUser && currentUser.profile ? currentUser.profile.hash_locally : false;
enableLocalHashing = enableLocalHashing && this.props.enableLocalHashing;
const { disabled,
handleSuccess,
submitMessage,
headerMessage,
isFineUploaderActive,
isFineUploaderEditable,
location,
children,
enableLocalHashing } = this.props;
const { currentUser} = this.state;
const profileHashLocally = currentUser && currentUser.profile ? currentUser.profile.hash_locally : false;
const hashLocally = profileHashLocally && enableLocalHashing;
return (
<Form
disabled={this.props.disabled}
disabled={disabled}
className="ascribe-form-bordered"
ref='form'
url={ApiUrls.pieces_list}
handleSuccess={this.props.handleSuccess}
handleSuccess={handleSuccess}
buttons={
<button
type="submit"
className="btn btn-default btn-wide"
disabled={!this.state.isUploadReady || this.props.disabled}>
{this.props.submitMessage}
</button>
<FormSubmitButton
ref="submitButton"
defaultReadyStates={{
digitalWorkKeyReady: false,
thumbnailKeyReady: true
}}
label={submitMessage}/>
}
spinner={
<span className="btn btn-default btn-wide btn-spinner">
@ -98,12 +157,14 @@ let RegisterPieceForm = React.createClass({
</span>
}>
<div className="ascribe-form-header">
<h3>{this.props.headerMessage}</h3>
<h3>{headerMessage}</h3>
</div>
<Property
name="digital_work_key"
ignoreFocus={true}>
ignoreFocus={true}
label={getLangText('Your Work')}>
<InputFineUploader
ref={ref => this.refs.digitalWorkFineUploader = ref}
keyRoutine={{
url: AppConstants.serverUrl + 's3/key/',
fileClass: 'digitalwork'
@ -112,12 +173,43 @@ let RegisterPieceForm = React.createClass({
url: ApiUrls.blob_digitalworks
}}
validation={AppConstants.fineUploader.validation.registerWork}
setIsUploadReady={this.setIsUploadReady}
setIsUploadReady={this.setIsUploadReady('digitalWorkKeyReady')}
isReadyForFormSubmission={formSubmissionValidation.atLeastOneUploadedFile}
isFineUploaderActive={this.props.isFineUploaderActive}
disabled={!this.props.isFineUploaderEditable}
isFineUploaderActive={isFineUploaderActive}
disabled={!isFineUploaderEditable}
enableLocalHashing={hashLocally}
uploadMethod={location.query.method}
handleChangedFile={this.handleChangedDigitalWork}/>
</Property>
<Property
name="thumbnail_file"
expanded={this.isThumbnailDialogExpanded()}>
<InputFineUploader
ref={ref => this.refs.thumbnailFineUploader = ref}
fileInputElement={UploadButton({ className: 'btn btn-secondary btn-sm' })}
createBlobRoutine={{
url: ApiUrls.blob_thumbnails
}}
handleChangedFile={this.handleChangedThumbnail}
isReadyForFormSubmission={formSubmissionValidation.fileOptional}
keyRoutine={{
url: AppConstants.serverUrl + 's3/key/',
fileClass: 'thumbnail'
}}
validation={{
itemLimit: AppConstants.fineUploader.validation.registerWork.itemLimit,
sizeLimit: AppConstants.fineUploader.validation.additionalData.sizeLimit,
allowedExtensions: ['png', 'jpg', 'jpeg', 'gif']
}}
setIsUploadReady={this.setIsUploadReady('thumbnailKeyReady')}
fileClassToUpload={{
singular: getLangText('Select representative image'),
plural: getLangText('Select representative images')
}}
isFineUploaderActive={isFineUploaderActive}
disabled={!isFineUploaderEditable}
enableLocalHashing={enableLocalHashing}
uploadMethod={this.props.location.query.method} />
uploadMethod={location.query.method} />
</Property>
<Property
name='artist_name'
@ -144,7 +236,7 @@ let RegisterPieceForm = React.createClass({
min={1}
required/>
</Property>
{this.props.children}
{children}
</Form>
);
}

View File

@ -11,7 +11,6 @@ import GlobalNotificationActions from '../../actions/global_notification_actions
import Form from './form';
import Property from './property';
import PropertyCollapsible from './property_collapsible';
import InputTextAreaToggable from './input_textarea_toggable';
import ApiUrls from '../../constants/api_urls';
@ -122,9 +121,10 @@ let SendContractAgreementForm = React.createClass({
required/>
</Property>
{this.getContracts()}
<PropertyCollapsible
<Property
name='appendix'
checkboxLabel={getLangText('Add appendix to the contract')}>
checkboxLabel={getLangText('Add appendix to the contract')}
expanded={false}>
<span>{getLangText('Appendix')}</span>
{/* We're using disabled on a form here as PropertyCollapsible currently
does not support the disabled + overrideForm functionality */}
@ -132,7 +132,7 @@ let SendContractAgreementForm = React.createClass({
rows={1}
disabled={false}
placeholder={getLangText('This will be appended to the contract selected above')}/>
</PropertyCollapsible>
</Property>
</Form>
);
}

View File

@ -10,13 +10,13 @@ import AppConstants from '../../constants/application_constants';
import { getCookie } from '../../utils/fetch_api_utils';
const { func, bool, object, shape, string, number, arrayOf } = React.PropTypes;
const { func, bool, shape, string, number, arrayOf } = React.PropTypes;
const InputFineUploader = React.createClass({
propTypes: {
setIsUploadReady: func,
isReadyForFormSubmission: func,
submitFileName: func,
submitFile: func,
fileInputElement: func,
areAssetsDownloadable: bool,
@ -51,6 +51,7 @@ const InputFineUploader = React.createClass({
singular: string,
plural: string
}),
handleChangedFile: func,
// Provided by `Property`
onChange: React.PropTypes.func
@ -79,8 +80,8 @@ const InputFineUploader = React.createClass({
this.props.onChange({ target: { value: this.state.value } });
}
if(typeof this.props.submitFileName === 'function') {
this.props.submitFileName(file.originalName);
if(typeof this.props.submitFile === 'function') {
this.props.submitFile(file);
}
},
@ -108,8 +109,8 @@ const InputFineUploader = React.createClass({
keyRoutine,
setIsUploadReady,
uploadMethod,
validation } = this.props;
validation,
handleChangedFile } = this.props;
let editable = isFineUploaderActive;
// if disabled is actually set by property, we want to override
@ -146,7 +147,8 @@ const InputFineUploader = React.createClass({
}}
enableLocalHashing={enableLocalHashing}
uploadMethod={uploadMethod}
fileClassToUpload={fileClassToUpload} />
fileClassToUpload={fileClassToUpload}
handleChangedFile={handleChangedFile}/>
);
}
});

View File

@ -248,7 +248,6 @@ const Property = React.createClass({
// if the component is actually being shown (!== 'expanded === false')
if((this.state.expanded && this.props.checkboxLabel) || !this.props.checkboxLabel) {
return ReactAddons.Children.map(this.props.children, (child) => {
// Since refs will be overriden by this functions return statement,
// we still want to be able to define refs for nested `Form` or `Property`
// children, which is why we're upfront simply invoking the callback-ref-
@ -307,7 +306,6 @@ const Property = React.createClass({
render() {
let footer = null;
let style = Object.assign({}, this.props.style);
if(this.props.footer){
footer = (
@ -317,18 +315,11 @@ const Property = React.createClass({
);
}
if (!this.state.expanded) {
style.paddingBottom = 0;
}
if (!this.props.editable) {
style.cursor = 'not-allowed';
}
return (
<div
className={'ascribe-property-wrapper ' + this.getClassName()}
onClick={this.handleFocus}
style={style}>
style={this.props.style}>
{this.getCheckbox()}
<Panel
collapsible
@ -336,7 +327,7 @@ const Property = React.createClass({
className="bs-custom-panel">
<div className={'ascribe-property ' + this.props.className}>
{this.getLabelAndErrors()}
{this.renderChildren(style)}
{this.renderChildren(this.props.style)}
{footer}
</div>
</Panel>

View File

@ -1,96 +0,0 @@
'use strict';
import React from 'react';
import ReactAddons from 'react/addons';
import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger';
import Tooltip from 'react-bootstrap/lib/Tooltip';
import Panel from 'react-bootstrap/lib/Panel';
let PropertyCollapsible = React.createClass({
propTypes: {
children: React.PropTypes.arrayOf(React.PropTypes.element),
checkboxLabel: React.PropTypes.string,
tooltip: React.PropTypes.string
},
getInitialState() {
return {
show: false
};
},
handleFocus() {
this.refs.checkboxCollapsible.getDOMNode().checked = !this.refs.checkboxCollapsible.getDOMNode().checked;
this.setState({
show: this.refs.checkboxCollapsible.getDOMNode().checked
});
},
handleChange(event) {
this.setState({value: event.target.value});
},
renderChildren() {
if(this.state.show) {
return ReactAddons.Children.map(this.props.children, (child) => {
return ReactAddons.addons.cloneWithProps(child, {
onChange: this.handleChange
});
});
}
},
reset() {
// If the child input is a native HTML element, it will be reset automatically
// by the DOM.
// However, we need to collapse this component again.
this.setState(this.getInitialState());
},
render() {
let tooltip = <span/>;
if (this.props.tooltip){
tooltip = (
<Tooltip>
{this.props.tooltip}
</Tooltip>);
}
let style = this.state.show ? {} : {paddingBottom: 0};
return (
<div
className={'ascribe-property-wrapper'}
style={style}>
<OverlayTrigger
delay={500}
placement="top"
overlay={tooltip}>
<div
className="ascribe-property-collapsible-toggle"
onClick={this.handleFocus}
onFocus={this.handleFocus}>
<input
onChange={this.handleChange}
type="checkbox"
ref="checkboxCollapsible"/>
{/* PLEASE LEAVE THE SPACE BETWEEN LABEL and this.props.label */}
<span className="checkbox"> {this.props.checkboxLabel}</span>
</div>
</OverlayTrigger>
<Panel
collapsible
expanded={this.state.show}
className="bs-custom-panel">
<div className="ascribe-property">
{this.renderChildren()}
</div>
</Panel>
</div>
);
}
});
export default PropertyCollapsible;

View File

@ -55,7 +55,7 @@ let ContractSettingsUpdateButton = React.createClass({
render() {
return (
<ReactS3FineUploader
fileInputElement={UploadButton}
fileInputElement={UploadButton()}
keyRoutine={{
url: AppConstants.serverUrl + 's3/key/',
fileClass: 'contract'

View File

@ -5,22 +5,31 @@ import React from 'react';
import FileDragAndDropPreviewImage from './file_drag_and_drop_preview_image';
import FileDragAndDropPreviewOther from './file_drag_and_drop_preview_other';
import { getLangText } from '../../../utils/lang_utils';
import { truncateTextAtCharIndex } from '../../../utils/general_utils';
import { extractFileExtensionFromString } from '../../../utils/file_utils';
let FileDragAndDropPreview = React.createClass({
const { shape, string, number, func, bool } = React.PropTypes;
const FileDragAndDropPreview = React.createClass({
propTypes: {
file: React.PropTypes.shape({
url: React.PropTypes.string,
type: React.PropTypes.string
file: shape({
url: string,
type: string,
progress: number,
id: number,
status: string,
s3Url: string,
s3UrlSafe: string
}).isRequired,
handleDeleteFile: React.PropTypes.func,
handleCancelFile: React.PropTypes.func,
handlePauseFile: React.PropTypes.func,
handleResumeFile: React.PropTypes.func,
areAssetsDownloadable: React.PropTypes.bool,
areAssetsEditable: React.PropTypes.bool
handleDeleteFile: func,
handleCancelFile: func,
handlePauseFile: func,
handleResumeFile: func,
areAssetsDownloadable: bool,
areAssetsEditable: bool,
numberOfDisplayedFiles: number
},
toggleUploadProcess() {
@ -32,14 +41,21 @@ let FileDragAndDropPreview = React.createClass({
},
handleDeleteFile() {
// handleDeleteFile is optional, so if its not submitted,
// don't run it
// On the other hand, if the files progress is not yet at a 100%,
// just run fineuploader.cancel
if(this.props.handleDeleteFile && this.props.file.progress === 100) {
this.props.handleDeleteFile(this.props.file.id);
} else if(this.props.handleCancelFile && this.props.file.progress !== 100) {
this.props.handleCancelFile(this.props.file.id);
const { handleDeleteFile,
handleCancelFile,
file } = this.props;
// `handleDeleteFile` is optional, so if its not submitted, don't run it
//
// For delete though, we only want to trigger it, when we're sure that
// the file has *completely* been uploaded to S3 and call now also be
// deleted using an HTTP DELETE request.
if (handleDeleteFile &&
file.progress === 100 &&
(file.status === 'upload successful' || file.status === 'online') &&
file.s3UrlSafe) {
handleDeleteFile(file.id);
} else if(handleCancelFile) {
handleCancelFile(file.id);
}
},
@ -50,44 +66,80 @@ let FileDragAndDropPreview = React.createClass({
}
},
getFileName() {
const { numberOfDisplayedFiles, file } = this.props;
if(numberOfDisplayedFiles === 1) {
return (
<span className="file-name">
{truncateTextAtCharIndex(file.name, 30, '(...).' + extractFileExtensionFromString(file.name))}
</span>
);
} else {
return null;
}
},
getRemoveButton() {
if(this.props.areAssetsEditable) {
return (
<div className="delete-file">
<span
className="glyphicon glyphicon-remove text-center"
aria-hidden="true"
title={getLangText('Remove file')}
onClick={this.handleDeleteFile}/>
</div>
);
} else {
return null;
}
},
render() {
const { file,
areAssetsDownloadable,
numberOfDisplayedFiles } = this.props;
const innerStyle = numberOfDisplayedFiles === 1 ? { verticalAlign: 'middle' } : null;
const outerStyle = numberOfDisplayedFiles !== 1 ? { display: 'inline-block' } : null;
let previewElement;
let removeBtn;
// Decide whether an image or a placeholder picture should be displayed
if(this.props.file.type.split('/')[0] === 'image') {
previewElement = (<FileDragAndDropPreviewImage
onClick={this.handleDeleteFile}
progress={this.props.file.progress}
url={this.props.file.url}
toggleUploadProcess={this.toggleUploadProcess}
areAssetsDownloadable={this.props.areAssetsDownloadable}
downloadUrl={this.props.file.s3UrlSafe}/>);
// If a file has its `thumbnailUrl` defined, then we display it also as an image
if(file.type.split('/')[0] === 'image' || file.thumbnailUrl) {
previewElement = (
<FileDragAndDropPreviewImage
onClick={this.handleDeleteFile}
progress={file.progress}
url={file.thumbnailUrl || file.url}
toggleUploadProcess={this.toggleUploadProcess}
areAssetsDownloadable={areAssetsDownloadable}
downloadUrl={file.s3UrlSafe}
showProgress={numberOfDisplayedFiles > 1} />
);
} else {
previewElement = (<FileDragAndDropPreviewOther
onClick={this.handleDeleteFile}
progress={this.props.file.progress}
type={this.props.file.type.split('/')[1]}
toggleUploadProcess={this.toggleUploadProcess}
areAssetsDownloadable={this.props.areAssetsDownloadable}
downloadUrl={this.props.file.s3UrlSafe}/>);
}
if(this.props.areAssetsEditable) {
removeBtn = (<div className="delete-file">
<span
className="glyphicon glyphicon-remove text-center"
aria-hidden="true"
title={getLangText('Remove file')}
onClick={this.handleDeleteFile}/>
</div>);
previewElement = (
<FileDragAndDropPreviewOther
onClick={this.handleDeleteFile}
progress={file.progress}
type={file.type.split('/')[1]}
toggleUploadProcess={this.toggleUploadProcess}
areAssetsDownloadable={areAssetsDownloadable}
downloadUrl={file.s3UrlSafe}
showProgress={numberOfDisplayedFiles > 1} />
);
}
return (
<div
className="file-drag-and-drop-position">
{removeBtn}
{previewElement}
<div style={outerStyle}>
<div
style={innerStyle}
className="file-drag-and-drop-position">
{this.getRemoveButton()}
{previewElement}
</div>
{this.getFileName()}
</div>
);
}

View File

@ -3,16 +3,21 @@
import React from 'react';
import ProgressBar from 'react-bootstrap/lib/ProgressBar';
import AclProxy from '../../acl_proxy';
import AscribeSpinner from '../../ascribe_spinner';
import { getLangText } from '../../../utils/lang_utils';
let FileDragAndDropPreviewImage = React.createClass({
const { number, string, func, bool } = React.PropTypes;
const FileDragAndDropPreviewImage = React.createClass({
propTypes: {
progress: React.PropTypes.number,
url: React.PropTypes.string,
toggleUploadProcess: React.PropTypes.func,
downloadUrl: React.PropTypes.string,
areAssetsDownloadable: React.PropTypes.bool
progress: number,
url: string,
toggleUploadProcess: func,
downloadUrl: string,
areAssetsDownloadable: bool,
showProgress: bool
},
getInitialState() {
@ -33,40 +38,44 @@ let FileDragAndDropPreviewImage = React.createClass({
},
render() {
let imageStyle = {
backgroundImage: 'url("' + this.props.url + '")',
const { url,
progress,
areAssetsDownloadable,
downloadUrl,
showProgress } = this.props;
const imageStyle = {
backgroundImage: 'url("' + url + '")',
backgroundSize: 'cover'
};
let actionSymbol;
if(this.props.progress > 0 && this.props.progress < 99 && this.state.paused) {
actionSymbol = <span className="glyphicon glyphicon-pause action-file" aria-hidden="true" title={getLangText('Pause upload')} onClick={this.toggleUploadProcess}/>;
} else if(this.props.progress > 0 && this.props.progress < 99 && !this.state.paused) {
actionSymbol = <span className="glyphicon glyphicon-play action-file" aria-hidden="true" title={getLangText('Resume uploading')} onClick={this.toggleUploadProcess}/>;
} else if(this.props.progress === 100) {
// only if assets are actually downloadable, there should be a download icon if the process is already at
// 100%. If not, no actionSymbol should be displayed
if(this.props.areAssetsDownloadable) {
actionSymbol = <a href={this.props.downloadUrl} target="_blank" className="glyphicon glyphicon-download action-file" aria-hidden="true" title={getLangText('Download file')}/>;
}
} else {
// only if assets are actually downloadable, there should be a download icon if the process is already at
// 100%. If not, no actionSymbol should be displayed
if(progress === 100 && areAssetsDownloadable) {
actionSymbol = <a href={downloadUrl} target="_blank" className="glyphicon glyphicon-download action-file" aria-hidden="true" title={getLangText('Download file')}/>;
} else if(progress >= 0 && progress < 100) {
actionSymbol = (
<div className="spinner-file">
<AscribeSpinner color='dark-blue' size='md' />
</div>
);
} else {
actionSymbol = (
<span className='ascribe-icon icon-ascribe-ok action-file'/>
);
}
return (
<div
className="file-drag-and-drop-preview-image"
style={imageStyle}>
<ProgressBar
now={Math.ceil(this.props.progress)}
className="ascribe-progress-bar ascribe-progress-bar-xs"/>
<AclProxy
show={showProgress}>
<ProgressBar
now={Math.ceil(progress)}
className="ascribe-progress-bar ascribe-progress-bar-xs"/>
</AclProxy>
{actionSymbol}
</div>
);

View File

@ -29,27 +29,25 @@ let FileDragAndDropPreviewIterator = React.createClass({
areAssetsDownloadable,
areAssetsEditable
} = this.props;
files = files.filter(displayValidFilesFilter);
if(files && files.length > 0) {
return (
<div className="file-drag-and-drop-preview-iterator">
<div className="file-drag-and-drop-preview-iterator-spacing">
{files.map((file, i) => {
return (
<FileDragAndDropPreview
key={i}
file={file}
handleDeleteFile={handleDeleteFile}
handleCancelFile={handleCancelFile}
handlePauseFile={handlePauseFile}
handleResumeFile={handleResumeFile}
areAssetsDownloadable={areAssetsDownloadable}
areAssetsEditable={areAssetsEditable}/>
);
})}
</div>
<div>
{files.map((file, i) => {
return (
<FileDragAndDropPreview
key={i}
file={file}
handleDeleteFile={handleDeleteFile}
handleCancelFile={handleCancelFile}
handlePauseFile={handlePauseFile}
handleResumeFile={handleResumeFile}
areAssetsDownloadable={areAssetsDownloadable}
areAssetsEditable={areAssetsEditable}
numberOfDisplayedFiles={files.length}/>
);
})}
<FileDragAndDropPreviewProgress files={files} />
</div>
);

View File

@ -3,16 +3,21 @@
import React from 'react';
import ProgressBar from 'react-bootstrap/lib/ProgressBar';
import AclProxy from '../../acl_proxy';
import AscribeSpinner from '../../ascribe_spinner';
import { getLangText } from '../../../utils/lang_utils';
let FileDragAndDropPreviewOther = React.createClass({
const { string, number, bool, func } = React.PropTypes;
const FileDragAndDropPreviewOther = React.createClass({
propTypes: {
type: React.PropTypes.string,
progress: React.PropTypes.number,
areAssetsDownloadable: React.PropTypes.bool,
toggleUploadProcess: React.PropTypes.func,
downloadUrl: React.PropTypes.string
type: string,
progress: number,
areAssetsDownloadable: bool,
toggleUploadProcess: func,
downloadUrl: string,
showProgress: bool
},
getInitialState() {
@ -33,39 +38,49 @@ let FileDragAndDropPreviewOther = React.createClass({
},
render() {
const { progress,
areAssetsDownloadable,
downloadUrl,
type,
showProgress } = this.props;
const style = !showProgress ? { visibility: 'hidden' } : null;
let actionSymbol;
if(this.props.progress > 0 && this.props.progress < 99 && this.state.paused) {
actionSymbol = <span className="glyphicon glyphicon-pause action-file" aria-hidden="true" title={getLangText('Pause upload')} onClick={this.toggleUploadProcess}/>;
} else if(this.props.progress > 0 && this.props.progress < 99 && !this.state.paused) {
actionSymbol = <span className="glyphicon glyphicon-play action-file" aria-hidden="true" title={getLangText('Resume uploading')} onClick={this.toggleUploadProcess}/>;
} else if(this.props.progress === 100) {
// only if assets are actually downloadable, there should be a download icon if the process is already at
// 100%. If not, no actionSymbol should be displayed
if(this.props.areAssetsDownloadable) {
actionSymbol = <a href={this.props.downloadUrl} target="_blank" className="glyphicon glyphicon-download action-file" aria-hidden="true" title={getLangText('Download file')}/>;
}
} else {
// only if assets are actually downloadable, there should be a
// download icon if the process is already at 100%.
// If not, no actionSymbol should be displayed
if (progress === 100 && areAssetsDownloadable) {
actionSymbol = (
<a
href={downloadUrl}
target="_blank"
className="glyphicon glyphicon-download action-file"
aria-hidden="true"
title={getLangText('Download file')}/>
);
} else if(progress >= 0 && progress < 100) {
actionSymbol = (
<div className="spinner-file">
<AscribeSpinner color='dark-blue' size='md' />
</div>
);
} else {
actionSymbol = (
<span className='ascribe-icon icon-ascribe-ok action-file'/>
);
}
return (
<div
className="file-drag-and-drop-preview">
<ProgressBar
now={Math.ceil(this.props.progress)}
now={Math.ceil(progress)}
style={style}
className="ascribe-progress-bar ascribe-progress-bar-xs"/>
<div className="file-drag-and-drop-preview-table-wrapper">
<div className="file-drag-and-drop-preview-other">
{actionSymbol}
<p>{'.' + this.props.type}</p>
<p style={style}>{'.' + type}</p>
</div>
</div>
</div>

View File

@ -5,10 +5,9 @@ import React from 'react';
import ProgressBar from 'react-bootstrap/lib/ProgressBar';
import { displayValidProgressFilesFilter } from '../react_s3_fine_uploader_utils';
import { getLangText } from '../../../utils/lang_utils';
let FileDragAndDropPreviewProgress = React.createClass({
const FileDragAndDropPreviewProgress = React.createClass({
propTypes: {
files: React.PropTypes.array
},
@ -40,24 +39,18 @@ let FileDragAndDropPreviewProgress = React.createClass({
},
render() {
const files = this.props.files.filter(displayValidProgressFilesFilter);
const style = !files.length ? { display: 'none' } : null;
let overallProgress = this.calcOverallProgress();
let overallFileSize = this.calcOverallFileSize();
let style = {
visibility: 'hidden'
};
// only visible if overallProgress is over zero
// or the overallFileSize is greater than 10MB
if(overallProgress !== 0 && overallFileSize > 10000000) {
style.visibility = 'visible';
}
return (
<ProgressBar
now={Math.ceil(overallProgress)}
label={getLangText('Overall progress%s', ': %(percent)s%')}
className="ascribe-progress-bar"
style={style} />
<div style={{marginTop: '1.3em'}}>
<ProgressBar
now={Math.ceil(overallProgress)}
label={'%(percent)s%'}
className="ascribe-progress-bar"
style={style} />
</div>
);
}
});

View File

@ -2,138 +2,195 @@
import React from 'react';
import Glyphicon from 'react-bootstrap/lib/Glyphicon';
import { displayValidProgressFilesFilter } from '../react_s3_fine_uploader_utils';
import { getLangText } from '../../../utils/lang_utils';
import { truncateTextAtCharIndex } from '../../../utils/general_utils';
const { func, array, bool, shape, string } = React.PropTypes;
let UploadButton = React.createClass({
propTypes: {
onDrop: func.isRequired,
filesToUpload: array,
multiple: bool,
// For simplification purposes we're just going to use this prop as a
// label for the upload button
fileClassToUpload: shape({
singular: string,
plural: string
}),
export default function UploadButton({ className = 'btn btn-default btn-sm' } = {}) {
return React.createClass({
displayName: 'UploadButton',
allowedExtensions: string,
propTypes: {
onDrop: func.isRequired,
filesToUpload: array,
multiple: bool,
handleCancelFile: func // provided by ReactS3FineUploader
},
// For simplification purposes we're just going to use this prop as a
// label for the upload button
fileClassToUpload: shape({
singular: string,
plural: string
}),
handleDrop(event) {
event.preventDefault();
event.stopPropagation();
let files = event.target.files;
allowedExtensions: string,
if(typeof this.props.onDrop === 'function' && files) {
this.props.onDrop(files);
}
// provided by ReactS3FineUploader
handleCancelFile: func,
handleDeleteFile: func
},
},
getInitialState() {
return {
disabled: this.getUploadingFiles().length !== 0
};
},
getUploadingFiles() {
return this.props.filesToUpload.filter((file) => file.status === 'uploading');
},
componentWillReceiveProps(nextProps) {
if(this.props.filesToUpload !== nextProps.filesToUpload) {
this.setState({
disabled: this.getUploadingFiles(nextProps.filesToUpload).length !== 0
});
}
},
getUploadedFile() {
return this.props.filesToUpload.filter((file) => file.status === 'upload successful')[0];
},
handleDrop(event) {
event.preventDefault();
event.stopPropagation();
let files = event.target.files;
handleOnClick() {
const uploadingFiles = this.getUploadingFiles();
const uploadedFile = this.getUploadedFile();
if(typeof this.props.onDrop === 'function' && files) {
this.props.onDrop(files);
}
},
if(uploadedFile) {
this.props.handleCancelFile(uploadedFile.id);
}
if(uploadingFiles.length === 0) {
// We only want the button to be clickable if there are no files currently uploading
getUploadingFiles(filesToUpload = this.props.filesToUpload) {
return filesToUpload.filter((file) => file.status === 'uploading');
},
// Firefox only recognizes the simulated mouse click if bubbles is set to true,
// but since Google Chrome propagates the event much further than needed, we
// need to stop propagation as soon as the event is created
var evt = new MouseEvent('click', {
view: window,
bubbles: true,
cancelable: true
});
getUploadedFile() {
return this.props.filesToUpload.filter((file) => file.status === 'upload successful')[0];
},
evt.stopPropagation();
this.refs.fileinput.getDOMNode().dispatchEvent(evt);
}
},
clearSelection() {
this.refs.fileSelector.getDOMNode().value = '';
},
getButtonLabel() {
let { filesToUpload, fileClassToUpload } = this.props;
handleOnClick() {
if(!this.state.disabled) {
let evt;
const uploadingFiles = this.getUploadingFiles();
const uploadedFile = this.getUploadedFile();
// filter invalid files that might have been deleted or canceled...
filesToUpload = filesToUpload.filter(displayValidProgressFilesFilter);
this.clearSelection();
if(uploadingFiles.length) {
this.props.handleCancelFile(uploadingFiles[0].id);
} else if(uploadedFile && !uploadedFile.s3UrlSafe) {
this.props.handleCancelFile(uploadedFile.id);
} else if(uploadedFile && uploadedFile.s3UrlSafe) {
this.props.handleDeleteFile(uploadedFile.id);
}
if(this.getUploadingFiles().length !== 0) {
return getLangText('Upload progress') + ': ' + Math.ceil(filesToUpload[0].progress) + '%';
} else {
return fileClassToUpload.singular;
}
},
try {
evt = new MouseEvent('click', {
view: window,
bubbles: true,
cancelable: true
});
} catch(e) {
// For browsers that do not support the new MouseEvent syntax
evt = document.createEvent('MouseEvents');
evt.initMouseEvent('click', true, true, window, 0, 0, 0, 80, 20, false, false, false, false, 0, null);
}
evt.stopPropagation();
this.refs.fileSelector.getDOMNode().dispatchEvent(evt);
}
},
getUploadedFileLabel() {
const uploadedFile = this.getUploadedFile();
onClickCancel() {
this.clearSelection();
const uploadingFile = this.getUploadingFiles()[0];
this.props.handleCancelFile(uploadingFile.id);
},
if(uploadedFile) {
onClickRemove() {
this.clearSelection();
const uploadedFile = this.getUploadedFile();
this.props.handleDeleteFile(uploadedFile.id);
},
getButtonLabel() {
let { filesToUpload, fileClassToUpload } = this.props;
// filter invalid files that might have been deleted or canceled...
filesToUpload = filesToUpload.filter(displayValidProgressFilesFilter);
if(this.getUploadingFiles().length !== 0) {
return getLangText('Upload progress') + ': ' + Math.ceil(filesToUpload[0].progress) + '%';
} else {
return fileClassToUpload.singular;
}
},
getUploadedFileLabel() {
const uploadedFile = this.getUploadedFile();
const uploadingFiles = this.getUploadingFiles();
if(uploadingFiles.length) {
return (
<span>
{' ' + truncateTextAtCharIndex(uploadingFiles[0].name, 40) + ' '}
[<a onClick={this.onClickCancel}>{getLangText('cancel upload')}</a>]
</span>
);
} else if(uploadedFile) {
return (
<span>
<span className='ascribe-icon icon-ascribe-ok'/>
{' ' + truncateTextAtCharIndex(uploadedFile.name, 40) + ' '}
[<a onClick={this.onClickRemove}>{getLangText('remove')}</a>]
</span>
);
} else {
return (
<span>{getLangText('No file chosen')}</span>
);
}
},
render() {
const {
multiple,
allowedExtensions } = this.props;
const { disabled } = this.state;
/*
* We do not want a button that submits here.
* As UploadButton could be used in forms that want to be submitted independent
* of clicking the selector.
* Therefore the wrapping component needs to be an `anchor` tag instead of a `button`
*/
return (
<span>
<Glyphicon glyph="ok" />
{' ' + truncateTextAtCharIndex(uploadedFile.name, 40)}
</span>
);
} else {
return (
<span>{getLangText('No file chosen')}</span>
<div className="upload-button-wrapper">
{/*
The button needs to be of `type="button"` as it would
otherwise submit the form its in.
*/}
<button
type="button"
onClick={this.handleOnClick}
className={className}
disabled={disabled}>
{this.getButtonLabel()}
<input
multiple={multiple}
ref="fileSelector"
type="file"
style={{
display: 'none',
height: 0,
width: 0
}}
onChange={this.handleDrop}
accept={allowedExtensions}/>
</button>
{this.getUploadedFileLabel()}
</div>
);
}
},
render() {
let { multiple,
allowedExtensions } = this.props;
/*
* We do not want a button that submits here.
* As UploadButton could be used in forms that want to be submitted independent
* of clicking the selector.
* Therefore the wrapping component needs to be an `anchor` tag instead of a `button`
*/
return (
<div className="upload-button-wrapper">
<a
onClick={this.handleOnClick}
className="btn btn-default btn-sm margin-left-2px"
disabled={this.getUploadingFiles().length !== 0}>
{this.getButtonLabel()}
<input
multiple={multiple}
ref="fileinput"
type="file"
style={{
display: 'none',
height: 0,
width: 0
}}
onChange={this.handleDrop}
accept={allowedExtensions}/>
</a>
{this.getUploadedFileLabel()}
</div>
);
}
});
export default UploadButton;
});
}

View File

@ -18,87 +18,100 @@ import { displayValidFilesFilter, transformAllowedExtensionsToInputAcceptProp }
import { getCookie } from '../../utils/fetch_api_utils';
import { getLangText } from '../../utils/lang_utils';
let ReactS3FineUploader = React.createClass({
const { shape,
string,
oneOfType,
number,
func,
bool,
any,
object,
oneOf,
element,
arrayOf } = React.PropTypes;
const ReactS3FineUploader = React.createClass({
propTypes: {
keyRoutine: React.PropTypes.shape({
url: React.PropTypes.string,
fileClass: React.PropTypes.string,
pieceId: React.PropTypes.oneOfType([
React.PropTypes.string,
React.PropTypes.number
keyRoutine: shape({
url: string,
fileClass: string,
pieceId: oneOfType([
string,
number
])
}),
createBlobRoutine: React.PropTypes.shape({
url: React.PropTypes.string,
pieceId: React.PropTypes.oneOfType([
React.PropTypes.string,
React.PropTypes.number
createBlobRoutine: shape({
url: string,
pieceId: oneOfType([
string,
number
])
}),
submitFile: React.PropTypes.func,
autoUpload: React.PropTypes.bool,
debug: React.PropTypes.bool,
objectProperties: React.PropTypes.shape({
acl: React.PropTypes.string
handleChangedFile: func, // is for when a file is dropped or selected
submitFile: func, // is for when a file has been successfully uploaded, TODO: rename to handleSubmitFile
autoUpload: bool,
debug: bool,
objectProperties: shape({
acl: string
}),
request: React.PropTypes.shape({
endpoint: React.PropTypes.string,
accessKey: React.PropTypes.string,
params: React.PropTypes.shape({
csrfmiddlewaretoken: React.PropTypes.string
request: shape({
endpoint: string,
accessKey: string,
params: shape({
csrfmiddlewaretoken: string
})
}),
signature: React.PropTypes.shape({
endpoint: React.PropTypes.string
signature: shape({
endpoint: string
}).isRequired,
uploadSuccess: React.PropTypes.shape({
method: React.PropTypes.string,
endpoint: React.PropTypes.string,
params: React.PropTypes.shape({
isBrowserPreviewCapable: React.PropTypes.any, // maybe fix this later
bitcoin_ID_noPrefix: React.PropTypes.string
uploadSuccess: shape({
method: string,
endpoint: string,
params: shape({
isBrowserPreviewCapable: any, // maybe fix this later
bitcoin_ID_noPrefix: string
})
}),
cors: React.PropTypes.shape({
expected: React.PropTypes.bool
cors: shape({
expected: bool
}),
chunking: React.PropTypes.shape({
enabled: React.PropTypes.bool
chunking: shape({
enabled: bool
}),
resume: React.PropTypes.shape({
enabled: React.PropTypes.bool
resume: shape({
enabled: bool
}),
deleteFile: React.PropTypes.shape({
enabled: React.PropTypes.bool,
method: React.PropTypes.string,
endpoint: React.PropTypes.string,
customHeaders: React.PropTypes.object
deleteFile: shape({
enabled: bool,
method: string,
endpoint: string,
customHeaders: object
}).isRequired,
session: React.PropTypes.shape({
customHeaders: React.PropTypes.object,
endpoint: React.PropTypes.string,
params: React.PropTypes.object,
refreshOnRequests: React.PropTypes.bool
session: shape({
customHeaders: object,
endpoint: string,
params: object,
refreshOnRequests: bool
}),
validation: React.PropTypes.shape({
itemLimit: React.PropTypes.number,
sizeLimit: React.PropTypes.string,
allowedExtensions: React.PropTypes.arrayOf(React.PropTypes.string)
validation: shape({
itemLimit: number,
sizeLimit: string,
allowedExtensions: arrayOf(string)
}),
messages: React.PropTypes.shape({
unsupportedBrowser: React.PropTypes.string
messages: shape({
unsupportedBrowser: string
}),
formatFileName: React.PropTypes.func,
multiple: React.PropTypes.bool,
retry: React.PropTypes.shape({
enableAuto: React.PropTypes.bool
formatFileName: func,
multiple: bool,
retry: shape({
enableAuto: bool
}),
uploadStarted: React.PropTypes.func,
setIsUploadReady: React.PropTypes.func,
isReadyForFormSubmission: React.PropTypes.func,
areAssetsDownloadable: React.PropTypes.bool,
areAssetsEditable: React.PropTypes.bool,
defaultErrorMessage: React.PropTypes.string,
setIsUploadReady: func,
isReadyForFormSubmission: func,
areAssetsDownloadable: bool,
areAssetsEditable: bool,
defaultErrorMessage: string,
// We encountered some cases where people had difficulties to upload their
// works to ascribe due to a slow internet connection.
@ -111,22 +124,22 @@ let ReactS3FineUploader = React.createClass({
// which should be passed into 'uploadMethod':
// 'hash': upload using the hash
// 'upload': upload full file (default if not specified)
enableLocalHashing: React.PropTypes.bool,
uploadMethod: React.PropTypes.oneOf(['hash', 'upload']),
enableLocalHashing: bool,
uploadMethod: oneOf(['hash', 'upload']),
// A class of a file the user has to upload
// Needs to be defined both in singular as well as in plural
fileClassToUpload: React.PropTypes.shape({
singular: React.PropTypes.string,
plural: React.PropTypes.string
fileClassToUpload: shape({
singular: string,
plural: string
}),
// Uploading functionality of react fineuploader is disconnected from its UI
// layer, which means that literally every (properly adjusted) react element
// can handle the UI handling.
fileInputElement: React.PropTypes.oneOfType([
React.PropTypes.func,
React.PropTypes.element
fileInputElement: oneOfType([
func,
element
])
},
@ -272,7 +285,7 @@ let ReactS3FineUploader = React.createClass({
// Cancel uploads and clear previously selected files on the input element
cancelUploads(id) {
!!id ? this.state.uploader.cancel(id) : this.state.uploader.cancelAll();
typeof id !== 'undefined' ? this.state.uploader.cancel(id) : this.state.uploader.cancelAll();
// Reset the file input element to clear the previously selected files so that
// the user can reselect them again.
@ -375,6 +388,21 @@ let ReactS3FineUploader = React.createClass({
});
},
setThumbnailForFileId(fileId, url) {
const { filesToUpload } = this.state;
if(fileId < filesToUpload.length) {
const changeSet = { $set: url };
const newFilesToUpload = React.addons.update(filesToUpload, {
[fileId]: { thumbnailUrl: changeSet }
});
this.setState({ filesToUpload: newFilesToUpload });
} else {
throw new Error('Accessing an index out of range of filesToUpload');
}
},
/* FineUploader specific callback function handlers */
onUploadChunk(id, name, chunkData) {
@ -509,7 +537,12 @@ let ReactS3FineUploader = React.createClass({
onCancel(id) {
// when a upload is canceled, we need to update this components file array
this.setStatusOfFile(id, 'canceled');
this.setStatusOfFile(id, 'canceled')
.then(() => {
if(typeof this.props.handleChangedFile === 'function') {
this.props.handleChangedFile(this.state.filesToUpload[id]);
}
});
let notification = new GlobalNotificationModel(getLangText('File upload canceled'), 'success', 5000);
GlobalNotificationActions.appendGlobalNotification(notification);
@ -603,7 +636,12 @@ let ReactS3FineUploader = React.createClass({
//
// If there is an error during the deletion, we will just change the status back to 'online'
// and display an error message
this.setStatusOfFile(fileId, 'deleted');
this.setStatusOfFile(fileId, 'deleted')
.then(() => {
if(typeof this.props.handleChangedFile === 'function') {
this.props.handleChangedFile(this.state.filesToUpload[fileId]);
}
});
// In some instances (when the file was already uploaded and is just displayed to the user
// - for example in the contract or additional files dialog)
@ -671,11 +709,6 @@ let ReactS3FineUploader = React.createClass({
// override standard files list with only valid files
files = validFiles;
// Call this method to signal the outside component that an upload is in progress
if(typeof this.props.uploadStarted === 'function' && files.length > 0) {
this.props.uploadStarted();
}
// if multiple is set to false and user drops multiple files into the dropzone,
// take the first one and notify user that only one file can be submitted
if(!this.props.multiple && files.length > 1) {
@ -848,21 +881,37 @@ let ReactS3FineUploader = React.createClass({
// set the new file array
let filesToUpload = React.addons.update(this.state.filesToUpload, { $set: oldAndNewFiles });
this.setState({ filesToUpload });
this.setState({ filesToUpload }, () => {
// when files have been dropped or selected by a user, we want to propagate that
// information to the outside components, so they can act on it (in our case, because
// we want the user to define a thumbnail when the actual work is not renderable
// (like e.g. a .zip file))
if(typeof this.props.handleChangedFile === 'function') {
// its save to assume that the last file in `filesToUpload` is always
// the latest file added
this.props.handleChangedFile(this.state.filesToUpload.slice(-1)[0]);
}
});
},
// This method has been made promise-based to immediately afterwards
// call a callback function (instantly after this.setState went through)
// This is e.g. needed when showing/hiding the optional thumbnail upload
// field in the registration form
setStatusOfFile(fileId, status) {
let changeSet = {};
return Q.Promise((resolve) => {
let changeSet = {};
if(status === 'deleted' || status === 'canceled') {
changeSet.progress = { $set: 0 };
}
if(status === 'deleted' || status === 'canceled') {
changeSet.progress = { $set: 0 };
}
changeSet.status = { $set: status };
changeSet.status = { $set: status };
let filesToUpload = React.addons.update(this.state.filesToUpload, { [fileId]: changeSet });
let filesToUpload = React.addons.update(this.state.filesToUpload, { [fileId]: changeSet });
this.setState({ filesToUpload });
this.setState({ filesToUpload }, resolve);
});
},
isDropzoneInactive() {

View File

@ -42,6 +42,15 @@ export function displayValidFilesFilter(file) {
return file.status !== 'deleted' && file.status !== 'canceled';
}
/**
* Filter function for filtering all files except for deleted and canceled files
* @param {object} file A file from filesToUpload that has status as a prop.
* @return {boolean}
*/
export function displayRemovedFilesFilter(file) {
return file.status === 'deleted' || file.status === 'canceled';
}
/**
* Filter function for which files to integrate in the progress process

View File

@ -17,7 +17,7 @@ import UserStore from '../stores/user_store';
import GlobalNotificationModel from '../models/global_notification_model';
import GlobalNotificationActions from '../actions/global_notification_actions';
import PropertyCollapsible from './ascribe_forms/property_collapsible';
import Property from './ascribe_forms/property';
import RegisterPieceForm from './ascribe_forms/form_register_piece';
import { mergeOptions } from '../utils/general_utils';
@ -86,15 +86,16 @@ let RegisterPiece = React.createClass( {
getSpecifyEditions() {
if(this.state.whitelabel && this.state.whitelabel.acl_create_editions || Object.keys(this.state.whitelabel).length === 0) {
return (
<PropertyCollapsible
<Property
name="num_editions"
checkboxLabel={getLangText('Specify editions')}>
checkboxLabel={getLangText('Specify editions')}
expanded={false}>
<span>{getLangText('Editions')}</span>
<input
type="number"
placeholder="(e.g. 32)"
min={0}/>
</PropertyCollapsible>
</Property>
);
}
},

View File

@ -253,7 +253,7 @@ const PRRegisterPieceForm = React.createClass({
name="digitalWorkKey"
label={getLangText('Select the PDF with your work')}>
<InputFineuploader
fileInputElement={UploadButton}
fileInputElement={UploadButton()}
isReadyForFormSubmission={formSubmissionValidation.atLeastOneUploadedFile}
setIsUploadReady={this.setIsUploadReady('digitalWorkKeyReady')}
createBlobRoutine={{
@ -279,7 +279,7 @@ const PRRegisterPieceForm = React.createClass({
name="thumbnailKey"
label={getLangText('Featured Cover photo')}>
<InputFineuploader
fileInputElement={UploadButton}
fileInputElement={UploadButton()}
createBlobRoutine={{
url: ApiUrls.blob_thumbnails
}}
@ -305,7 +305,7 @@ const PRRegisterPieceForm = React.createClass({
name="supportingMaterials"
label={getLangText('Supporting Materials (Optional)')}>
<InputFineuploader
fileInputElement={UploadButton}
fileInputElement={UploadButton()}
isReadyForFormSubmission={formSubmissionValidation.atLeastOneUploadedFile}
setIsUploadReady={this.setIsUploadReady('supportingMaterialsReady')}
createBlobRoutine={this.getCreateBlobRoutine()}
@ -327,7 +327,7 @@ const PRRegisterPieceForm = React.createClass({
name="proofOfPayment"
label={getLangText('Proof of payment')}>
<InputFineuploader
fileInputElement={UploadButton}
fileInputElement={UploadButton()}
isReadyForFormSubmission={formSubmissionValidation.atLeastOneUploadedFile}
setIsUploadReady={this.setIsUploadReady('proofOfPaymentReady')}
createBlobRoutine={this.getCreateBlobRoutine()}

View File

@ -8,6 +8,7 @@ import PieceSubmitToPrizeForm from '../../../../../ascribe_forms/form_submit_to_
import { getLangText } from '../../../../../../utils/lang_utils';
let SubmitToPrizeButton = React.createClass({
propTypes: {
className: React.PropTypes.string,
@ -21,8 +22,8 @@ let SubmitToPrizeButton = React.createClass({
<button
disabled
className="btn btn-default btn-xs pull-right">
{getLangText('Submitted to prize')} <span className="glyphicon glyphicon-ok"
aria-hidden="true"></span>
{getLangText('Submitted to prize') + ' '}
<span className='ascribe-icon icon-ascribe-ok'/>
</button>
);
}

View File

@ -76,8 +76,8 @@ let CylandAccordionListItem = React.createClass({
<button
disabled
className="btn btn-default btn-xs pull-right">
{getLangText('Submitted to Cyland')} <span className="glyphicon glyphicon-ok"
aria-hidden="true"></span>
{getLangText('Submitted to Cyland') + ' '}
<span className='ascribe-icon icon-ascribe-ok'/>
</button>
</AclProxy>
<AclProxy
@ -86,8 +86,8 @@ let CylandAccordionListItem = React.createClass({
<button
disabled
className="btn btn-default btn-xs pull-right">
{getLangText('Loaned to Cyland')} <span className="glyphicon glyphicon-ok"
aria-hidden="true"></span>
{getLangText('Loaned to Cyland') + ' '}
<span className='ascribe-icon icon-ascribe-ok'/>
</button>
</AclProxy>
</div>

View File

@ -64,12 +64,6 @@ let CylandAdditionalDataForm = React.createClass({
},
uploadStarted() {
this.setState({
isUploadReady: false
});
},
setIsUploadReady(isReady) {
this.setState({
isUploadReady: isReady
@ -184,7 +178,6 @@ let CylandAdditionalDataForm = React.createClass({
</Property>
<FurtherDetailsFileuploader
label={getLangText('Additional files (e.g. still images, pdf)')}
uploadStarted={this.uploadStarted}
submitFile={function () {}}
setIsUploadReady={this.setIsUploadReady}
isReadyForFormSubmission={formSubmissionValidation.fileOptional}

View File

@ -81,8 +81,8 @@ let IkonotvAccordionListItem = React.createClass({
<button
disabled
className="btn btn-default btn-xs pull-right">
{getLangText('Submitted to IkonoTV')} <span className="glyphicon glyphicon-ok"
aria-hidden="true"></span>
{getLangText('Submitted to IkonoTV') + ' '}
<span className='ascribe-icon icon-ascribe-ok'/>
</button>
</AclProxy>
<AclProxy
@ -91,8 +91,8 @@ let IkonotvAccordionListItem = React.createClass({
<button
disabled
className="btn btn-default btn-xs pull-right">
{getLangText('Loaned to IkonoTV')} <span className="glyphicon glyphicon-ok"
aria-hidden="true"></span>
{getLangText('Loaned to IkonoTV') + ' '}
<span className='ascribe-icon icon-ascribe-ok'/>
</button>
</AclProxy>
</div>

View File

@ -99,8 +99,18 @@ const constants = {
'Bildrecht GmbH', 'SABAM', 'AUTVIS', 'CREAIMAGEN', 'SONECA', 'Copydan', 'EAU', 'Kuvasto', 'GCA', 'HUNGART',
'IVARO', 'SIAE', 'JASPAR-SPDA', 'AKKA/LAA', 'LATGA-A', 'SOMAAP', 'ARTEGESTION', 'CARIER', 'BONO', 'APSAV',
'SPA', 'GESTOR', 'VISaRTA', 'RAO', 'LITA', 'DALRO', 'VeGaP', 'BUS', 'ProLitteris', 'AGADU', 'AUTORARTE', 'BUBEDRA', 'BBDA', 'BCDA', 'BURIDA', 'ADAVIS', 'BSDA'],
'searchThreshold': 500,
'supportedThumbnailFileFormats': [
'x-sgi-movie', 'x-msvideo', 'quicktime', 'mpeg', 'png', 'jpeg', 'gif',
'ogg', 'oga', 'ogv', 'ogx', 'wmv', 'wma', 'flv', '3gpp2', '3p2', '3pg',
'png', 'jpg', 'jpeg', 'gif', '264', '3g', '3g2', '3gp', '3gp2', '3gpp',
'mp4', 'm4a', 'm4v', 'f4v', 'f4a', 'm4b', 'm4r', 'f4b', 'mov', 'quicktime',
'webm', 'x264', 'mpeg', 'mpeg4', 'mpg4', 'bmp', 'eps', 'jp2', 'j2k', 'jpm',
'mj2'
],
// in case of whitelabel customization, we store stuff here
'whitelabel': {},

View File

@ -84,4 +84,21 @@ export function computeHashOfFile(file) {
loadNext();
});
}
/**
* Extracts a file extension from a string, by splitting by dot and taking
* the last substring
*
* If a file without an extension is submitted (file), then
* this method just returns an empty string.
* @param {string} s file's name + extension
* @return {string} file extension
*
* Via: http://stackoverflow.com/a/190878/1263876
*/
export function extractFileExtensionFromString(s) {
const explodedFileName = s.split('.');
return explodedFileName.length > 1 ? explodedFileName.pop()
: '';
}

View File

@ -1,250 +1,78 @@
/*
These glyphs are generated using: https://icomoon.io
Even though it seems radically complicated, check out the site,
its fairly straight forward.
If someone wants you to add a new glyph go to the site,
drop in the regular ascribe-logo font and select all icons.
Then also add the new glyph, name and address it correctly and download
the font again.
Once you replace all the fonts they gave you, you're done.
*/
@font-face {
font-family: 'ascribe';
src: url('#{$BASE_URL}static/fonts/ascribe.eot?-oi6ttk');
src: url('#{$BASE_URL}static/fonts/ascribe.eot?#iefix-oi6ttk') format('embedded-opentype'),
url('#{$BASE_URL}static/fonts/ascribe.woff?-oi6ttk') format('woff'),
url('#{$BASE_URL}static/fonts/ascribe.ttf?-oi6ttk') format('truetype'),
url('#{$BASE_URL}static/fonts/ascribe.svg?-oi6ttk#ascribe') format('svg');
font-weight: normal;
font-style: normal;
font-family: 'ascribe-font';
src:url('#{$BASE_URL}static/fonts/ascribe-logo.eot?q6qoae');
src:url('#{$BASE_URL}static/fonts/ascribe-logo.eot?q6qoae#iefix') format('embedded-opentype'),
url('#{$BASE_URL}static/fonts/ascribe-logo.ttf?q6qoae') format('truetype'),
url('#{$BASE_URL}static/fonts/ascribe-logo.woff?q6qoae') format('woff'),
url('#{$BASE_URL}static/fonts/ascribe-logo.svg?q6qoae#ascribe-logo') format('svg');
font-weight: normal;
font-style: normal;
}
[class^="icon-ascribe-"], [class*=" icon-ascribe-"] {
font-family: 'ascribe-logo';
speak: none;
font-style: normal;
font-weight: normal;
font-variant: normal;
text-transform: none;
line-height: 1;
font-family: 'ascribe-font';
speak: none;
font-style: normal;
font-weight: normal;
font-variant: normal;
text-transform: none;
line-height: 1;
/* Better Font Rendering =========== */
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
@font-face {
font-family: 'ascribe-logo';
src:url('#{$BASE_URL}static/fonts/ascribe-logo.eot?q6qoae');
src:url('#{$BASE_URL}static/fonts/ascribe-logo.eot?q6qoae#iefix') format('embedded-opentype'),
url('#{$BASE_URL}static/fonts/ascribe-logo.ttf?q6qoae') format('truetype'),
url('#{$BASE_URL}static/fonts/ascribe-logo.woff?q6qoae') format('woff'),
url('#{$BASE_URL}static/fonts/ascribe-logo.svg?q6qoae#ascribe-logo') format('svg');
font-weight: normal;
font-style: normal;
}
[class^="icon-ascribe-"], [class*=" icon-ascribe-"] {
font-family: 'ascribe-logo';
speak: none;
font-style: normal;
font-weight: normal;
font-variant: normal;
text-transform: none;
line-height: 1;
/* Better Font Rendering =========== */
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
/* Better Font Rendering =========== */
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-ascribe-add:before {
content: "\e800";
content: "\e800";
}
.icon-ascribe-sort:before {
content: "\e801";
content: "\e801";
}
.icon-ascribe-search:before {
content: "\e802";
content: "\e802";
}
.icon-ascribe-filter:before {
content: "\e803";
content: "\e803";
}
.icon-ascribe-add-white:before {
content: "\e804";
content: "\e804";
}
.icon-ascribe-add-blue .path1:before {
content: "\e805";
color: rgb(0, 60, 106);
content: "\e805";
color: rgb(0, 60, 106);
}
.icon-ascribe-add-blue .path2:before {
content: "\e806";
margin-left: -1em;
color: rgb(255, 255, 255);
content: "\e806";
margin-left: -1em;
color: rgb(255, 255, 255);
}
.icon-ascribe-icon:before {
content: "\e807";
content: "\e807";
}
.icon-ascribe-logo:before {
content: "\e808";
content: "\e808";
}
.glyph-ascribe-logo-spool:before {
content: "\e600";
}
.glyph-ascribe-spool:before {
content: "\e601";
}
.glyph-ascribe-logo-spool-chunked:before {
content: "\e602";
}
.glyph-ascribe-spool-chunked:before {
content: "\e603";
}
.glyph-ascribe-home:before {
content: "\e900";
}
.glyph-ascribe-home2:before {
content: "\e901";
}
.glyph-ascribe-home3:before {
content: "\e902";
}
.glyph-ascribe-pencil:before {
content: "\e905";
}
.glyph-ascribe-pencil2:before {
content: "\e906";
}
.glyph-ascribe-quill:before {
content: "\e907";
}
.glyph-ascribe-image:before {
content: "\e90d";
}
.glyph-ascribe-camera:before {
content: "\e90f";
}
.glyph-ascribe-music:before {
content: "\e911";
}
.glyph-ascribe-play:before {
content: "\e912";
}
.glyph-ascribe-film:before {
content: "\e913";
}
.glyph-ascribe-credit-card:before {
content: "\e93f";
}
.glyph-ascribe-pushpin:before {
content: "\e946";
}
.glyph-ascribe-undo2:before {
content: "\e967";
}
.glyph-ascribe-redo2:before {
content: "\e968";
}
.glyph-ascribe-enlarge:before {
content: "\e989";
}
.glyph-ascribe-shrink:before {
content: "\e98a";
}
.glyph-ascribe-enlarge2:before {
content: "\e98b";
}
.glyph-ascribe-shrink2:before {
content: "\e98c";
}
.glyph-ascribe-share:before {
content: "\ea7d";
}
.glyph-ascribe-new-tab:before {
content: "\ea7e";
}
.glyph-ascribe-share2:before {
content: "\ea82";
}
.glyph-ascribe-google:before {
content: "\ea87";
}
.glyph-ascribe-google-plus:before {
content: "\ea88";
}
.glyph-ascribe-google-plus2:before {
content: "\ea89";
}
.glyph-ascribe-facebook:before {
content: "\ea8c";
}
.glyph-ascribe-facebook2:before {
content: "\ea8d";
}
.glyph-ascribe-twitter:before {
content: "\ea91";
}
.glyph-ascribe-twitter2:before {
content: "\ea92";
}
.glyph-ascribe-youtube3:before {
content: "\ea99";
}
.glyph-ascribe-dropbox:before {
content: "\eaaf";
}
.glyph-ascribe-file-pdf:before {
content: "\eada";
}
.glyph-ascribe-chrome:before {
content: "\eae5";
}
.glyph-ascribe-firefox:before {
content: "\eae6";
}
.glyph-ascribe-IE:before {
content: "\eae7";
}
.glyph-ascribe-opera:before {
content: "\eae8";
}
.glyph-ascribe-safari:before {
content: "\eae9";
.icon-ascribe-ok:before {
content: "\e809";
font-size: .7em;
}
.btn-glyph-ascribe {
font-size: 18px;
padding: 4px 12px 0 10px
}
font-size: 18px;
padding: 4px 12px 0 10px
}

View File

@ -266,6 +266,24 @@ hr {
font-weight: $ascribe--font-weight-light;
}
.btn-default {
background-color: $ascribe--button-default-color;
border-color: $ascribe--button-default-color;
&:hover,
&:active,
&:focus,
&:active:hover,
&:active:focus,
&:active.focus,
&.active:hover,
&.active:focus,
&.active.focus {
background-color: lighten($ascribe--button-default-color, 20%);
border-color: lighten($ascribe--button-default-color, 20%);
}
}
// disabled buttons
.btn-default.disabled,
.btn-default.disabled:hover,
@ -289,9 +307,10 @@ fieldset[disabled] .btn-default.active {
border-color: darken($ascribe--button-default-color, 20%);
}
.btn-default {
background-color: $ascribe--button-default-color;
border-color: $ascribe--button-default-color;
.btn-secondary {
background-color: $ascribe--button-secondary-bg-color;
border-color: $ascribe--button-secondary-fg-color;
color: $ascribe--button-secondary-fg-color;
&:hover,
&:active,
@ -302,8 +321,9 @@ fieldset[disabled] .btn-default.active {
&.active:hover,
&.active:focus,
&.active.focus {
background-color: lighten($ascribe--button-default-color, 20%);
border-color: lighten($ascribe--button-default-color, 20%);
background-color: $ascribe--button-secondary-fg-color;
border-color: $ascribe--button-secondary-bg-color;
color: $ascribe--button-secondary-bg-color;
}
}
@ -331,26 +351,6 @@ fieldset[disabled] .btn-secondary.active {
color: darken($ascribe--button-secondary-fg-color, 20%);
}
.btn-secondary {
background-color: $ascribe--button-secondary-bg-color;
border-color: $ascribe--button-secondary-fg-color;
color: $ascribe--button-secondary-fg-color;
&:hover,
&:active,
&:focus,
&:active:hover,
&:active:focus,
&:active.focus,
&.active:hover,
&.active:focus,
&.active.focus {
background-color: $ascribe--button-secondary-fg-color;
border-color: $ascribe--button-secondary-bg-color;
color: $ascribe--button-secondary-bg-color;
}
}
.btn-tertiary {
background-color: transparent;
border-color: transparent;
@ -589,11 +589,6 @@ fieldset[disabled] .btn-secondary.active {
background-color: lighten($ascribe--button-default-color, 20%);
}
// uploader
.ascribe-progress-bar > .progress-bar {
background-color: lighten($ascribe--button-default-color, 20%);
}
.action-file {
text-shadow: -1px 0 black,
0 1px black,

View File

@ -89,6 +89,10 @@ $ascribe-red-error: rgb(169, 68, 66);
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
}
> .file-drag-and-drop {
margin-top: .5em;
}
> p {
height: 20px;
margin-bottom: 0;
@ -166,7 +170,7 @@ $ascribe-red-error: rgb(169, 68, 66);
.ascribe-property-collapsible-toggle {
border-top: 1px solid rgba(0, 0, 0, .05);
display: inline-block;
padding: .5em 1.5em;
padding: .75em 0 .75em 1.5em;
text-align: left;
width: 100%;
}

View File

@ -3,19 +3,12 @@
cursor: default !important;
display: block;
height: auto;
margin-top: 1em;
/* margin-top: 1em; */
outline: 1px dashed #9e9e9e;
overflow: auto;
text-align: center;
vertical-align: middle;
padding: 1.5em 0 1.5em 0;
.file-drag-and-drop-dialog > p:first-child {
font-size: 1.5em !important;
margin-bottom: 0;
margin-top: 0;
padding-bottom: 0;
}
padding-top: 1.5em;
}
.inactive-dropzone {
@ -34,21 +27,19 @@
}
}
.file-drag-and-drop-preview-iterator {
margin: 2.5em 0 0 0;
text-align: right;
> div:first-child {
text-align: center;
}
}
.file-drag-and-drop-preview-iterator-spacing {
margin-bottom: 1em;
}
.file-drag-and-drop-dialog {
margin: 1.5em 0 1.5em 0;
> p:first-child {
font-size: 1.5em !important;
margin-bottom: 0;
margin-top: 0;
padding-bottom: 0;
}
> .btn {
margin-bottom: 2em;
}
}
.file-drag-and-drop-hashing-dialog {
@ -107,6 +98,7 @@
cursor: default;
overflow: hidden;
}
.action-file {
color: white;
cursor: pointer;
@ -125,6 +117,13 @@
&:hover {
color: #d9534f;
}
&.icon-ascribe-ok, &.icon-ascribe-ok:hover {
cursor: default;
color: $ascribe-dark-blue;
font-size: 4.2em;
top: .2em;
}
}
.spinner-file {
@ -139,12 +138,16 @@
text-align: center;
width: 104px;
.action-file, .spinner-file {
.action-file, .spinner-file, .icon-ascribe-ok {
margin-top: 1em;
line-height: 1.3;
}
.ascribe-progress-bar + .action-file, .ascribe-progress-bar + .spinner-file {
margin-top: .6em;
}
}
.file-drag-and-drop-preview-other {
display: table-cell;
text-align: center;
@ -154,7 +157,7 @@
margin-top: 5px;
}
.action-file, .spinner-file {
.action-file:not(.icon-ascribe-ok), .spinner-file {
margin-top: 0;
position: relative;
top: .3em;
@ -171,6 +174,15 @@
> .progress-bar {
background-color: $ascribe-dark-blue;
}
span {
font-size: 1.2em;
color: white;
text-shadow: -1px 0 $ascribe--button-default-color,
0 1px $ascribe--button-default-color,
1px 0 $ascribe--button-default-color,
0 -1px $ascribe--button-default-color;
}
}
.ascribe-progress-bar-xs {

View File

@ -207,4 +207,20 @@ $cc--button-color: $cc--nav-fg-prim-color;
.client--cc .acl-information-dropdown-list .title {
color: $cc--button-color;
}
.client--cc .action-file.icon-ascribe-ok,
.client--cc .action-file.icon-ascribe-ok:hover {
color: $cc--button-color;
}
.client--cc .ascribe-progress-bar span {
text-shadow: -1px 0 $cc--button-color,
0 1px $cc--button-color,
1px 0 $cc--button-color,
0 -1px $cc--button-color;
}
.client--cc .upload-button-wrapper > span {
color: $cc--button-color;
}

View File

@ -59,39 +59,14 @@ $cyland--button-color: $cyland--nav-fg-prim-color;
display: none;
}
.client--cyland .icon-ascribe-search{
.client--cyland .icon-ascribe-search {
color: $cyland--button-color;
}
.client--cyland .ascribe-piece-list-toolbar .btn-ascribe-add{
.client--cyland .ascribe-piece-list-toolbar .btn-ascribe-add {
display: none;
}
// disabled buttons
.client--cyland {
.btn-default.disabled,
.btn-default.disabled:hover,
.btn-default.disabled:focus,
.btn-default.disabled.focus,
.btn-default.disabled:active,
.btn-default.disabled.active,
.btn-default[disabled],
.btn-default[disabled]:hover,
.btn-default[disabled]:focus,
.btn-default[disabled].focus,
.btn-default[disabled]:active,
.btn-default[disabled].active,
fieldset[disabled] .btn-default,
fieldset[disabled] .btn-default:hover,
fieldset[disabled] .btn-default:focus,
fieldset[disabled] .btn-default.focus,
fieldset[disabled] .btn-default:active,
fieldset[disabled] .btn-default.active {
background-color: darken($cyland--button-color, 20%);
border-color: darken($cyland--button-color, 20%);
}
}
// buttons!
// thought of the day:
// "every great atrocity is the result of people just following orders"
@ -128,6 +103,26 @@ $cyland--button-color: $cyland--nav-fg-prim-color;
}
}
.btn-secondary {
background-color: white;
border-color: $cyland--button-color;
color: $cyland--button-color;
&:hover,
&:active,
&:focus,
&:active:hover,
&:active:focus,
&:active.focus,
&.active:hover,
&.active:focus,
&.active.focus {
background-color: $cyland--button-color;
border-color: $cyland--button-color;
color: white;
}
}
.open > .btn-default.dropdown-toggle:hover,
.open > .btn-default.dropdown-toggle:focus,
.open > .btn-default.dropdown-toggle.focus,
@ -147,6 +142,30 @@ $cyland--button-color: $cyland--nav-fg-prim-color;
}
}
.client--ikonotv {
.btn-default.disabled,
.btn-default.disabled:hover,
.btn-default.disabled:focus,
.btn-default.disabled.focus,
.btn-default.disabled:active,
.btn-default.disabled.active,
.btn-default[disabled],
.btn-default[disabled]:hover,
.btn-default[disabled]:focus,
.btn-default[disabled].focus,
.btn-default[disabled]:active,
.btn-default[disabled].active,
fieldset[disabled] .btn-default,
fieldset[disabled] .btn-default:hover,
fieldset[disabled] .btn-default:focus,
fieldset[disabled] .btn-default.focus,
fieldset[disabled] .btn-default:active,
fieldset[disabled] .btn-default.active {
background-color: darken($cyland--button-color, 20%);
border-color: darken($cyland--button-color, 20%);
}
}
// landing page
.client--cyland {
.route--landing {
@ -200,3 +219,19 @@ $cyland--button-color: $cyland--nav-fg-prim-color;
.client--cyland .acl-information-dropdown-list .title {
color: $cyland--button-color;
}
.client--cyland .action-file.icon-ascribe-ok,
.client--cyland .action-file.icon-ascribe-ok:hover {
color: $cyland--nav-fg-prim-color;
}
.client--cyland .ascribe-progress-bar span {
text-shadow: -1px 0 $cyland--nav-fg-prim-color,
0 1px $cyland--nav-fg-prim-color,
1px 0 $cyland--nav-fg-prim-color,
0 -1px $cyland--nav-fg-prim-color;
}
.client--cyland .upload-button-wrapper > span {
color: $cyland--button-color;
}

View File

@ -411,6 +411,26 @@ $ikono--font: 'Helvetica Neue', 'Helvetica', sans-serif !important;
}
}
.btn-secondary {
background-color: white;
border-color: $ikono--button-color;
color: $ikono--button-color;
&:hover,
&:active,
&:focus,
&:active:hover,
&:active:focus,
&:active.focus,
&.active:hover,
&.active:focus,
&.active.focus {
background-color: $ikono--button-color;
border-color: $ikono--button-color;
color: white;
}
}
.open > .btn-default.dropdown-toggle:hover,
.open > .btn-default.dropdown-toggle:focus,
.open > .btn-default.dropdown-toggle.focus,
@ -524,4 +544,20 @@ $ikono--font: 'Helvetica Neue', 'Helvetica', sans-serif !important;
.client--ikonotv .acl-information-dropdown-list .title {
color: $ikono--button-color;
}
.client--ikonotv .action-file.icon-ascribe-ok,
.client--ikonotv .action-file.icon-ascribe-ok:hover {
color: $ikono--button-color;
}
.client--ikonotv .ascribe-progress-bar span {
text-shadow: -1px 0 $ikono--button-color,
0 1px $ikono--button-color,
1px 0 $ikono--button-color,
0 -1px $ikono--button-color;
}
.client--ikonotv .upload-button-wrapper > span {
color: $ikono--button-color;
}