From b5f0180cd668d6290d7d5bcdac0cc249f0e4ddae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Tue, 26 May 2015 14:05:34 +0200 Subject: [PATCH 01/28] Orderable Resource not a requirement for table anymore --- .DS_Store | Bin 0 -> 6148 bytes js/.DS_Store | Bin 0 -> 6148 bytes js/components/.DS_Store | Bin 0 -> 6148 bytes js/components/ascribe_table/.DS_Store | Bin 0 -> 6148 bytes js/components/ascribe_table/table_header.js | 6 +++--- js/components/ascribe_table/table_header_item.js | 10 +++++----- .../ascribe_table/table_item_subtable.js | 15 ++------------- 7 files changed, 10 insertions(+), 21 deletions(-) create mode 100644 .DS_Store create mode 100644 js/.DS_Store create mode 100644 js/components/.DS_Store create mode 100644 js/components/ascribe_table/.DS_Store diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..36dd3e247a289deecc66728285e3a7ea7d7717b6 GIT binary patch literal 6148 zcmeHK%}T>S5Z+P^h$sN=-a$z7bqU9g&Rja6nL- zd9BC;`^{^&@w_(#a=INe?GrBSzUeMnThP=)U=hGnZ?JRn>ndAqh2*} zlWtscJ4b3J{lGJJ#Z8(Y_CXZ2hPLa~WYBBa3%gO6xH1enpF)r8GW4TfDe8uPd|cJ< zt4lv=HtfYpCpd@DiW>$s8B0&LWO8BU@M+jf{r<*wAukH+YlFP#7q^Oev0W$*2KK9E zEw60u>>suVmsi&}w|Dmsk5BppI3|rUuVFYo4=pl?0b+m{7;6U1HE7L_b(WMIF+dFb zh5@`E1Sq0oFx9B84j5Dm0GI{060otCz!+iBF_>zE6%ejN0d*)hEe6-&;1_0}V=&dI z!x=Zt2RC2lrbFTC>+pV|wlnT%q>&gP2EH;dp{F+1|Gl64|F1zbBL;|pv0{K{%hhrT zQZlu5Bsr|L0`wFV1^1;Ihaq67QVe^s6fc1)0lz>4&@q^51P=)P2q+q8AO`-Ffp_vr BUR(eG literal 0 HcmV?d00001 diff --git a/js/.DS_Store b/js/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..8f65424352bd69f2c70480fcd4428c0396c70faa GIT binary patch literal 6148 zcmeHK%}N6?5Kd~ebp-@porS7^54bXxHU=*LGjz2Cm{lSbX1tG0u42(7wduqR{b$)-#$tQ@wwJ>ToCZWIfmxU$?Yh+b*E zR1h1*QonD%TGqni+UCwdtABZQeRF$v|M2*vZ-gTWC^H%c{qw*ggBTzNh=Gw}z&v}_ z)JUC*4nqtO1HZulz7GNv(J`26R8I$VsssScf?EmLSW94xFz6UeHNp%C*P(zql$#QR z>u~T3v(7P?YSiJ3o8p6;FLP6&aP@WAU#R7bI~u7c28e;L42l2s L8mJ=%{*-}tJttr# literal 0 HcmV?d00001 diff --git a/js/components/.DS_Store b/js/components/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..a817a720381c8c59c4e07b04f0dfaa5d3526c674 GIT binary patch literal 6148 zcmeHK&1%~~5T141MouWGq=i5)dky#y_b>RSy6!PxaIpzVaJ7}d3qmrM921N|=R8J} z{=7$M-=UAtN9e6HyBibZCGh*hO9nGxRZ(&yh0HQUC8UQ{3c&LPx8k#$V-jl9K z#YF@nD$b!nK@0;ZAY94j!2ieq?cF2XtsFkWcxnF>BoM1$E$}rrjbeCV49yADfYmV&(i!SPXCc_gR)K{806DJRSH?-ezeL z>NFnTDn04zG|Hx}Y?4O#N!QNT*HJMX_)k0I_zX)sVH)>zu9Z%7aqiXV8Th-i*~^1Q zT{d1kpV#HA`MOz`2aV=@?*H<{wXX9}ABi zW`G%B2G)cDci?&3YqB0*1~b46{5=Nfe2}Pwfy2_GIXcjo767q|VI$~MFF`fZVc@W| zh;LAYEk(4Y!nGK}mSbGHyue{;(Uya7&4+Mb7Oq1P=Ic1WH0dA$i)@(zW?-3t4LkJd z{(pCW|G!+sBW8dZSStoZwcTyEa7pfNU0EF6wG#CMDhcJ478fPxn5!6b=_=kuHG*+T X4r1W2w1^QD{t+-Vuwe%NDFc51NIqci literal 0 HcmV?d00001 diff --git a/js/components/ascribe_table/.DS_Store b/js/components/ascribe_table/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..5008ddfcf53c02e82d7eee2e57c38e5672ef89f6 GIT binary patch literal 6148 zcmeH~Jr2S!425mzP>H1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0 column.rowWidth ); - let numOfColumns = GeneralUtils.sumNumList(listOfRowValues); - - if(numOfColumns > 10) { - throw new Error('Bootstrap has only 12 columns to assign. You defined ' + numOfColumns + '. Change this in the columnMap you\'re passing to the table.') - } else { - return bootstrapClasses.join( listOfRowValues[i] + ' ') + listOfRowValues[i]; - } - }, - render() { let calcColumnElementContent = () => { From 65ccaf10cfc43dcded2a92534728b1ce261c3c31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Tue, 26 May 2015 14:32:28 +0200 Subject: [PATCH 02/28] remove all .DS_Store and add to gitignore --- .DS_Store | Bin 6148 -> 0 bytes .gitignore | 2 ++ js/.DS_Store | Bin 6148 -> 0 bytes js/components/.DS_Store | Bin 6148 -> 0 bytes js/components/ascribe_table/.DS_Store | Bin 6148 -> 0 bytes 5 files changed, 2 insertions(+) delete mode 100644 .DS_Store delete mode 100644 js/.DS_Store delete mode 100644 js/components/.DS_Store delete mode 100644 js/components/ascribe_table/.DS_Store diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index 36dd3e247a289deecc66728285e3a7ea7d7717b6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHK%}T>S5Z+P^h$sN=-a$z7bqU9g&Rja6nL- zd9BC;`^{^&@w_(#a=INe?GrBSzUeMnThP=)U=hGnZ?JRn>ndAqh2*} zlWtscJ4b3J{lGJJ#Z8(Y_CXZ2hPLa~WYBBa3%gO6xH1enpF)r8GW4TfDe8uPd|cJ< zt4lv=HtfYpCpd@DiW>$s8B0&LWO8BU@M+jf{r<*wAukH+YlFP#7q^Oev0W$*2KK9E zEw60u>>suVmsi&}w|Dmsk5BppI3|rUuVFYo4=pl?0b+m{7;6U1HE7L_b(WMIF+dFb zh5@`E1Sq0oFx9B84j5Dm0GI{060otCz!+iBF_>zE6%ejN0d*)hEe6-&;1_0}V=&dI z!x=Zt2RC2lrbFTC>+pV|wlnT%q>&gP2EH;dp{F+1|Gl64|F1zbBL;|pv0{K{%hhrT zQZlu5Bsr|L0`wFV1^1;Ihaq67QVe^s6fc1)0lz>4&@q^51P=)P2q+q8AO`-Ffp_vr BUR(eG diff --git a/.gitignore b/.gitignore index 580f3863..31b4a8c5 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,5 @@ node_modules npm-debug.log build/app.js + +.DS_Store \ No newline at end of file diff --git a/js/.DS_Store b/js/.DS_Store deleted file mode 100644 index 8f65424352bd69f2c70480fcd4428c0396c70faa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHK%}N6?5Kd~ebp-@porS7^54bXxHU=*LGjz2Cm{lSbX1tG0u42(7wduqR{b$)-#$tQ@wwJ>ToCZWIfmxU$?Yh+b*E zR1h1*QonD%TGqni+UCwdtABZQeRF$v|M2*vZ-gTWC^H%c{qw*ggBTzNh=Gw}z&v}_ z)JUC*4nqtO1HZulz7GNv(J`26R8I$VsssScf?EmLSW94xFz6UeHNp%C*P(zql$#QR z>u~T3v(7P?YSiJ3o8p6;FLP6&aP@WAU#R7bI~u7c28e;L42l2s L8mJ=%{*-}tJttr# diff --git a/js/components/.DS_Store b/js/components/.DS_Store deleted file mode 100644 index a817a720381c8c59c4e07b04f0dfaa5d3526c674..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHK&1%~~5T141MouWGq=i5)dky#y_b>RSy6!PxaIpzVaJ7}d3qmrM921N|=R8J} z{=7$M-=UAtN9e6HyBibZCGh*hO9nGxRZ(&yh0HQUC8UQ{3c&LPx8k#$V-jl9K z#YF@nD$b!nK@0;ZAY94j!2ieq?cF2XtsFkWcxnF>BoM1$E$}rrjbeCV49yADfYmV&(i!SPXCc_gR)K{806DJRSH?-ezeL z>NFnTDn04zG|Hx}Y?4O#N!QNT*HJMX_)k0I_zX)sVH)>zu9Z%7aqiXV8Th-i*~^1Q zT{d1kpV#HA`MOz`2aV=@?*H<{wXX9}ABi zW`G%B2G)cDci?&3YqB0*1~b46{5=Nfe2}Pwfy2_GIXcjo767q|VI$~MFF`fZVc@W| zh;LAYEk(4Y!nGK}mSbGHyue{;(Uya7&4+Mb7Oq1P=Ic1WH0dA$i)@(zW?-3t4LkJd z{(pCW|G!+sBW8dZSStoZwcTyEa7pfNU0EF6wG#CMDhcJ478fPxn5!6b=_=kuHG*+T X4r1W2w1^QD{t+-Vuwe%NDFc51NIqci diff --git a/js/components/ascribe_table/.DS_Store b/js/components/ascribe_table/.DS_Store deleted file mode 100644 index 5008ddfcf53c02e82d7eee2e57c38e5672ef89f6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeH~Jr2S!425mzP>H1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0 Date: Tue, 26 May 2015 14:57:32 +0200 Subject: [PATCH 03/28] Refactor TableColumnMixin --- js/components/ascribe_table/table_header.js | 2 +- js/components/ascribe_table/table_item.js | 2 +- js/components/ascribe_table/table_item_subtable.js | 2 +- js/mixins/table_column_mixin.js | 8 ++++---- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/js/components/ascribe_table/table_header.js b/js/components/ascribe_table/table_header.js index a4e68879..8176ad31 100644 --- a/js/components/ascribe_table/table_header.js +++ b/js/components/ascribe_table/table_header.js @@ -23,7 +23,7 @@ let TableHeader = React.createClass({
{this.props.columnList.map((val, i) => { - let columnClasses = this.calcColumnClasses(this.props.columnList, i); + let columnClasses = this.calcColumnClasses(this.props.columnList, i, 12); let columnName = this.props.columnList[i].columnName; let canBeOrdered = this.props.columnList[i].canBeOrdered; diff --git a/js/components/ascribe_table/table_item.js b/js/components/ascribe_table/table_item.js index 23f91201..89e9fbbe 100644 --- a/js/components/ascribe_table/table_item.js +++ b/js/components/ascribe_table/table_item.js @@ -18,7 +18,7 @@ let TableItem = React.createClass({ return this.props.columnList.map((column, i) => { let TypeElement = column.displayType; - let columnClass = this.calcColumnClasses(this.props.columnList, i); + let columnClass = this.calcColumnClasses(this.props.columnList, i, 12); return (
diff --git a/js/components/ascribe_table/table_item_subtable.js b/js/components/ascribe_table/table_item_subtable.js index 70f8fbee..a4643d3e 100644 --- a/js/components/ascribe_table/table_item_subtable.js +++ b/js/components/ascribe_table/table_item_subtable.js @@ -56,7 +56,7 @@ let TableItemSubtable = React.createClass({ return this.props.columnList.map((column, i) => { let TypeElement = column.displayType; - let columnClass = this.calcColumnClasses(this.props.columnList, i); + let columnClass = this.calcColumnClasses(this.props.columnList, i, 12); return (
diff --git a/js/mixins/table_column_mixin.js b/js/mixins/table_column_mixin.js index 5904389d..d74214e1 100644 --- a/js/mixins/table_column_mixin.js +++ b/js/mixins/table_column_mixin.js @@ -7,14 +7,14 @@ let TableColumnMixin = { * Generates the bootstrap grid column declarations automatically using * the columnMap. */ - calcColumnClasses(list, i) { + calcColumnClasses(list, i, numOfColumns) { let bootstrapClasses = ['col-xs-', 'col-sm-', 'col-md-', 'col-lg-']; let listOfRowValues = list.map((column) => column.rowWidth ); - let numOfColumns = GeneralUtils.sumNumList(listOfRowValues); + let numOfUsedColumns = GeneralUtils.sumNumList(listOfRowValues); - if(numOfColumns > 12) { - throw new Error('Bootstrap has only 12 columns to assign. You defined ' + numOfColumns + '. Change this in the columnMap you\'re passing to the table.') + if(numOfUsedColumns > numOfColumns) { + throw new Error('This table has only ' + numOfColumns + ' columns to assign. You defined ' + numOfUsedColumns + '. Change this in the columnMap you\'re passing to the table.') } else { return bootstrapClasses.join( listOfRowValues[i] + ' ') + listOfRowValues[i]; } From e3c115897f1d054291f9363363211e59e56a76d7 Mon Sep 17 00:00:00 2001 From: ddejongh Date: Tue, 26 May 2015 15:31:28 +0200 Subject: [PATCH 04/28] refactored edition properties --- css/main.css | 4 ++ js/components/edition.js | 83 ++++++++++++---------------------------- 2 files changed, 29 insertions(+), 58 deletions(-) diff --git a/css/main.css b/css/main.css index 1676fc84..4ecb7e62 100644 --- a/css/main.css +++ b/css/main.css @@ -70,6 +70,10 @@ margin-bottom: -0.2em; } +.ascribe-detail-property > .row-same-height > .col-xs-2 { + text-transform: uppercase; +} + /* columns of same height styles */ /* http://www.minimit.com/articles/solutions-tutorials/bootstrap-3-responsive-columns-of-same-height */ .row-full-height { diff --git a/js/components/edition.js b/js/components/edition.js index 336bacff..a0f1dd76 100644 --- a/js/components/edition.js +++ b/js/components/edition.js @@ -25,39 +25,13 @@ let Edition = React.createClass({ }); let EditionHeader = React.createClass({ - //propTypes: { - // title: React.PropTypes.string.isRequired - //}, - render() { + var title_html =
{this.props.edition.title}
; return (
-
-
-
-
TITLE:
-
-
-
{this.props.edition.title}
-
-
-
-
-
-
BY:
-
-
-
{this.props.edition.artist_name}
-
-
-
-
-
DATE:
-
-
-
{ this.props.edition.date_created.slice(0,4) }
-
-
+ + +
); @@ -65,42 +39,35 @@ let EditionHeader = React.createClass({ }); let EditionDetails = React.createClass({ - //propTypes: { - // title: React.PropTypes.string.isRequired - //}, - render() { return (
-
-
-
EDITION:
-
-
-
{ this.props.edition.edition_number } of {this.props.edition.num_editions}
-
-
-
-
-
ID:
-
-
-
{ this.props.edition.bitcoin_id }
-
-
-
-
-
OWNER:
-
-
-
{ this.props.edition.owner }
-
-
+ + +
); } }); +let EditionDetailProperty = React.createClass({ + render() { + return ( +
+
+
+
{ this.props.label }:
+
+
+
{ this.props.value }
+
+
+
+ ); + } +}); + export default Edition; \ No newline at end of file From 230ecfb0e409bff2cf57eb3337a345a90d9437d8 Mon Sep 17 00:00:00 2001 From: ddejongh Date: Tue, 26 May 2015 16:46:02 +0200 Subject: [PATCH 05/28] modal try 1 --- index.html | 1 + js/actions/edition_actions.js | 2 +- js/components/edition.js | 74 +++++++++++++++++++++++++++++++++-- package.json | 3 +- 4 files changed, 74 insertions(+), 6 deletions(-) diff --git a/index.html b/index.html index 824eeaee..95b1c72b 100644 --- a/index.html +++ b/index.html @@ -12,6 +12,7 @@
+ diff --git a/js/actions/edition_actions.js b/js/actions/edition_actions.js index f8d43ccc..a39c330a 100644 --- a/js/actions/edition_actions.js +++ b/js/actions/edition_actions.js @@ -15,7 +15,7 @@ class EditionActions { this.actions.updateEdition(res.edition); }) .catch((err) => { - console.log(err); + console.log(err); }); } } diff --git a/js/components/edition.js b/js/components/edition.js index a0f1dd76..b2eab502 100644 --- a/js/components/edition.js +++ b/js/components/edition.js @@ -1,24 +1,29 @@ import React from 'react'; import ImageViewer from './ascribe_media/image_viewer'; +import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger'; +import OverlayMixin from 'react-bootstrap/lib/OverlayMixin'; +import Modal from 'react-bootstrap/lib/Modal'; +import ModalTrigger from 'react-bootstrap/lib/ModalTrigger'; +import Modal from 'react-modal'; /** * This is the component that implements display-specific functionality */ let Edition = React.createClass({ - //propTypes: { - // title: React.PropTypes.string.isRequired - //}, - render() { + var modal = ; return (
+ {modal}
+
+
); } @@ -69,5 +74,66 @@ let EditionDetailProperty = React.createClass({ } }); +let ShareModal = React.createClass({ + mixins: [OverlayMixin], + + getInitialState: function() { + return { + isModalOpen: true + }; + }, + renderOverlay: function() { + if (!this.state.isModalOpen) { + return ; + } + }, + render: function() { + return ( + + + ); + } +}); +//let ShareModal = React.createClass({ +// mixins: [OverlayMixin], +// +// getInitialState: function() { +// return { +// isModalOpen: true +// }; +// }, +// renderOverlay: function() { +// if (!this.state.isModalOpen) { +// return ; +// } +// }, +// hide: function(){ +// this.setState({isModalOpen: false}); +// }, +// render: function() { +// var content = "Hi,\n\nI am sharing \"" + this.props.edition.title + +// "\" with you.\n\nTruly yours,\n"; +// return ( +// +//
+//
+//
+// +//
+//
+// +//
+//
+// +// +//
+//
+//
+//
+// ); +// } +//}); export default Edition; \ No newline at end of file diff --git a/package.json b/package.json index a7b45c6c..5a7f2787 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,8 @@ "object-assign": "^2.0.0", "react": "^0.13.2", "react-router": "^0.13.3", - "uglifyjs": "^2.4.10" + "uglifyjs": "^2.4.10", + "react-bootstrap": "~0.22.6" }, "jest": { "scriptPreprocessor": "node_modules/babel-jest", From d685d68d154a6ca500727a4a95bc63d716683fb2 Mon Sep 17 00:00:00 2001 From: ddejongh Date: Tue, 26 May 2015 16:46:50 +0200 Subject: [PATCH 06/28] modal try 1 --- js/components/edition.js | 1 - 1 file changed, 1 deletion(-) diff --git a/js/components/edition.js b/js/components/edition.js index b2eab502..d8b9899c 100644 --- a/js/components/edition.js +++ b/js/components/edition.js @@ -4,7 +4,6 @@ import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger'; import OverlayMixin from 'react-bootstrap/lib/OverlayMixin'; import Modal from 'react-bootstrap/lib/Modal'; import ModalTrigger from 'react-bootstrap/lib/ModalTrigger'; -import Modal from 'react-modal'; /** * This is the component that implements display-specific functionality From 92be6a63e8d90b247f97c0bbf31946a492fd5184 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Tue, 26 May 2015 16:48:48 +0200 Subject: [PATCH 07/28] select state is saved in the store --- css/main.css | 8 +++-- js/actions/edition_list_actions.js | 5 +-- js/components/ascribe_table/table_item.js | 8 +++-- .../ascribe_table/table_item_selectable.js | 36 +++++++++++++++++++ .../ascribe_table/table_item_subtable.js | 15 ++++++-- js/stores/edition_list_store.js | 18 ++++++++-- 6 files changed, 79 insertions(+), 11 deletions(-) create mode 100644 js/components/ascribe_table/table_item_selectable.js diff --git a/css/main.css b/css/main.css index cac29beb..de85b7fc 100644 --- a/css/main.css +++ b/css/main.css @@ -31,10 +31,10 @@ .ascribe-table-header-column > span > .glyphicon { font-size: .5em; } - +/* .ascribe-table-item:nth-child(even) { background-color: #F5F5F5; -} +}*/ /*.ascribe-table-item:hover { background-color: #EEEEEE; @@ -55,4 +55,8 @@ .btn-ascribe, .btn-ascribe:hover, .btn-ascribe:active, .btn-ascribe:focus { background-color: rgba(2, 182, 163, 0.5); border-color: rgba(2, 182, 163, 0.5); +} + +.ascribe-table-item-selected { + background-color: rgba(2, 182, 163, 0.5); } \ No newline at end of file diff --git a/js/actions/edition_list_actions.js b/js/actions/edition_list_actions.js index 055ef2a5..10e1d66c 100644 --- a/js/actions/edition_list_actions.js +++ b/js/actions/edition_list_actions.js @@ -5,7 +5,8 @@ import EditionListFetcher from '../fetchers/edition_list_fetcher.js'; class EditionListActions { constructor() { this.generateActions( - 'updateEditionList' + 'updateEditionList', + 'selectEdition' ); } @@ -14,7 +15,7 @@ class EditionListActions { .fetch(pieceId) .then((res) => { this.actions.updateEditionList({ - 'editionList': res.editions, + 'editionListOfPiece': res.editions, pieceId }); }) diff --git a/js/components/ascribe_table/table_item.js b/js/components/ascribe_table/table_item.js index 89e9fbbe..6b7b62f8 100644 --- a/js/components/ascribe_table/table_item.js +++ b/js/components/ascribe_table/table_item.js @@ -10,7 +10,9 @@ let TableItem = React.createClass({ propTypes: { columnList: React.PropTypes.arrayOf(React.PropTypes.instanceOf(TableColumnContentModel)), - columnContent: React.PropTypes.object + columnContent: React.PropTypes.object, + onClick: React.PropTypes.func, // See: https://facebook.github.io/react/tips/expose-component-functions.html + classNames: React.PropTypes.string }, render() { @@ -30,7 +32,9 @@ let TableItem = React.createClass({ }; return ( -
+
{calcColumnElementContent()}
diff --git a/js/components/ascribe_table/table_item_selectable.js b/js/components/ascribe_table/table_item_selectable.js new file mode 100644 index 00000000..8e48b816 --- /dev/null +++ b/js/components/ascribe_table/table_item_selectable.js @@ -0,0 +1,36 @@ +import React from 'react'; +import classNames from 'classnames'; + +import TableColumnContentModel from '../../models/table_column_content_model'; + +import TableItem from './table_item'; + +// This Component is implemented as recommended here: http://stackoverflow.com/a/25723635/1263876 +let TableItemSelectable = React.createClass({ + + propTypes: { + parentId: React.PropTypes.number + }, + + propTypes: { + columnList: React.PropTypes.arrayOf(React.PropTypes.instanceOf(TableColumnContentModel)), + columnContent: React.PropTypes.object + }, + + render() { + let tableItemClasses = classNames({ + 'ascribe-table-item-selected': this.props.columnContent.selected + }); + let boundSelectItem = this.props.selectItem.bind(this, this.props.parentId, this.props.columnContent.edition_number); + + return ( + + + ); + } +}); + +export default TableItemSelectable; diff --git a/js/components/ascribe_table/table_item_subtable.js b/js/components/ascribe_table/table_item_subtable.js index a4643d3e..66faee49 100644 --- a/js/components/ascribe_table/table_item_subtable.js +++ b/js/components/ascribe_table/table_item_subtable.js @@ -10,7 +10,7 @@ import EditionListActions from '../../actions/edition_list_actions'; import GeneralUtils from '../../utils/general_utils'; import Table from './table'; -import TableItem from './table_item'; +import TableItemSelectable from './table_item_selectable'; import TableItemText from './table_item_text'; import TableItemSubtableButton from './table_item_subtable_button'; @@ -50,6 +50,13 @@ let TableItemSubtable = React.createClass({ } }, + selectItem(parentId, itemId) { + EditionListActions.selectEdition({ + 'pieceId': parentId, + 'editionId': itemId + }); + }, + render() { let calcColumnElementContent = () => { @@ -83,9 +90,11 @@ let TableItemSubtable = React.createClass({ {this.state.editionList[this.props.columnContent.id].map((edition, i) => { return ( - - + ); })}
diff --git a/js/stores/edition_list_store.js b/js/stores/edition_list_store.js index 4158e74c..0edad1dc 100644 --- a/js/stores/edition_list_store.js +++ b/js/stores/edition_list_store.js @@ -7,8 +7,22 @@ class EditionListStore { this.bindActions(EditionsListActions); } - onUpdateEditionList({pieceId, editionList}) { - this.editionList[pieceId] = editionList; + onUpdateEditionList({pieceId, editionListOfPiece}) { + this.editionList[pieceId] = editionListOfPiece; + } + + onSelectEdition({pieceId, editionId}) { + + this.editionList[pieceId].forEach((edition) => { + if(edition.edition_number === editionId) { + if(edition.selected) { + edition.selected = false; + } else { + edition.selected = true; + } + } + }); + } }; From 3a103c1d9928d09f117ed605643e1740ee648185 Mon Sep 17 00:00:00 2001 From: ddejongh Date: Tue, 26 May 2015 16:52:53 +0200 Subject: [PATCH 08/28] modal try 1 --- js/components/edition.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/js/components/edition.js b/js/components/edition.js index d8b9899c..69a2fbee 100644 --- a/js/components/edition.js +++ b/js/components/edition.js @@ -78,17 +78,20 @@ let ShareModal = React.createClass({ getInitialState: function() { return { - isModalOpen: true + isOpen: true }; }, + hide: function(){ + this.setState({isOpen: false}) + }, renderOverlay: function() { - if (!this.state.isModalOpen) { + if (!this.state.isOpen) { return ; } }, render: function() { return ( - + ); } From d71e6baa19a5f3ec95ee2c4530b6e2a141cfe053 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Tue, 26 May 2015 17:25:03 +0200 Subject: [PATCH 09/28] add persistent selected rows --- js/components/ascribe_table/table_item_subtable.js | 1 + js/stores/edition_list_store.js | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/js/components/ascribe_table/table_item_subtable.js b/js/components/ascribe_table/table_item_subtable.js index 66faee49..f3d65407 100644 --- a/js/components/ascribe_table/table_item_subtable.js +++ b/js/components/ascribe_table/table_item_subtable.js @@ -42,6 +42,7 @@ let TableItemSubtable = React.createClass({ 'open': false }); } else { + EditionListActions.fetchEditionList(this.props.columnContent.id); this.setState({ 'open': true, diff --git a/js/stores/edition_list_store.js b/js/stores/edition_list_store.js index 0edad1dc..feb0ba2a 100644 --- a/js/stores/edition_list_store.js +++ b/js/stores/edition_list_store.js @@ -1,3 +1,5 @@ +import React from 'react'; + import alt from '../alt'; import EditionsListActions from '../actions/edition_list_actions'; @@ -8,6 +10,13 @@ class EditionListStore { } onUpdateEditionList({pieceId, editionListOfPiece}) { + if(this.editionList[pieceId]) { + this.editionList[pieceId].forEach((edition, i) => { + // This uses the index of the new editionList for determining the edition. + // If the list of editions can be sorted in the future, this needs to be changed! + editionListOfPiece[i] = React.addons.update(edition, {$merge: editionListOfPiece[i]}); + }) + } this.editionList[pieceId] = editionListOfPiece; } From 64793cd90b847096b4ad2f764fd0238f2deef91e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Tue, 26 May 2015 19:16:30 +0200 Subject: [PATCH 10/28] remove npm start scripts, add gulp for build and watch, add source maps --- README.md | 4 +--- gulpfile.js | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++ package.json | 22 ++++++++--------- 3 files changed, 78 insertions(+), 15 deletions(-) create mode 100644 gulpfile.js diff --git a/README.md b/README.md index 21c85c0c..c4391d52 100644 --- a/README.md +++ b/README.md @@ -18,9 +18,7 @@ Install some nice extensions for Chrom(e|ium): git clone git@bitbucket.org:ascribe/onion.git cd onion npm install -npm run watch - -python -mSimpleHTTPServer +gulp serve ``` diff --git a/gulpfile.js b/gulpfile.js new file mode 100644 index 00000000..3b42e4de --- /dev/null +++ b/gulpfile.js @@ -0,0 +1,67 @@ +var gulp = require('gulp'); +var gulpif = require('gulp-if'); +var sourcemaps = require('gulp-sourcemaps'); +var util = require('gulp-util'); +var source = require('vinyl-source-stream'); +var buffer = require('vinyl-buffer'); +var watchify = require('watchify'); +var browserify = require('browserify'); +var browserSync = require('browser-sync'); +var babelify = require('babelify'); +var notify = require('gulp-notify'); +var _ = require('lodash'); + +gulp.task('build', function() { + bundle(false); +}); + +gulp.task('serve', ['browser-sync'], function() { + bundle(true); +}); + +gulp.task('browser-sync', function() { + browserSync({ + server: { + baseDir: "." + }, + port: process.env.PORT || 3000 + }); +}); + +function bundle(watch) { + var bro; + + if (watch) { + bro = watchify(browserify('./js/app.js', + // Assigning debug to have sourcemaps + _.assign(watchify.args, { + debug: true + }))); + bro.on('update', function() { + rebundle(bro, true); + }); + } else { + bro = browserify('./js/app.js', { + debug: true + }); + } + + bro.transform(babelify.configure({ + compact: false + })); + + function rebundle(bundler, watch) { + return bundler.bundle() + .on('error', notify.onError('Error: <%= error.message %>')) + .pipe(source('app.js')) + .pipe(buffer()) + .pipe(sourcemaps.init({ + loadMaps: true + })) // loads map from browserify file + .pipe(sourcemaps.write()) // writes .map file + .pipe(gulp.dest('./build')) + .pipe(browserSync.stream()); + } + + return rebundle(bro); +} \ No newline at end of file diff --git a/package.json b/package.json index a7b45c6c..2313c305 100644 --- a/package.json +++ b/package.json @@ -3,26 +3,24 @@ "version": "0.0.1", "description": "Das neue web client for Ascribe", "main": "js/app.js", - "scripts": { - "watch": "watchify -o build/app.js -v -d js/app.js", - "build": "browserify . -t [envify --NODE_ENV production] | uglifyjs -cm > build/app.js", - "test": "jest" - }, "author": "Ascribe", "license": "Copyright", - "browserify": { - "transform": [ - "babelify", - "envify" - ] - }, "devDependencies": { "babel-jest": "^4.0.0", - "babelify": "^6.0.2", + "babelify": "^6.1.2", + "browser-sync": "^2.7.5", "browserify": "^9.0.8", "envify": "^3.4.0", + "gulp": "^3.8.11", + "gulp-if": "^1.2.5", + "gulp-notify": "^2.2.0", + "gulp-sourcemaps": "^1.5.2", + "gulp-util": "^3.0.4", "jest-cli": "^0.4.0", + "lodash": "^3.9.3", "reactify": "^1.1.0", + "vinyl-buffer": "^1.0.0", + "vinyl-source-stream": "^1.1.0", "watchify": "^3.1.2" }, "dependencies": { From 9c017ac993f3c685b485f71098b4a76a02c1ffbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Tue, 26 May 2015 19:50:18 +0200 Subject: [PATCH 11/28] Fix bind warning --- js/components/ascribe_table/table_item_selectable.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/js/components/ascribe_table/table_item_selectable.js b/js/components/ascribe_table/table_item_selectable.js index 8e48b816..974c5453 100644 --- a/js/components/ascribe_table/table_item_selectable.js +++ b/js/components/ascribe_table/table_item_selectable.js @@ -17,17 +17,20 @@ let TableItemSelectable = React.createClass({ columnContent: React.PropTypes.object }, + selectItem() { + this.props.selectItem(this.props.parentId, this.props.columnContent.edition_number); + }, + render() { let tableItemClasses = classNames({ 'ascribe-table-item-selected': this.props.columnContent.selected }); - let boundSelectItem = this.props.selectItem.bind(this, this.props.parentId, this.props.columnContent.edition_number); return ( + onClick={this.selectItem}> ); } From abac948dd1a285eb98c71a1a23d522820924d894 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Tue, 26 May 2015 19:59:37 +0200 Subject: [PATCH 12/28] Add ACL display for table --- js/components/ascribe_table/table_item_acl.js | 18 ++++++++++++++++++ .../ascribe_table/table_item_subtable.js | 5 +++-- 2 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 js/components/ascribe_table/table_item_acl.js diff --git a/js/components/ascribe_table/table_item_acl.js b/js/components/ascribe_table/table_item_acl.js new file mode 100644 index 00000000..87e14761 --- /dev/null +++ b/js/components/ascribe_table/table_item_acl.js @@ -0,0 +1,18 @@ +import React from 'react'; + + +let TableItemAcl = React.createClass({ + propTypes: { + content: React.PropTypes.array.isRequired + }, + + render() { + return ( + + {this.props.content.join('/')} + + ); + } +}); + +export default TableItemAcl; diff --git a/js/components/ascribe_table/table_item_subtable.js b/js/components/ascribe_table/table_item_subtable.js index f3d65407..85e361fe 100644 --- a/js/components/ascribe_table/table_item_subtable.js +++ b/js/components/ascribe_table/table_item_subtable.js @@ -10,8 +10,9 @@ import EditionListActions from '../../actions/edition_list_actions'; import GeneralUtils from '../../utils/general_utils'; import Table from './table'; -import TableItemSelectable from './table_item_selectable'; import TableItemText from './table_item_text'; +import TableItemAcl from './table_item_acl'; +import TableItemSelectable from './table_item_selectable'; import TableItemSubtableButton from './table_item_subtable_button'; @@ -81,7 +82,7 @@ let TableItemSubtable = React.createClass({ let columnList = [ new TableColumnContentModel('edition_number', 'Edition Number', TableItemText, 2, false), new TableColumnContentModel('user_registered', 'User', TableItemText, 4, true), - new TableColumnContentModel('bitcoin_id', 'Bitcoin Address', TableItemText, 4, true) + new TableColumnContentModel('acl', 'Actions', TableItemAcl, 4, true) ]; if(this.state.open && this.state.editionList[this.props.columnContent.id] && this.state.editionList[this.props.columnContent.id].length) { From b875a9817cc128a8aadb2ec898272f6009cba895 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Tue, 26 May 2015 20:20:17 +0200 Subject: [PATCH 13/28] Refactor table_item logic --- js/components/ascribe_table/table_item.js | 26 ++++---------- .../ascribe_table/table_item_subtable.js | 26 +++----------- .../ascribe_table/table_item_wrapper.js | 34 +++++++++++++++++++ 3 files changed, 46 insertions(+), 40 deletions(-) create mode 100644 js/components/ascribe_table/table_item_wrapper.js diff --git a/js/components/ascribe_table/table_item.js b/js/components/ascribe_table/table_item.js index 6b7b62f8..1827253f 100644 --- a/js/components/ascribe_table/table_item.js +++ b/js/components/ascribe_table/table_item.js @@ -1,12 +1,11 @@ import React from 'react'; -import TableColumnMixin from '../../mixins/table_column_mixin'; - import TableColumnContentModel from '../../models/table_column_content_model'; +import TableItemWrapper from './table_item_wrapper'; + let TableItem = React.createClass({ - mixins: [TableColumnMixin], propTypes: { columnList: React.PropTypes.arrayOf(React.PropTypes.instanceOf(TableColumnContentModel)), @@ -16,27 +15,16 @@ let TableItem = React.createClass({ }, render() { - let calcColumnElementContent = () => { - return this.props.columnList.map((column, i) => { - - let TypeElement = column.displayType; - let columnClass = this.calcColumnClasses(this.props.columnList, i, 12); - - return ( -
- -
- ); - - }); - }; - return (
- {calcColumnElementContent()} + +
); diff --git a/js/components/ascribe_table/table_item_subtable.js b/js/components/ascribe_table/table_item_subtable.js index 85e361fe..00c456ce 100644 --- a/js/components/ascribe_table/table_item_subtable.js +++ b/js/components/ascribe_table/table_item_subtable.js @@ -1,15 +1,13 @@ import React from 'react'; import TableColumnContentModel from '../../models/table_column_content_model'; -import TableColumnMixin from '../../mixins/table_column_mixin'; import EditionListStore from '../../stores/edition_list_store'; import EditionListActions from '../../actions/edition_list_actions'; -// ToDo: Create Table-specific Utils to not lock it to projects utilities -import GeneralUtils from '../../utils/general_utils'; import Table from './table'; +import TableItemWrapper from './table_item_wrapper'; import TableItemText from './table_item_text'; import TableItemAcl from './table_item_acl'; import TableItemSelectable from './table_item_selectable'; @@ -17,7 +15,6 @@ import TableItemSubtableButton from './table_item_subtable_button'; let TableItemSubtable = React.createClass({ - mixins: [TableColumnMixin], propTypes: { columnList: React.PropTypes.arrayOf(React.PropTypes.instanceOf(TableColumnContentModel)), columnContent: React.PropTypes.object @@ -61,22 +58,6 @@ let TableItemSubtable = React.createClass({ render() { - let calcColumnElementContent = () => { - return this.props.columnList.map((column, i) => { - - let TypeElement = column.displayType; - let columnClass = this.calcColumnClasses(this.props.columnList, i, 12); - - return ( -
- -
- ); - - }); - }; - - let renderEditionListTable = () => { let columnList = [ @@ -109,7 +90,10 @@ let TableItemSubtable = React.createClass({ return (
- {calcColumnElementContent()} +
diff --git a/js/components/ascribe_table/table_item_wrapper.js b/js/components/ascribe_table/table_item_wrapper.js new file mode 100644 index 00000000..2f9f4c7e --- /dev/null +++ b/js/components/ascribe_table/table_item_wrapper.js @@ -0,0 +1,34 @@ +import React from 'react'; + +import TableColumnContentModel from '../../models/table_column_content_model'; +import TableColumnMixin from '../../mixins/table_column_mixin'; + +let TableItemWrapper = React.createClass({ + mixins: [TableColumnMixin], + propTypes: { + columnList: React.PropTypes.arrayOf(React.PropTypes.instanceOf(TableColumnContentModel)), + columnContent: React.PropTypes.object, + columnWidth: React.PropTypes.number.isRequired + }, + + render() { + return ( +
+ {this.props.columnList.map((column, i) => { + + let TypeElement = column.displayType; + let columnClass = this.calcColumnClasses(this.props.columnList, i, this.props.columnWidth); + + return ( +
+ +
+ ); + + })} +
+ ); + } +}); + +export default TableItemWrapper; \ No newline at end of file From f6dab18cba7a4b53cf8f7219d332b21a09c2b657 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Wed, 27 May 2015 08:24:13 +0200 Subject: [PATCH 14/28] small refactor --- js/components/ascribe_table/table.js | 8 +++++++- js/components/ascribe_table/table_item_selectable.js | 5 +++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/js/components/ascribe_table/table.js b/js/components/ascribe_table/table.js index 90067be6..06af7b89 100644 --- a/js/components/ascribe_table/table.js +++ b/js/components/ascribe_table/table.js @@ -27,7 +27,13 @@ let Table = React.createClass({ if(this.props.itemList && this.props.itemList.length > 0) { return (
- + {this.renderChildren()}
); diff --git a/js/components/ascribe_table/table_item_selectable.js b/js/components/ascribe_table/table_item_selectable.js index 974c5453..7b03618c 100644 --- a/js/components/ascribe_table/table_item_selectable.js +++ b/js/components/ascribe_table/table_item_selectable.js @@ -5,7 +5,7 @@ import TableColumnContentModel from '../../models/table_column_content_model'; import TableItem from './table_item'; -// This Component is implemented as recommended here: http://stackoverflow.com/a/25723635/1263876 +// This component is implemented as recommended here: http://stackoverflow.com/a/25723635/1263876 let TableItemSelectable = React.createClass({ propTypes: { @@ -27,7 +27,8 @@ let TableItemSelectable = React.createClass({ }); return ( - From aa75b7d8bdd9c26b40b0e5c07af5c0e189daa1a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Wed, 27 May 2015 09:05:39 +0200 Subject: [PATCH 15/28] fix small bug --- js/components/ascribe_table/table_item_selectable.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/js/components/ascribe_table/table_item_selectable.js b/js/components/ascribe_table/table_item_selectable.js index 7b03618c..bc508a7c 100644 --- a/js/components/ascribe_table/table_item_selectable.js +++ b/js/components/ascribe_table/table_item_selectable.js @@ -8,13 +8,10 @@ import TableItem from './table_item'; // This component is implemented as recommended here: http://stackoverflow.com/a/25723635/1263876 let TableItemSelectable = React.createClass({ - propTypes: { - parentId: React.PropTypes.number - }, - propTypes: { columnList: React.PropTypes.arrayOf(React.PropTypes.instanceOf(TableColumnContentModel)), - columnContent: React.PropTypes.object + columnContent: React.PropTypes.object, + parentId: React.PropTypes.number }, selectItem() { From 8624eb26c790f86ec43b26efb8e6259ff6381c0b Mon Sep 17 00:00:00 2001 From: ddejongh Date: Wed, 27 May 2015 09:34:49 +0200 Subject: [PATCH 16/28] sharemodal view --- css/ascribe-fonts/style.css | 14 ++-- css/main.css | 80 ++++++++++++++++++++-- index.html | 7 +- js/components/ascribe_modal/modal_share.js | 51 ++++++++++++++ js/components/edition.js | 79 ++------------------- js/components/edition_container.js | 10 ++- 6 files changed, 152 insertions(+), 89 deletions(-) create mode 100644 js/components/ascribe_modal/modal_share.js diff --git a/css/ascribe-fonts/style.css b/css/ascribe-fonts/style.css index c4ecbdc8..eaab4bca 100644 --- a/css/ascribe-fonts/style.css +++ b/css/ascribe-fonts/style.css @@ -1,10 +1,10 @@ @font-face { font-family: 'ascribe'; - src:url('fonts/ascribe.eot?-6bb2dq'); - src:url('fonts/ascribe.eot?#iefix-6bb2dq') format('embedded-opentype'), - url('fonts/ascribe.woff?-6bb2dq') format('woff'), - url('fonts/ascribe.ttf?-6bb2dq') format('truetype'), - url('fonts/ascribe.svg?-6bb2dq#ascribe') format('svg'); + src:url('ascribe.eot?-6bb2dq'); + src:url('ascribe.eot?#iefix-6bb2dq') format('embedded-opentype'), + url('ascribe.woff?-6bb2dq') format('woff'), + url('ascribe.ttf?-6bb2dq') format('truetype'), + url('ascribe.svg?-6bb2dq#ascribe') format('svg'); font-weight: normal; font-style: normal; } @@ -187,3 +187,7 @@ content: "\eae9"; } +.btn-glyph-ascribe{ + font-size: 18px; + padding: 4px 12px 0 10px +} \ No newline at end of file diff --git a/css/main.css b/css/main.css index 4ecb7e62..7ccd50a8 100644 --- a/css/main.css +++ b/css/main.css @@ -52,28 +52,94 @@ vertical-align: middle; } -.btn-ascribe, .btn-ascribe:hover, .btn-ascribe:active, .btn-ascribe:focus { - background-color: rgba(2, 182, 163, 0.5); - border-color: rgba(2, 182, 163, 0.5); +/*.btn-ascribe, .btn-ascribe:hover, .btn-ascribe:active, .btn-ascribe:focus {*/ +/*background-color: rgba(2, 182, 163, 0.5);*/ +/*border-color: rgba(2, 182, 163, 0.5);*/ +/*}*/ + +.btn-ascribe, .btn-ascribe-inv { + border: 1px solid #444; + line-height: 2em; + margin-right: 1px; + margin-left: 0 !important; + font-family: sans-serif !important; + border-radius: 0 !important; + } -.ascribe-detail-header{ +.btn-ascribe, .btn-ascribe-inv:active, .btn-ascribe-inv:hover { + color: #222 !important; + background-color: #FFF; +} + +.btn-ascribe:active, .btn-ascribe:hover, .btn-ascribe-inv { + color: #FFF !important; + background-color: #444; +} + +.btn-ascribe-inv:disabled, .btn-ascribe-inv:focus { + color: #444 !important; + background-color: #BBB !important; + border: 1px solid #444 !important; +} + +.btn-ascribe-sm { + font-size: 12px; + line-height: 1.3em; +} + +.btn-ascribe-green, .btn-ascribe-green-inv { + border: 1px solid #48DACB; + line-height: 2em; + margin-left: 0 !important; + font-family: sans-serif !important; + border-radius: 0 !important; + +} + +.btn-ascribe-green, .btn-ascribe-green-inv:active, .btn-ascribe-green-inv:hover { + background-color: #FFF; + border: 1px solid rgba(2, 182, 163, 0.5); + color: rgba(2, 182, 163, 0.5); +} + +.btn-ascribe-green:active, .btn-ascribe-green:hover, .btn-ascribe-green-inv { + border: 1px solid rgba(2, 182, 163, 0.5); + color: white; + background-color: rgba(2, 182, 163, 0.5); +} + +.ascribe-detail-header { margin-top: 2em; } -.ascribe-detail-header > div{ - padding-bottom: 0.4em; -} .ascribe-detail-title { font-size: 2em; margin-bottom: -0.2em; } +.ascribe-detail-property { + padding-bottom: 0.4em; +} .ascribe-detail-property > .row-same-height > .col-xs-2 { text-transform: uppercase; } +.input-text-ascribe { + border-bottom: 1px solid black; + border-top: 0; + border-left: 0; + border-right: 0; + background: transparent; + border-radius: 0 !important; + box-shadow: none; +} + +.textarea-ascribe-message { + height: 13em !important; +} + /* columns of same height styles */ /* http://www.minimit.com/articles/solutions-tutorials/bootstrap-3-responsive-columns-of-same-height */ .row-full-height { diff --git a/index.html b/index.html index 95b1c72b..21dac715 100644 --- a/index.html +++ b/index.html @@ -5,9 +5,10 @@ ascribe - - - + + + + diff --git a/js/components/ascribe_modal/modal_share.js b/js/components/ascribe_modal/modal_share.js new file mode 100644 index 00000000..ca148fa2 --- /dev/null +++ b/js/components/ascribe_modal/modal_share.js @@ -0,0 +1,51 @@ +import React from 'react'; +import Modal from 'react-bootstrap/lib/Modal'; +import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger'; +import ModalTrigger from 'react-bootstrap/lib/ModalTrigger'; +import Tooltip from 'react-bootstrap/lib/Tooltip'; + + +let ShareModalButton = React.createClass({ + render() { + return ( + Share the artwork}> + }> +
+ +
+
+
+ ) + } +}); + +let ShareModal = React.createClass({ + render() { + var content = "Hi,\n\nI am sharing \"" + this.props.edition.title + + "\" with you.\n\nTruly yours,\n" + this.props.currentUser.username; + return ( + +
+
+
+ +
+
+ +
+
+ + +
+
+
+
+ ); + } +}); + +export default ShareModalButton; \ No newline at end of file diff --git a/js/components/edition.js b/js/components/edition.js index 69a2fbee..b64ccc3b 100644 --- a/js/components/edition.js +++ b/js/components/edition.js @@ -1,26 +1,21 @@ import React from 'react'; + import ImageViewer from './ascribe_media/image_viewer'; -import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger'; -import OverlayMixin from 'react-bootstrap/lib/OverlayMixin'; -import Modal from 'react-bootstrap/lib/Modal'; -import ModalTrigger from 'react-bootstrap/lib/ModalTrigger'; +import ShareModalButton from './ascribe_modal/modal_share'; /** * This is the component that implements display-specific functionality */ let Edition = React.createClass({ render() { - var modal = ; return (
- {modal}
- - +
@@ -43,6 +38,7 @@ let EditionHeader = React.createClass({ }); let EditionDetails = React.createClass({ + render() { return (
@@ -50,9 +46,11 @@ let EditionDetails = React.createClass({ value={this.props.edition.edition_number + " of " + this.props.edition.num_editions} /> +
); + } }); @@ -73,69 +71,6 @@ let EditionDetailProperty = React.createClass({ } }); -let ShareModal = React.createClass({ - mixins: [OverlayMixin], - getInitialState: function() { - return { - isOpen: true - }; - }, - hide: function(){ - this.setState({isOpen: false}) - }, - renderOverlay: function() { - if (!this.state.isOpen) { - return ; - } - }, - render: function() { - return ( - - - ); - } -}); -//let ShareModal = React.createClass({ -// mixins: [OverlayMixin], -// -// getInitialState: function() { -// return { -// isModalOpen: true -// }; -// }, -// renderOverlay: function() { -// if (!this.state.isModalOpen) { -// return ; -// } -// }, -// hide: function(){ -// this.setState({isModalOpen: false}); -// }, -// render: function() { -// var content = "Hi,\n\nI am sharing \"" + this.props.edition.title + -// "\" with you.\n\nTruly yours,\n"; -// return ( -// -//
-//
-//
-// -//
-//
-// -//
-//
-// -// -//
-//
-//
-//
-// ); -// } -//}); +export default Edition; -export default Edition; \ No newline at end of file diff --git a/js/components/edition_container.js b/js/components/edition_container.js index 83a8579b..77d28962 100644 --- a/js/components/edition_container.js +++ b/js/components/edition_container.js @@ -2,6 +2,8 @@ import React from 'react'; import EditionActions from '../actions/edition_actions'; import EditionStore from '../stores/edition_store'; +import UserActions from '../actions/user_actions'; +import UserStore from '../stores/user_store'; import Edition from './edition'; @@ -11,7 +13,8 @@ import Edition from './edition'; let EditionContainer = React.createClass({ getInitialState() { - return EditionStore.getState(); + return {'user': UserStore.getState(), + 'edition': EditionStore.getState()} }, onChange(state) { @@ -21,17 +24,20 @@ let EditionContainer = React.createClass({ componentDidMount() { EditionActions.fetchOne(this.props.params.editionId); EditionStore.listen(this.onChange); + UserActions.fetchCurrentUser(); + UserStore.listen(this.onChange); }, componentDidUnmount() { EditionStore.unlisten(this.onChange); + UserStore.unlisten(this.onChange); }, render() { if('title' in this.state.edition) { return ( - + ); } else { return ( From 58e284cbdf03c6ce125319cce2b97dbfd504b73c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Wed, 27 May 2015 09:56:26 +0200 Subject: [PATCH 17/28] refactor edition-button --- css/main.css | 13 ++++++------- .../ascribe_table/table_item_selectable.js | 5 +++-- js/components/ascribe_table/table_item_subtable.js | 8 +++++--- .../ascribe_table/table_item_subtable_button.js | 2 +- 4 files changed, 15 insertions(+), 13 deletions(-) diff --git a/css/main.css b/css/main.css index de85b7fc..9188fe42 100644 --- a/css/main.css +++ b/css/main.css @@ -16,7 +16,7 @@ .ascribe-table-header-column { display: table; - height:4em; + height:3em; } .ascribe-table-header-column > span { @@ -44,7 +44,7 @@ display: table; font-family: 'Source Sans Pro'; font-size: 1.2em; - height:4em; + height:3em; } .ascribe-table-item-column > * { @@ -52,11 +52,10 @@ vertical-align: middle; } -.btn-ascribe, .btn-ascribe:hover, .btn-ascribe:active, .btn-ascribe:focus { - background-color: rgba(2, 182, 163, 0.5); - border-color: rgba(2, 182, 163, 0.5); -} - .ascribe-table-item-selected { background-color: rgba(2, 182, 163, 0.5); +} + +.ascribe-table-item-selectable { + cursor: default; } \ No newline at end of file diff --git a/js/components/ascribe_table/table_item_selectable.js b/js/components/ascribe_table/table_item_selectable.js index bc508a7c..d62f8d04 100644 --- a/js/components/ascribe_table/table_item_selectable.js +++ b/js/components/ascribe_table/table_item_selectable.js @@ -11,7 +11,8 @@ let TableItemSelectable = React.createClass({ propTypes: { columnList: React.PropTypes.arrayOf(React.PropTypes.instanceOf(TableColumnContentModel)), columnContent: React.PropTypes.object, - parentId: React.PropTypes.number + parentId: React.PropTypes.number, + className: React.PropTypes.string }, selectItem() { @@ -25,7 +26,7 @@ let TableItemSelectable = React.createClass({ return ( diff --git a/js/components/ascribe_table/table_item_subtable.js b/js/components/ascribe_table/table_item_subtable.js index 00c456ce..9db1930c 100644 --- a/js/components/ascribe_table/table_item_subtable.js +++ b/js/components/ascribe_table/table_item_subtable.js @@ -74,6 +74,7 @@ let TableItemSubtable = React.createClass({ {this.state.editionList[this.props.columnContent.id].map((edition, i) => { return ( @@ -93,9 +94,10 @@ let TableItemSubtable = React.createClass({ -
- + columnWidth={12}> + +
+
diff --git a/js/components/ascribe_table/table_item_subtable_button.js b/js/components/ascribe_table/table_item_subtable_button.js index 7638dc13..8c5431d8 100644 --- a/js/components/ascribe_table/table_item_subtable_button.js +++ b/js/components/ascribe_table/table_item_subtable_button.js @@ -10,7 +10,7 @@ let TableItemSubtableButton = React.createClass({ render() { return ( - From f85d4fd1067043eab0f001d5548c270800a0c57d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Wed, 27 May 2015 13:57:11 +0200 Subject: [PATCH 18/28] implement intersection logic for acls --- css/main.css | 11 +++ .../piece_list_toolbar.js | 81 +++++++++++++++++++ js/components/piece_list.js | 5 +- 3 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 js/components/ascribe_piece_list_toolbar/piece_list_toolbar.js diff --git a/css/main.css b/css/main.css index 9188fe42..d76c9773 100644 --- a/css/main.css +++ b/css/main.css @@ -12,11 +12,13 @@ .ascribe-table-header-row { border-bottom: 2px solid rgba(2, 182, 163, 0.5); border-top: 2px solid rgba(2, 182, 163, 0.5); + padding: 0; } .ascribe-table-header-column { display: table; height:3em; + padding: 0; } .ascribe-table-header-column > span { @@ -58,4 +60,13 @@ .ascribe-table-item-selectable { cursor: default; +} + +.piece-list-toolbar { + height:3em; +} + +.no-margin { + margin-right: 0; + margin-left: 0; } \ No newline at end of file diff --git a/js/components/ascribe_piece_list_toolbar/piece_list_toolbar.js b/js/components/ascribe_piece_list_toolbar/piece_list_toolbar.js new file mode 100644 index 00000000..a45e7b9d --- /dev/null +++ b/js/components/ascribe_piece_list_toolbar/piece_list_toolbar.js @@ -0,0 +1,81 @@ +import React from 'react'; + +import EditionListStore from '../../stores/edition_list_store'; + +let PieceListToolbar = React.createClass({ + getInitialState() { + return EditionListStore.getState(); + }, + + onChange(state) { + this.setState(state); + }, + + componentDidMount() { + EditionListStore.listen(this.onChange) + }, + + componentDidUnmount() { + EditionListStore.unlisten(this.onChange) + }, + + filterForSelected(edition) { + return edition.selected; + }, + + fetchSelectedEditionList() { + let selectedEditionList = []; + + Object + .keys(this.state.editionList) + .forEach((key) => { + let filteredEditionsForPiece = this.state.editionList[key] + .filter(this.filterForSelected); + selectedEditionList = selectedEditionList.concat(filteredEditionsForPiece); + }); + + return selectedEditionList; + }, + + intersectAcls(a, b) { + //console.log(a, b); + return a.filter((val) => b.indexOf(val) > -1); + }, + + getAvailableAcls() { + let availableAcls = []; + let selectedEditionList = this.fetchSelectedEditionList(); + + // If no edition has been selected, availableActions is empty + // If only one edition has been selected, their actions are available + if(selectedEditionList.length >= 1) { + availableAcls = selectedEditionList[0].acl; + } + if(selectedEditionList.length >= 2) { + for(let i = 1; i < selectedEditionList.length; i++) { + availableAcls = this.intersectAcls(availableAcls, selectedEditionList[i].acl); + } + } + + return availableAcls; + }, + + render() { + this.getAvailableAcls(); + + return ( +
+
+
+ + + + +
+
+
+ ); + } +}); + +export default PieceListToolbar; \ No newline at end of file diff --git a/js/components/piece_list.js b/js/components/piece_list.js index 13927164..f9ffddc3 100644 --- a/js/components/piece_list.js +++ b/js/components/piece_list.js @@ -13,7 +13,9 @@ import TableItemSubtableButton from './ascribe_table/table_item_subtable_button' import TableColumnContentModel from '../models/table_column_content_model'; -import Pagination from './ascribe_pagination/pagination' +import Pagination from './ascribe_pagination/pagination'; + +import PieceListToolbar from './ascribe_piece_list_toolbar/piece_list_toolbar'; let PieceList = React.createClass({ @@ -62,6 +64,7 @@ let PieceList = React.createClass({ if(this.state.pieceList && this.state.pieceList.length > 0) { return (
+ Date: Wed, 27 May 2015 14:35:33 +0200 Subject: [PATCH 19/28] add acl buttons for selection --- js/components/acl_button.js | 32 +++++++++++++++++++ .../piece_list_toolbar.js | 17 +++++----- js/constants/application_constants.js | 3 +- 3 files changed, 43 insertions(+), 9 deletions(-) create mode 100644 js/components/acl_button.js diff --git a/js/components/acl_button.js b/js/components/acl_button.js new file mode 100644 index 00000000..9d52a09a --- /dev/null +++ b/js/components/acl_button.js @@ -0,0 +1,32 @@ +import React from 'react'; + +import AppConstants from '../constants/application_constants'; + +let AclButton = React.createClass({ + propTypes: { + action: React.PropTypes.oneOf(AppConstants.aclList).isRequired, + availableAcls: React.PropTypes.array.isRequired + }, + + render() { + let shouldDisplay = this.props.availableAcls.indexOf(this.props.action) > -1; + let styles = {}; + + if(shouldDisplay) { + styles.display = 'inline-block'; + } else { + styles.display = 'none'; + } + + return ( + + ); + } +}); + +export default AclButton; \ No newline at end of file diff --git a/js/components/ascribe_piece_list_toolbar/piece_list_toolbar.js b/js/components/ascribe_piece_list_toolbar/piece_list_toolbar.js index a45e7b9d..1ce4d744 100644 --- a/js/components/ascribe_piece_list_toolbar/piece_list_toolbar.js +++ b/js/components/ascribe_piece_list_toolbar/piece_list_toolbar.js @@ -2,6 +2,8 @@ import React from 'react'; import EditionListStore from '../../stores/edition_list_store'; +import AclButton from '../acl_button'; + let PieceListToolbar = React.createClass({ getInitialState() { return EditionListStore.getState(); @@ -29,8 +31,7 @@ let PieceListToolbar = React.createClass({ Object .keys(this.state.editionList) .forEach((key) => { - let filteredEditionsForPiece = this.state.editionList[key] - .filter(this.filterForSelected); + let filteredEditionsForPiece = this.state.editionList[key].filter(this.filterForSelected); selectedEditionList = selectedEditionList.concat(filteredEditionsForPiece); }); @@ -38,7 +39,6 @@ let PieceListToolbar = React.createClass({ }, intersectAcls(a, b) { - //console.log(a, b); return a.filter((val) => b.indexOf(val) > -1); }, @@ -48,6 +48,7 @@ let PieceListToolbar = React.createClass({ // If no edition has been selected, availableActions is empty // If only one edition has been selected, their actions are available + // If more than one editions have been selected, their acl properties are intersected if(selectedEditionList.length >= 1) { availableAcls = selectedEditionList[0].acl; } @@ -61,16 +62,16 @@ let PieceListToolbar = React.createClass({ }, render() { - this.getAvailableAcls(); + let availableAcls = this.getAvailableAcls(); return (
- - - - + + + +
diff --git a/js/constants/application_constants.js b/js/constants/application_constants.js index 8efb7196..7d706d8c 100644 --- a/js/constants/application_constants.js +++ b/js/constants/application_constants.js @@ -1,6 +1,7 @@ let constants = { 'baseUrl': 'http://staging.ascribe.io/api/', - 'debugCredentialBase64': 'ZGltaUBtYWlsaW5hdG9yLmNvbTowMDAwMDAwMDAw' // dimi@mailinator:0000000000 + 'debugCredentialBase64': 'ZGltaUBtYWlsaW5hdG9yLmNvbTowMDAwMDAwMDAw', // dimi@mailinator:0000000000 + 'aclList': ['edit', 'consign', 'transfer', 'loan', 'share', 'download', 'view', 'delete', 'del_from_collection', 'add_to_collection'] }; export default constants; \ No newline at end of file From 76317dcdcae2f1469822f1a71f8e1ce704f52ec7 Mon Sep 17 00:00:00 2001 From: ddejongh Date: Wed, 27 May 2015 15:53:26 +0200 Subject: [PATCH 20/28] modal + forms --- js/components/ascribe_modal/modal_share.js | 77 +++++++++++++++++----- js/components/edition.js | 1 + 2 files changed, 61 insertions(+), 17 deletions(-) diff --git a/js/components/ascribe_modal/modal_share.js b/js/components/ascribe_modal/modal_share.js index ca148fa2..235e4ad5 100644 --- a/js/components/ascribe_modal/modal_share.js +++ b/js/components/ascribe_modal/modal_share.js @@ -1,3 +1,8 @@ +import fetch from 'isomorphic-fetch'; + +import AppConstants from '../../constants/application_constants'; +import FetchApiUtils from '../../utils/fetch_api_utils'; + import React from 'react'; import Modal from 'react-bootstrap/lib/Modal'; import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger'; @@ -22,28 +27,66 @@ let ShareModalButton = React.createClass({ let ShareModal = React.createClass({ render() { - var content = "Hi,\n\nI am sharing \"" + this.props.edition.title + - "\" with you.\n\nTruly yours,\n" + this.props.currentUser.username; return (
-
-
- -
-
- -
-
- - -
- +
+ ) + } +}); + +let ShareForm = React.createClass({ + submit(e) { + e.preventDefault(); + let url = "http://localhost:8000/api/ownership/shares/mail/"; + fetch(url, { + method: 'post', + headers: { + 'Authorization': 'Basic ' + AppConstants.debugCredentialBase64, + 'Accept': 'application/json', + 'Content-Type': 'application/json' + }, + body: JSON.stringify(this.getFormData()) + }) + }, + getFormData() { + return { + bitcoin_id: this.props.edition.bitcoin_id, + share_emails: this.refs.share_emails.getDOMNode().value, + share_message: this.refs.share_message.getDOMNode().value + } + }, + renderTextInput(id, placeHolder, required){ + return( +
+ +
+ ) + }, + renderTextArea(id, placeHolder, required){ + return( +
+ +
+ ) + }, + render() { + let content = "Hi,\n\nI am sharing \"" + this.props.edition.title + + "\" with you.\n\nTruly yours,\n" + this.props.currentUser.username; + return ( +
+ {this.renderTextInput("share_emails", "Comma separated emails", "required")} + {this.renderTextArea("share_message", content, "")} +
+ + +
+ ); } }); diff --git a/js/components/edition.js b/js/components/edition.js index b64ccc3b..3c4827cf 100644 --- a/js/components/edition.js +++ b/js/components/edition.js @@ -46,6 +46,7 @@ let EditionDetails = React.createClass({ value={this.props.edition.edition_number + " of " + this.props.edition.num_editions} /> +

From 3c3504d773397279c1b60c34fe54e35f9f1470de Mon Sep 17 00:00:00 2001 From: ddejongh Date: Wed, 27 May 2015 17:33:15 +0200 Subject: [PATCH 21/28] modal error --- js/components/ascribe_modal/modal_share.js | 11 +++++++++++ js/components/edition.js | 1 - js/utils/fetch_api_utils.js | 7 +++++++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/js/components/ascribe_modal/modal_share.js b/js/components/ascribe_modal/modal_share.js index 235e4ad5..710ad820 100644 --- a/js/components/ascribe_modal/modal_share.js +++ b/js/components/ascribe_modal/modal_share.js @@ -39,6 +39,9 @@ let ShareModal = React.createClass({ }); let ShareForm = React.createClass({ + getInitialState(){ + return {errors: []} + }, submit(e) { e.preventDefault(); let url = "http://localhost:8000/api/ownership/shares/mail/"; @@ -51,6 +54,14 @@ let ShareForm = React.createClass({ }, body: JSON.stringify(this.getFormData()) }) + .then((response) => response.json()) + .catch(function(error) { + this.setState({errors: error}); + console.log('request failed', error); + }.bind(this)); + + //.then(FetchApiUtils.status) + }, getFormData() { return { diff --git a/js/components/edition.js b/js/components/edition.js index 3c4827cf..938293e8 100644 --- a/js/components/edition.js +++ b/js/components/edition.js @@ -38,7 +38,6 @@ let EditionHeader = React.createClass({ }); let EditionDetails = React.createClass({ - render() { return (
diff --git a/js/utils/fetch_api_utils.js b/js/utils/fetch_api_utils.js index e8395490..47b52e66 100644 --- a/js/utils/fetch_api_utils.js +++ b/js/utils/fetch_api_utils.js @@ -54,6 +54,13 @@ let FetchApiUtils = { } return interpolation + orderBy; + }, + + status(response) { + if (response.status >= 200 && response.status < 300) { + return response + } + throw new Error(response.json()) } }; From 97abafda0d9d482920f6afb44d7edd5472251599 Mon Sep 17 00:00:00 2001 From: vrde Date: Wed, 27 May 2015 17:55:09 +0200 Subject: [PATCH 22/28] Fix error handling on AJAX request --- js/components/ascribe_modal/modal_share.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/js/components/ascribe_modal/modal_share.js b/js/components/ascribe_modal/modal_share.js index 710ad820..28740a43 100644 --- a/js/components/ascribe_modal/modal_share.js +++ b/js/components/ascribe_modal/modal_share.js @@ -54,11 +54,16 @@ let ShareForm = React.createClass({ }, body: JSON.stringify(this.getFormData()) }) + .then((response) => { + if (response.status >= 200 && response.status < 300) + return response + throw new Error(response.statusText) + }) .then((response) => response.json()) - .catch(function(error) { + .catch((error) => { this.setState({errors: error}); console.log('request failed', error); - }.bind(this)); + }); //.then(FetchApiUtils.status) @@ -102,4 +107,4 @@ let ShareForm = React.createClass({ } }); -export default ShareModalButton; \ No newline at end of file +export default ShareModalButton; From a8807e8d3c3fce176f4f39d4c28634a3693e3473 Mon Sep 17 00:00:00 2001 From: ddejongh Date: Wed, 27 May 2015 18:54:45 +0200 Subject: [PATCH 23/28] modal error resolves --- js/components/ascribe_modal/modal_share.js | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/js/components/ascribe_modal/modal_share.js b/js/components/ascribe_modal/modal_share.js index 28740a43..33a9d04c 100644 --- a/js/components/ascribe_modal/modal_share.js +++ b/js/components/ascribe_modal/modal_share.js @@ -57,14 +57,9 @@ let ShareForm = React.createClass({ .then((response) => { if (response.status >= 200 && response.status < 300) return response - throw new Error(response.statusText) - }) - .then((response) => response.json()) - .catch((error) => { - this.setState({errors: error}); - console.log('request failed', error); - }); - + response.json().then((response) => this.setState({errors: response.errors})) + } + ); //.then(FetchApiUtils.status) }, From d4a98ce7c4d3e01fae5f422d2ef4f2895350e45b Mon Sep 17 00:00:00 2001 From: ddejongh Date: Thu, 28 May 2015 10:16:58 +0200 Subject: [PATCH 24/28] modal error resolves --- js/components/ascribe_modal/modal_share.js | 71 ++++++++++++++++++---- 1 file changed, 58 insertions(+), 13 deletions(-) diff --git a/js/components/ascribe_modal/modal_share.js b/js/components/ascribe_modal/modal_share.js index 33a9d04c..a3a4141d 100644 --- a/js/components/ascribe_modal/modal_share.js +++ b/js/components/ascribe_modal/modal_share.js @@ -8,6 +8,7 @@ import Modal from 'react-bootstrap/lib/Modal'; import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger'; import ModalTrigger from 'react-bootstrap/lib/ModalTrigger'; import Tooltip from 'react-bootstrap/lib/Tooltip'; +import Alert from 'react-bootstrap/lib/Alert'; let ShareModalButton = React.createClass({ @@ -15,7 +16,7 @@ let ShareModalButton = React.createClass({ return ( Share the artwork}> }> + currentUser={this.props.currentUser}/>}>
@@ -26,12 +27,17 @@ let ShareModalButton = React.createClass({ }); let ShareModal = React.createClass({ + onRequestHide(e){ + e.preventDefault(); + this.props.onRequestHide(); + }, render() { return (
+ currentUser={this.props.currentUser} + onRequestHide={this.onRequestHide}/>
) @@ -39,8 +45,8 @@ let ShareModal = React.createClass({ }); let ShareForm = React.createClass({ - getInitialState(){ - return {errors: []} + getInitialState() { + return {errors: null} }, submit(e) { e.preventDefault(); @@ -54,10 +60,10 @@ let ShareForm = React.createClass({ }, body: JSON.stringify(this.getFormData()) }) - .then((response) => { - if (response.status >= 200 && response.status < 300) - return response - response.json().then((response) => this.setState({errors: response.errors})) + .then((response) => { + if (response.status >= 200 && response.status < 300) + return response + response.json().then((response) => this.setState({errors: response.errors})) } ); //.then(FetchApiUtils.status) @@ -70,17 +76,33 @@ let ShareForm = React.createClass({ share_message: this.refs.share_message.getDOMNode().value } }, - renderTextInput(id, placeHolder, required){ - return( + renderAlert(id){ + if (this.state.errors && id in this.state.errors) { + return this.state.errors[id].map(function(error) { + return + } + ) + } + return + }, + renderTextInput(id, placeHolder, required) { + + return (
+ {this.renderAlert(id)}
) }, - renderTextArea(id, placeHolder, required){ - return( + renderTextArea(id, placeHolder, required) { + let alert = ""; + if (this.state.errors && id in this.state.errors) { + alert = + } + return (
+ {alert}
@@ -88,7 +110,7 @@ let ShareForm = React.createClass({ }, render() { let content = "Hi,\n\nI am sharing \"" + this.props.edition.title + - "\" with you.\n\nTruly yours,\n" + this.props.currentUser.username; + "\" with you.\n\nTruly yours,\n" + this.props.currentUser.username; return (
{this.renderTextInput("share_emails", "Comma separated emails", "required")} @@ -102,4 +124,27 @@ let ShareForm = React.createClass({ } }); +const AlertDismissable = React.createClass({ + getInitialState() { + return { + alertVisible: true + }; + }, + render() { + if (this.state.alertVisible) { + return ( + + {this.props.error} + + ); + } + return ( + + ); + }, + handleAlertDismiss() { + this.setState({alertVisible: false}); + } +}); + export default ShareModalButton; From 0a4dae850b962588702255af8f928918d1c5063f Mon Sep 17 00:00:00 2001 From: ddejongh Date: Thu, 28 May 2015 18:18:13 +0200 Subject: [PATCH 25/28] solved error + reusability refactor --- .../ascribe_forms/form_share_email.js | 57 +++++++++ js/components/ascribe_modal/modal_share.js | 117 +----------------- js/mixins/form_alert_mixin.js | 75 +++++++++++ 3 files changed, 138 insertions(+), 111 deletions(-) create mode 100644 js/components/ascribe_forms/form_share_email.js create mode 100644 js/mixins/form_alert_mixin.js diff --git a/js/components/ascribe_forms/form_share_email.js b/js/components/ascribe_forms/form_share_email.js new file mode 100644 index 00000000..d78c02ec --- /dev/null +++ b/js/components/ascribe_forms/form_share_email.js @@ -0,0 +1,57 @@ +import fetch from 'isomorphic-fetch'; + +import React from 'react'; + +import AppConstants from '../../constants/application_constants'; +import FetchApiUtils from '../../utils/fetch_api_utils'; +import FormMixin from '../../mixins/form_alert_mixin'; + +let ShareForm = React.createClass({ + mixins: [FormMixin], + + submit(e) { + e.preventDefault(); + fetch(AppConstants.baseUrl + 'ownership/shares/mail/', { + method: 'post', + headers: { + 'Authorization': 'Basic ' + AppConstants.debugCredentialBase64, + 'Accept': 'application/json', + 'Content-Type': 'application/json' + }, + body: JSON.stringify(this.getFormData()) + }) + .then( + (response) => this.handleResponse(response) + ); + }, + getFormData() { + return { + bitcoin_id: this.props.edition.bitcoin_id, + share_emails: this.refs.share_emails.getDOMNode().value, + share_message: this.refs.share_message.getDOMNode().value + } + }, + renderMessage() { + return "" + + "Hi,\n" + + "\n" + + "I am sharing \"" + this.props.edition.title + "\" with you.\n" + + "\n" + + "Truly yours,\n" + + this.props.currentUser.username; + }, + render() { + return ( + + {this.renderTextInput("share_emails", "email", "Comma separated emails", "required")} + {this.renderTextArea("share_message", this.renderMessage(), "")} +
+ + +
+ + ); + } +}); + +export default ShareForm; \ No newline at end of file diff --git a/js/components/ascribe_modal/modal_share.js b/js/components/ascribe_modal/modal_share.js index a3a4141d..4cc05d5a 100644 --- a/js/components/ascribe_modal/modal_share.js +++ b/js/components/ascribe_modal/modal_share.js @@ -1,22 +1,19 @@ -import fetch from 'isomorphic-fetch'; - -import AppConstants from '../../constants/application_constants'; -import FetchApiUtils from '../../utils/fetch_api_utils'; - import React from 'react'; import Modal from 'react-bootstrap/lib/Modal'; import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger'; import ModalTrigger from 'react-bootstrap/lib/ModalTrigger'; import Tooltip from 'react-bootstrap/lib/Tooltip'; -import Alert from 'react-bootstrap/lib/Alert'; + +import ShareForm from '../ascribe_forms/form_share_email' + let ShareModalButton = React.createClass({ render() { return ( Share the artwork}> }> + currentUser={this.props.currentUser}/>}>
@@ -36,115 +33,13 @@ let ShareModal = React.createClass({
+ currentUser={this.props.currentUser} + onRequestHide={this.onRequestHide}/>
) } }); -let ShareForm = React.createClass({ - getInitialState() { - return {errors: null} - }, - submit(e) { - e.preventDefault(); - let url = "http://localhost:8000/api/ownership/shares/mail/"; - fetch(url, { - method: 'post', - headers: { - 'Authorization': 'Basic ' + AppConstants.debugCredentialBase64, - 'Accept': 'application/json', - 'Content-Type': 'application/json' - }, - body: JSON.stringify(this.getFormData()) - }) - .then((response) => { - if (response.status >= 200 && response.status < 300) - return response - response.json().then((response) => this.setState({errors: response.errors})) - } - ); - //.then(FetchApiUtils.status) - - }, - getFormData() { - return { - bitcoin_id: this.props.edition.bitcoin_id, - share_emails: this.refs.share_emails.getDOMNode().value, - share_message: this.refs.share_message.getDOMNode().value - } - }, - renderAlert(id){ - if (this.state.errors && id in this.state.errors) { - return this.state.errors[id].map(function(error) { - return - } - ) - } - return - }, - renderTextInput(id, placeHolder, required) { - - return ( -
- {this.renderAlert(id)} - -
- ) - }, - renderTextArea(id, placeHolder, required) { - let alert = ""; - if (this.state.errors && id in this.state.errors) { - alert = - } - return ( -
- {alert} - -
- ) - }, - render() { - let content = "Hi,\n\nI am sharing \"" + this.props.edition.title + - "\" with you.\n\nTruly yours,\n" + this.props.currentUser.username; - return ( -
- {this.renderTextInput("share_emails", "Comma separated emails", "required")} - {this.renderTextArea("share_message", content, "")} -
- - -
- - ); - } -}); - -const AlertDismissable = React.createClass({ - getInitialState() { - return { - alertVisible: true - }; - }, - render() { - if (this.state.alertVisible) { - return ( - - {this.props.error} - - ); - } - return ( - - ); - }, - handleAlertDismiss() { - this.setState({alertVisible: false}); - } -}); export default ShareModalButton; diff --git a/js/mixins/form_alert_mixin.js b/js/mixins/form_alert_mixin.js new file mode 100644 index 00000000..ff9a5d52 --- /dev/null +++ b/js/mixins/form_alert_mixin.js @@ -0,0 +1,75 @@ +import React from 'react'; +import Alert from 'react-bootstrap/lib/Alert'; + +let FormMixin = { + getInitialState() { + return {errors: null, + retry: 0 // used for unique keying + } + }, + handleResponse(response){ + if (response.status >= 200 && response.status < 300) + return response; + this.handleError(response); + }, + handleError(response){ + response.json().then((response) => this.setState({errors: response.errors, + retry: this.state.retry + 1})) + }, + renderAlert(id){ + if (this.state.errors && id in this.state.errors) { + return this.state.errors[id].map(function(error) { + let key = error + this.state.retry; + return ; + }.bind(this) + ) + } + return + }, + renderTextInput(id, type, placeHolder, required) { + return ( +
+ {this.renderAlert(id)} + +
+ ) + }, + renderTextArea(id, placeHolder, required) { + return ( +
+ {this.renderAlert(id)} + +
+ ) + } +}; + +let AlertDismissable = React.createClass({ + getInitialState() { + return { + alertVisible: true + }; + }, + show() { + this.setState({alertVisible: true}); + }, + hide() { + this.setState({alertVisible: false}); + }, + render() { + if (this.state.alertVisible) { + return ( + + {this.props.error} + + ); + } + return ( + + ); + } +}); + +export default FormMixin; \ No newline at end of file From c3ea9aecbe0b22005b3b7e7550ced45c436d9b4d Mon Sep 17 00:00:00 2001 From: ddejongh Date: Fri, 29 May 2015 01:54:56 +0200 Subject: [PATCH 26/28] form framework - inputtext, area, btn - alertmixin - formmixin - 500 - transfer/share --- js/components/ascribe_forms/alert.js | 31 ++++++++ .../ascribe_forms/button_submit_close.js | 21 ++++++ .../ascribe_forms/form_share_email.js | 68 ++++++++--------- js/components/ascribe_forms/form_transfer.js | 68 +++++++++++++++++ js/components/ascribe_forms/input_text.js | 35 +++++++++ js/components/ascribe_forms/input_textarea.js | 35 +++++++++ js/components/ascribe_modal/modal_share.js | 5 +- js/components/ascribe_modal/modal_transfer.js | 45 +++++++++++ js/components/edition.js | 2 + js/constants/api_urls.js | 8 ++ js/constants/application_constants.js | 8 +- js/mixins/alert_mixin.js | 21 ++++++ js/mixins/form_alert_mixin.js | 75 ------------------- js/mixins/form_mixin.js | 67 +++++++++++++++++ 14 files changed, 373 insertions(+), 116 deletions(-) create mode 100644 js/components/ascribe_forms/alert.js create mode 100644 js/components/ascribe_forms/button_submit_close.js create mode 100644 js/components/ascribe_forms/form_transfer.js create mode 100644 js/components/ascribe_forms/input_text.js create mode 100644 js/components/ascribe_forms/input_textarea.js create mode 100644 js/components/ascribe_modal/modal_transfer.js create mode 100644 js/constants/api_urls.js create mode 100644 js/mixins/alert_mixin.js delete mode 100644 js/mixins/form_alert_mixin.js create mode 100644 js/mixins/form_mixin.js diff --git a/js/components/ascribe_forms/alert.js b/js/components/ascribe_forms/alert.js new file mode 100644 index 00000000..72ced310 --- /dev/null +++ b/js/components/ascribe_forms/alert.js @@ -0,0 +1,31 @@ +import React from 'react'; +import Alert from 'react-bootstrap/lib/Alert'; + +let AlertDismissable = React.createClass({ + getInitialState() { + return { + alertVisible: true + }; + }, + show() { + this.setState({alertVisible: true}); + }, + hide() { + this.setState({alertVisible: false}); + }, + render() { + if (this.state.alertVisible) { + let key = this.props.error; + return ( + + {this.props.error} + + ); + } + return ( + + ); + } +}); + +export default AlertDismissable; \ No newline at end of file diff --git a/js/components/ascribe_forms/button_submit_close.js b/js/components/ascribe_forms/button_submit_close.js new file mode 100644 index 00000000..60091f2f --- /dev/null +++ b/js/components/ascribe_forms/button_submit_close.js @@ -0,0 +1,21 @@ +import React from 'react'; + +let ButtonSubmitOrClose = React.createClass({ + render() { + if (this.props.submitted){ + return ( +
+ Loading +
+ ) + } + return ( +
+ + +
+ ) + } +}); + +export default ButtonSubmitOrClose; diff --git a/js/components/ascribe_forms/form_share_email.js b/js/components/ascribe_forms/form_share_email.js index d78c02ec..dd61bc7b 100644 --- a/js/components/ascribe_forms/form_share_email.js +++ b/js/components/ascribe_forms/form_share_email.js @@ -2,53 +2,49 @@ import fetch from 'isomorphic-fetch'; import React from 'react'; -import AppConstants from '../../constants/application_constants'; -import FetchApiUtils from '../../utils/fetch_api_utils'; -import FormMixin from '../../mixins/form_alert_mixin'; +import ApiUrls from '../../constants/api_urls'; +import FormMixin from '../../mixins/form_mixin'; +import InputText from './input_text'; +import InputTextArea from './input_textarea'; +import ButtonSubmitOrClose from './button_submit_close'; let ShareForm = React.createClass({ mixins: [FormMixin], - submit(e) { - e.preventDefault(); - fetch(AppConstants.baseUrl + 'ownership/shares/mail/', { - method: 'post', - headers: { - 'Authorization': 'Basic ' + AppConstants.debugCredentialBase64, - 'Accept': 'application/json', - 'Content-Type': 'application/json' - }, - body: JSON.stringify(this.getFormData()) - }) - .then( - (response) => this.handleResponse(response) - ); + url() { + return ApiUrls.ownership_shares_mail }, getFormData() { return { bitcoin_id: this.props.edition.bitcoin_id, - share_emails: this.refs.share_emails.getDOMNode().value, - share_message: this.refs.share_message.getDOMNode().value + share_emails: this.refs.share_emails.state.value, + share_message: this.refs.share_message.state.value } }, - renderMessage() { - return "" + - "Hi,\n" + - "\n" + - "I am sharing \"" + this.props.edition.title + "\" with you.\n" + - "\n" + - "Truly yours,\n" + - this.props.currentUser.username; - }, - render() { + renderForm() { + let message = "Hi,\n" + + "\n" + + "I am sharing \"" + this.props.edition.title + "\" with you.\n" + + "\n" + + "Truly yours,\n" + + this.props.currentUser.username; return ( -
- {this.renderTextInput("share_emails", "email", "Comma separated emails", "required")} - {this.renderTextArea("share_message", this.renderMessage(), "")} -
- - -
+ + + + ); } diff --git a/js/components/ascribe_forms/form_transfer.js b/js/components/ascribe_forms/form_transfer.js new file mode 100644 index 00000000..28e86db3 --- /dev/null +++ b/js/components/ascribe_forms/form_transfer.js @@ -0,0 +1,68 @@ +import fetch from 'isomorphic-fetch'; + +import React from 'react'; + +import ApiUrls from '../../constants/api_urls'; +import FormMixin from '../../mixins/form_mixin'; +import InputText from './input_text'; +import InputTextArea from './input_textarea'; +import ButtonSubmitOrClose from './button_submit_close'; + + + +let TransferForm = React.createClass({ + mixins: [FormMixin], + + url() { + return ApiUrls.ownership_transfers + }, + getFormData() { + return { + bitcoin_id: this.props.edition.bitcoin_id, + transferee: this.refs.transferee.state.value, + transfer_message: this.refs.transfer_message.state.value, + password: this.refs.password.state.value + } + }, + renderForm() { + let message = "Hi,\n" + + "\n" + + "I transfer ownership of \"" + this.props.edition.title + "\" to you.\n" + + "\n" + + "Truly yours,\n" + + this.props.currentUser.username; + return ( +
+ + + + + +
+ Make sure that display instructions and technology details are correct. + They cannot be edited after the transfer. +
+ + + ); + } +}); + +export default TransferForm; \ No newline at end of file diff --git a/js/components/ascribe_forms/input_text.js b/js/components/ascribe_forms/input_text.js new file mode 100644 index 00000000..a65bcc8f --- /dev/null +++ b/js/components/ascribe_forms/input_text.js @@ -0,0 +1,35 @@ +import React from 'react'; + +import AlertMixin from '../../mixins/alert_mixin' + +let InputText = React.createClass({ + + mixins : [AlertMixin], + + getInitialState() { + return {value: null, + alerts: null, // needed in AlertMixin + retry: 0 // needed in AlertMixin for generating unique alerts + }; + }, + handleChange(event) { + this.setState({value: event.target.value}); + }, + render() { + let className = "form-control input-text-ascribe"; + let alerts = (this.props.submitted) ? null : this.state.alerts; + return ( +
+ {alerts} + +
+ ); + + } +}); + +export default InputText; \ No newline at end of file diff --git a/js/components/ascribe_forms/input_textarea.js b/js/components/ascribe_forms/input_textarea.js new file mode 100644 index 00000000..b5f64b66 --- /dev/null +++ b/js/components/ascribe_forms/input_textarea.js @@ -0,0 +1,35 @@ +import React from 'react'; + +import AlertMixin from '../../mixins/alert_mixin' + +let InputTextArea = React.createClass({ + + mixins : [AlertMixin], + + getInitialState() { + return {value: this.props.defaultValue, + alerts: null, // needed in AlertMixin + retry: 0 // needed in AlertMixin for generating unique alerts + }; + }, + handleChange(event) { + this.setState({value: event.target.value}); + }, + render() { + let className = "form-control input-text-ascribe textarea-ascribe-message"; + + let alerts = (this.props.submitted) ? null : this.state.alerts; + return ( +
+ {alerts} + +
+ ); + + } +}); + +export default InputTextArea; \ No newline at end of file diff --git a/js/components/ascribe_modal/modal_share.js b/js/components/ascribe_modal/modal_share.js index 4cc05d5a..176541ee 100644 --- a/js/components/ascribe_modal/modal_share.js +++ b/js/components/ascribe_modal/modal_share.js @@ -13,7 +13,7 @@ let ShareModalButton = React.createClass({ return ( Share the artwork}> }> + currentUser={this.props.currentUser}/>}>
@@ -25,7 +25,8 @@ let ShareModalButton = React.createClass({ let ShareModal = React.createClass({ onRequestHide(e){ - e.preventDefault(); + if (e) + e.preventDefault(); this.props.onRequestHide(); }, render() { diff --git a/js/components/ascribe_modal/modal_transfer.js b/js/components/ascribe_modal/modal_transfer.js new file mode 100644 index 00000000..b57064ff --- /dev/null +++ b/js/components/ascribe_modal/modal_transfer.js @@ -0,0 +1,45 @@ +import React from 'react'; +import Modal from 'react-bootstrap/lib/Modal'; +import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger'; +import ModalTrigger from 'react-bootstrap/lib/ModalTrigger'; +import Tooltip from 'react-bootstrap/lib/Tooltip'; + +import TransferForm from '../ascribe_forms/form_transfer' + + +let TransferModalButton = React.createClass({ + render() { + return ( + Transfer the ownership of the artwork}> + }> +
+ TRANSFER +
+
+
+ ) + } +}); + +let TransferModal = React.createClass({ + onRequestHide(e){ + e.preventDefault(); + this.props.onRequestHide(); + }, + render() { + return ( + +
+ +
+
+ ) + } +}); + + +export default TransferModalButton; diff --git a/js/components/edition.js b/js/components/edition.js index 938293e8..ffeb9b25 100644 --- a/js/components/edition.js +++ b/js/components/edition.js @@ -1,6 +1,7 @@ import React from 'react'; import ImageViewer from './ascribe_media/image_viewer'; +import TransferModalButton from './ascribe_modal/modal_transfer'; import ShareModalButton from './ascribe_modal/modal_share'; /** @@ -46,6 +47,7 @@ let EditionDetails = React.createClass({
+
diff --git a/js/constants/api_urls.js b/js/constants/api_urls.js new file mode 100644 index 00000000..f0c7f9b6 --- /dev/null +++ b/js/constants/api_urls.js @@ -0,0 +1,8 @@ +import AppConstants from './application_constants'; + +let apiUrls = { + 'ownership_shares_mail' : AppConstants.baseUrl + 'ownership/shares/mail/', + 'ownership_transfers' : AppConstants.baseUrl + 'ownership/transfers/' +}; + +export default apiUrls; \ No newline at end of file diff --git a/js/constants/application_constants.js b/js/constants/application_constants.js index 8efb7196..55b9d5f0 100644 --- a/js/constants/application_constants.js +++ b/js/constants/application_constants.js @@ -1,6 +1,8 @@ let constants = { - 'baseUrl': 'http://staging.ascribe.io/api/', + 'baseUrl': 'http://localhost:8000/api/', + //'baseUrl': 'http://staging.ascribe.io/api/', 'debugCredentialBase64': 'ZGltaUBtYWlsaW5hdG9yLmNvbTowMDAwMDAwMDAw' // dimi@mailinator:0000000000 -}; -export default constants; \ No newline at end of file +}; +export default constants; + diff --git a/js/mixins/alert_mixin.js b/js/mixins/alert_mixin.js new file mode 100644 index 00000000..478c44db --- /dev/null +++ b/js/mixins/alert_mixin.js @@ -0,0 +1,21 @@ +import React from 'react'; +import AlertDismissable from '../components/ascribe_forms/alert'; + +let AlertMixin = { + setAlerts(errors){ + let alerts = errors.map( + function(error) { + let key = error + this.state.retry; + return ; + }.bind(this) + ); + this.setState({alerts: alerts, retry: this.state.retry + 1}); + }, + hideAlerts(){ + for (alert in this.state.alerts){ + alert.hide(); + } + } +}; + +export default AlertMixin; \ No newline at end of file diff --git a/js/mixins/form_alert_mixin.js b/js/mixins/form_alert_mixin.js deleted file mode 100644 index ff9a5d52..00000000 --- a/js/mixins/form_alert_mixin.js +++ /dev/null @@ -1,75 +0,0 @@ -import React from 'react'; -import Alert from 'react-bootstrap/lib/Alert'; - -let FormMixin = { - getInitialState() { - return {errors: null, - retry: 0 // used for unique keying - } - }, - handleResponse(response){ - if (response.status >= 200 && response.status < 300) - return response; - this.handleError(response); - }, - handleError(response){ - response.json().then((response) => this.setState({errors: response.errors, - retry: this.state.retry + 1})) - }, - renderAlert(id){ - if (this.state.errors && id in this.state.errors) { - return this.state.errors[id].map(function(error) { - let key = error + this.state.retry; - return ; - }.bind(this) - ) - } - return - }, - renderTextInput(id, type, placeHolder, required) { - return ( -
- {this.renderAlert(id)} - -
- ) - }, - renderTextArea(id, placeHolder, required) { - return ( -
- {this.renderAlert(id)} - -
- ) - } -}; - -let AlertDismissable = React.createClass({ - getInitialState() { - return { - alertVisible: true - }; - }, - show() { - this.setState({alertVisible: true}); - }, - hide() { - this.setState({alertVisible: false}); - }, - render() { - if (this.state.alertVisible) { - return ( - - {this.props.error} - - ); - } - return ( - - ); - } -}); - -export default FormMixin; \ No newline at end of file diff --git a/js/mixins/form_mixin.js b/js/mixins/form_mixin.js new file mode 100644 index 00000000..6bbf5efa --- /dev/null +++ b/js/mixins/form_mixin.js @@ -0,0 +1,67 @@ +import React from 'react'; + +import AppConstants from '../constants/application_constants' +import AlertDismissable from '../components/ascribe_forms/alert' + +export const FormMixin = { + getInitialState() { + return { + submitted: false + , status: null + } + }, + submit(e) { + e.preventDefault(); + this.setState({submitted: true}); + fetch(this.url(), { + method: 'post', + headers: { + 'Authorization': 'Basic ' + AppConstants.debugCredentialBase64, + 'Accept': 'application/json', + 'Content-Type': 'application/json' + }, + body: JSON.stringify(this.getFormData()) + }) + .then( + (response) => this.handleResponse(response) + ); + }, + handleResponse(response){ + if (response.status >= 200 && response.status < 300){ + this.props.onRequestHide(); + } + else if (response.status >= 400 && response.status < 500) { + this.handleError(response); + } + else { + this.setState({submitted: false, status: response.status}); + } + }, + handleError(response){ + response.json().then((response) => this.dispatchErrors(response.errors)); + + }, + dispatchErrors(errors){ + for (var input in errors){ + if (this.refs && this.refs[input] && this.refs[input].state){ + this.refs[input].setAlerts(errors[input]); + } + } + this.setState({submitted: false}); + }, + render(){ + let alert = null; + if (this.state.status >= 500){ + alert = ; + } + return ( +
+ {alert} + {this.renderForm()} +
+ ) + } +}; + +export default FormMixin; + From 61342a55e8e7e0b23ce43da476ea9c7413f9684b Mon Sep 17 00:00:00 2001 From: ddejongh Date: Fri, 29 May 2015 09:13:00 +0200 Subject: [PATCH 27/28] cleanup --- js/mixins/alert_mixin.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/js/mixins/alert_mixin.js b/js/mixins/alert_mixin.js index 478c44db..efabed0e 100644 --- a/js/mixins/alert_mixin.js +++ b/js/mixins/alert_mixin.js @@ -10,11 +10,6 @@ let AlertMixin = { }.bind(this) ); this.setState({alerts: alerts, retry: this.state.retry + 1}); - }, - hideAlerts(){ - for (alert in this.state.alerts){ - alert.hide(); - } } }; From 8383202cebdc13880d54468de599ad2bb3b2510e Mon Sep 17 00:00:00 2001 From: ddejongh Date: Fri, 29 May 2015 09:20:09 +0200 Subject: [PATCH 28/28] css fix --- css/main.css | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/css/main.css b/css/main.css index a5b50f39..cbd7f7ec 100644 --- a/css/main.css +++ b/css/main.css @@ -55,10 +55,21 @@ } .ascribe-table-item-selected { -/*.btn-ascribe, .btn-ascribe:hover, .btn-ascribe:active, .btn-ascribe:focus {*/ -/*background-color: rgba(2, 182, 163, 0.5);*/ -/*border-color: rgba(2, 182, 163, 0.5);*/ -/*}*/ + background-color: rgba(2, 182, 163, 0.5); +} + +.ascribe-table-item-selectable { + cursor: default; +} + +.piece-list-toolbar { + height:3em; +} + +.no-margin { + margin-right: 0; + margin-left: 0; +} .btn-ascribe, .btn-ascribe-inv { border: 1px solid #444; @@ -112,19 +123,6 @@ background-color: rgba(2, 182, 163, 0.5); } -.ascribe-table-item-selectable { - cursor: default; -} - -.piece-list-toolbar { - height:3em; -} - -.no-margin { - margin-right: 0; - margin-left: 0; -} - .ascribe-detail-header { margin-top: 2em; }