├── favicon.png ├── demo ├── pix │ ├── cube.gif │ ├── todo.gif │ ├── wine.gif │ ├── comics.png │ ├── contact.gif │ ├── flag_fr.gif │ ├── flag_us.gif │ ├── wine │ │ ├── yquem.gif │ │ ├── stjean.gif │ │ ├── wineno.gif │ │ ├── winered.gif │ │ ├── macrostie.gif │ │ ├── montelena.gif │ │ ├── vinecliff.gif │ │ ├── winerose.gif │ │ ├── winespark.gif │ │ ├── winesweet.gif │ │ └── winewhite.gif │ ├── color_wheel.png │ └── comics │ │ ├── alim1.jpg │ │ ├── codemc1.jpeg │ │ ├── incal1.jpeg │ │ ├── lama1.jpeg │ │ ├── quete1.jpeg │ │ ├── regard1.jpeg │ │ ├── ronin.jpeg │ │ ├── saga1.jpeg │ │ ├── surfer.jpeg │ │ ├── carmenmc1.jpeg │ │ ├── garulfo1.jpeg │ │ ├── lanfeust1.jpeg │ │ ├── neffous1.jpeg │ │ ├── pemaling1.jpeg │ │ ├── salammbo1.jpeg │ │ ├── skydoll1.jpeg │ │ ├── fleaudieux1.jpeg │ │ ├── metabaron1.jpeg │ │ ├── androitsheep1.jpeg │ │ ├── shaolin-cowboy.jpeg │ │ ├── imperfect-future.jpeg │ │ └── ghost-in-the-shell.jpeg ├── test.html ├── demo.js ├── index.html └── custom-app.html ├── doc ├── icons │ ├── ft-dec.gif │ ├── ft-doc.gif │ ├── ft-fn.gif │ ├── ft-htm.gif │ ├── ft-img.gif │ ├── ft-int.gif │ ├── ft-lov.gif │ ├── ft-txt.gif │ ├── ft-url.gif │ ├── ft-bool.gif │ ├── ft-color.gif │ ├── ft-date.gif │ ├── ft-datehm.gif │ ├── ft-email.gif │ ├── ft-hidden.png │ ├── ft-json.png │ ├── ft-list.png │ ├── ft-money.gif │ ├── ft-time.gif │ └── ft-txtml.gif ├── screenshots │ ├── one-edit.gif │ ├── one-json.gif │ ├── one-mini.gif │ ├── many-cards.gif │ ├── many-list.gif │ ├── one-browse.gif │ ├── action-export.gif │ ├── action-filter.gif │ ├── many-bubbles.gif │ ├── many-charts.gif │ ├── position-100.gif │ ├── position-50.gif │ ├── toolbar-many.gif │ ├── toolbar-one.gif │ ├── position-panels.gif │ └── position-address.gif ├── index.html └── controller.html ├── dist └── fonts │ └── bootstrap │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.ttf │ ├── glyphicons-halflings-regular.woff │ └── glyphicons-halflings-regular.woff2 ├── config.js ├── .gitignore ├── sass ├── print.scss ├── dico.scss ├── many-charts.scss ├── evolutility.scss ├── one-wizard.scss ├── action-import.scss ├── many-cards.scss ├── many-bubbles.scss ├── one-mini.scss ├── variables.scss ├── action-filter.scss ├── action-export.scss ├── demo.scss ├── many.scss ├── doc.scss ├── toolbar.scss ├── dependencies.scss ├── header.scss └── one.scss ├── js ├── view-one │ ├── one-edit.js │ ├── one-mini.js │ ├── one-json.js │ ├── one-browse.js │ └── one-wizard.js ├── dico │ ├── dom-charts.js │ ├── format.js │ ├── app.js │ └── def.js ├── view-many │ ├── many-cards.js │ ├── many-list.js │ ├── many-bubbles.js │ ├── many-charts.js │ └── many-bubbles-d3.js └── i18n │ └── EN.js ├── LICENSE ├── package.json └── models ├── test.data.js ├── todo.data.js ├── todo.js ├── contacts.data.js ├── winecellar.data.js ├── comics.js └── comics.data.js /favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/favicon.png -------------------------------------------------------------------------------- /demo/pix/cube.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/demo/pix/cube.gif -------------------------------------------------------------------------------- /demo/pix/todo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/demo/pix/todo.gif -------------------------------------------------------------------------------- /demo/pix/wine.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/demo/pix/wine.gif -------------------------------------------------------------------------------- /demo/pix/comics.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/demo/pix/comics.png -------------------------------------------------------------------------------- /demo/pix/contact.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/demo/pix/contact.gif -------------------------------------------------------------------------------- /demo/pix/flag_fr.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/demo/pix/flag_fr.gif -------------------------------------------------------------------------------- /demo/pix/flag_us.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/demo/pix/flag_us.gif -------------------------------------------------------------------------------- /doc/icons/ft-dec.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/doc/icons/ft-dec.gif -------------------------------------------------------------------------------- /doc/icons/ft-doc.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/doc/icons/ft-doc.gif -------------------------------------------------------------------------------- /doc/icons/ft-fn.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/doc/icons/ft-fn.gif -------------------------------------------------------------------------------- /doc/icons/ft-htm.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/doc/icons/ft-htm.gif -------------------------------------------------------------------------------- /doc/icons/ft-img.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/doc/icons/ft-img.gif -------------------------------------------------------------------------------- /doc/icons/ft-int.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/doc/icons/ft-int.gif -------------------------------------------------------------------------------- /doc/icons/ft-lov.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/doc/icons/ft-lov.gif -------------------------------------------------------------------------------- /doc/icons/ft-txt.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/doc/icons/ft-txt.gif -------------------------------------------------------------------------------- /doc/icons/ft-url.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/doc/icons/ft-url.gif -------------------------------------------------------------------------------- /demo/pix/wine/yquem.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/demo/pix/wine/yquem.gif -------------------------------------------------------------------------------- /doc/icons/ft-bool.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/doc/icons/ft-bool.gif -------------------------------------------------------------------------------- /doc/icons/ft-color.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/doc/icons/ft-color.gif -------------------------------------------------------------------------------- /doc/icons/ft-date.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/doc/icons/ft-date.gif -------------------------------------------------------------------------------- /doc/icons/ft-datehm.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/doc/icons/ft-datehm.gif -------------------------------------------------------------------------------- /doc/icons/ft-email.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/doc/icons/ft-email.gif -------------------------------------------------------------------------------- /doc/icons/ft-hidden.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/doc/icons/ft-hidden.png -------------------------------------------------------------------------------- /doc/icons/ft-json.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/doc/icons/ft-json.png -------------------------------------------------------------------------------- /doc/icons/ft-list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/doc/icons/ft-list.png -------------------------------------------------------------------------------- /doc/icons/ft-money.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/doc/icons/ft-money.gif -------------------------------------------------------------------------------- /doc/icons/ft-time.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/doc/icons/ft-time.gif -------------------------------------------------------------------------------- /doc/icons/ft-txtml.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/doc/icons/ft-txtml.gif -------------------------------------------------------------------------------- /demo/pix/color_wheel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/demo/pix/color_wheel.png -------------------------------------------------------------------------------- /demo/pix/comics/alim1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/demo/pix/comics/alim1.jpg -------------------------------------------------------------------------------- /demo/pix/wine/stjean.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/demo/pix/wine/stjean.gif -------------------------------------------------------------------------------- /demo/pix/wine/wineno.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/demo/pix/wine/wineno.gif -------------------------------------------------------------------------------- /demo/pix/wine/winered.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/demo/pix/wine/winered.gif -------------------------------------------------------------------------------- /demo/pix/comics/codemc1.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/demo/pix/comics/codemc1.jpeg -------------------------------------------------------------------------------- /demo/pix/comics/incal1.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/demo/pix/comics/incal1.jpeg -------------------------------------------------------------------------------- /demo/pix/comics/lama1.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/demo/pix/comics/lama1.jpeg -------------------------------------------------------------------------------- /demo/pix/comics/quete1.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/demo/pix/comics/quete1.jpeg -------------------------------------------------------------------------------- /demo/pix/comics/regard1.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/demo/pix/comics/regard1.jpeg -------------------------------------------------------------------------------- /demo/pix/comics/ronin.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/demo/pix/comics/ronin.jpeg -------------------------------------------------------------------------------- /demo/pix/comics/saga1.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/demo/pix/comics/saga1.jpeg -------------------------------------------------------------------------------- /demo/pix/comics/surfer.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/demo/pix/comics/surfer.jpeg -------------------------------------------------------------------------------- /demo/pix/wine/macrostie.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/demo/pix/wine/macrostie.gif -------------------------------------------------------------------------------- /demo/pix/wine/montelena.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/demo/pix/wine/montelena.gif -------------------------------------------------------------------------------- /demo/pix/wine/vinecliff.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/demo/pix/wine/vinecliff.gif -------------------------------------------------------------------------------- /demo/pix/wine/winerose.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/demo/pix/wine/winerose.gif -------------------------------------------------------------------------------- /demo/pix/wine/winespark.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/demo/pix/wine/winespark.gif -------------------------------------------------------------------------------- /demo/pix/wine/winesweet.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/demo/pix/wine/winesweet.gif -------------------------------------------------------------------------------- /demo/pix/wine/winewhite.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/demo/pix/wine/winewhite.gif -------------------------------------------------------------------------------- /doc/screenshots/one-edit.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/doc/screenshots/one-edit.gif -------------------------------------------------------------------------------- /doc/screenshots/one-json.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/doc/screenshots/one-json.gif -------------------------------------------------------------------------------- /doc/screenshots/one-mini.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/doc/screenshots/one-mini.gif -------------------------------------------------------------------------------- /demo/pix/comics/carmenmc1.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/demo/pix/comics/carmenmc1.jpeg -------------------------------------------------------------------------------- /demo/pix/comics/garulfo1.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/demo/pix/comics/garulfo1.jpeg -------------------------------------------------------------------------------- /demo/pix/comics/lanfeust1.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/demo/pix/comics/lanfeust1.jpeg -------------------------------------------------------------------------------- /demo/pix/comics/neffous1.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/demo/pix/comics/neffous1.jpeg -------------------------------------------------------------------------------- /demo/pix/comics/pemaling1.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/demo/pix/comics/pemaling1.jpeg -------------------------------------------------------------------------------- /demo/pix/comics/salammbo1.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/demo/pix/comics/salammbo1.jpeg -------------------------------------------------------------------------------- /demo/pix/comics/skydoll1.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/demo/pix/comics/skydoll1.jpeg -------------------------------------------------------------------------------- /doc/screenshots/many-cards.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/doc/screenshots/many-cards.gif -------------------------------------------------------------------------------- /doc/screenshots/many-list.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/doc/screenshots/many-list.gif -------------------------------------------------------------------------------- /doc/screenshots/one-browse.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/doc/screenshots/one-browse.gif -------------------------------------------------------------------------------- /demo/pix/comics/fleaudieux1.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/demo/pix/comics/fleaudieux1.jpeg -------------------------------------------------------------------------------- /demo/pix/comics/metabaron1.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/demo/pix/comics/metabaron1.jpeg -------------------------------------------------------------------------------- /doc/screenshots/action-export.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/doc/screenshots/action-export.gif -------------------------------------------------------------------------------- /doc/screenshots/action-filter.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/doc/screenshots/action-filter.gif -------------------------------------------------------------------------------- /doc/screenshots/many-bubbles.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/doc/screenshots/many-bubbles.gif -------------------------------------------------------------------------------- /doc/screenshots/many-charts.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/doc/screenshots/many-charts.gif -------------------------------------------------------------------------------- /doc/screenshots/position-100.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/doc/screenshots/position-100.gif -------------------------------------------------------------------------------- /doc/screenshots/position-50.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/doc/screenshots/position-50.gif -------------------------------------------------------------------------------- /doc/screenshots/toolbar-many.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/doc/screenshots/toolbar-many.gif -------------------------------------------------------------------------------- /doc/screenshots/toolbar-one.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/doc/screenshots/toolbar-one.gif -------------------------------------------------------------------------------- /demo/pix/comics/androitsheep1.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/demo/pix/comics/androitsheep1.jpeg -------------------------------------------------------------------------------- /demo/pix/comics/shaolin-cowboy.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/demo/pix/comics/shaolin-cowboy.jpeg -------------------------------------------------------------------------------- /doc/screenshots/position-panels.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/doc/screenshots/position-panels.gif -------------------------------------------------------------------------------- /demo/pix/comics/imperfect-future.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/demo/pix/comics/imperfect-future.jpeg -------------------------------------------------------------------------------- /doc/screenshots/position-address.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/doc/screenshots/position-address.gif -------------------------------------------------------------------------------- /demo/pix/comics/ghost-in-the-shell.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/demo/pix/comics/ghost-in-the-shell.jpeg -------------------------------------------------------------------------------- /dist/fonts/bootstrap/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/dist/fonts/bootstrap/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /dist/fonts/bootstrap/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/dist/fonts/bootstrap/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /dist/fonts/bootstrap/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/dist/fonts/bootstrap/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /dist/fonts/bootstrap/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evoluteur/evolutility-ui-jquery/HEAD/dist/fonts/bootstrap/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /config.js: -------------------------------------------------------------------------------- 1 | // default config for Evolutility-UI-jQuery 2 | 3 | var EvoConfig = { 4 | 5 | // --- using localStorage 6 | localStorage: true, 7 | 8 | // --- using evolutility-server-node 9 | //url: 'http://localhost:2000/api/v1/' 10 | 11 | }; 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | bower_components 3 | dist/dependencies.js 4 | *-nogit 5 | *-nogit.* 6 | 7 | demo-*/ 8 | evol-olive/ 9 | demo/demo-data.js 10 | dico/pix/ 11 | 12 | # Windows stuff 13 | Thumbs.db 14 | Desktop.ini 15 | 16 | # Mac stuff 17 | .DS_Store 18 | 19 | # WebStorm stuff 20 | .idea 21 | -------------------------------------------------------------------------------- /sass/print.scss: -------------------------------------------------------------------------------- 1 | 2 | @media print { 3 | 4 | // things to hide 5 | .evol-buttons, 6 | .evo-toolbar, 7 | .evo-noprint{ 8 | display: none !important; 9 | } 10 | 11 | .evo-filters { 12 | border: none; 13 | > .btn { 14 | display: none !important; 15 | } 16 | } 17 | 18 | // things to show 19 | .evo-filters{ 20 | min-height:0; 21 | } 22 | .tab-pane{ 23 | display: block !important; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /sass/dico.scss: -------------------------------------------------------------------------------- 1 | // Evolutility-UI-jQuery :: dico.css 2 | 3 | // https://github.com/evoluteur/evolutility-ui-jquery 4 | // (c) 2017 Olivier Giulieri 5 | 6 | .evodico-field, 7 | .evodico-panel { 8 | z-index: 2000; 9 | //position: absolute; 10 | overflow: auto; 11 | background-color: white; 12 | //box-shadow: 6px 6px 3px #a0a0a0; 13 | //border: #696969 1px solid; 14 | padding:4px; 15 | } 16 | 17 | .evodico-field { 18 | //width:400px; 19 | height:500px; 20 | } 21 | 22 | .evodico-panel { 23 | //width:500px; 24 | height:500px; 25 | } 26 | .panel-title, 27 | label { 28 | > .glyphicon-wrench { 29 | pointer: cursor; 30 | cursor: pointer; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /sass/many-charts.scss: -------------------------------------------------------------------------------- 1 | // Evolutility-UI-jQuery :: many-charts.css 2 | 3 | // https://github.com/evoluteur/evolutility-ui-jquery 4 | // (c) 2017 Olivier Giulieri 5 | 6 | /* --- charts --- */ 7 | .evol-many-charts{ 8 | @include flex-holder(); 9 | } 10 | .evol-chart-holder{ 11 | @include flex-item(); 12 | position: relative; 13 | text-align: center; 14 | background-color :#FFFFFF; 15 | margin:10px 10px 10px 5px; 16 | width: 400px; 17 | min-height:286px; 18 | border-color: $color-border; 19 | } 20 | .chart-holder{ 21 | >label{ 22 | display:block; 23 | } 24 | } 25 | .evol-chart-title{ 26 | text-align:center; 27 | padding:10px 20px 30px; 28 | font-weight: 400; 29 | } 30 | /* 31 | .evo-chart-table{ 32 | overflow-y: auto; 33 | } 34 | */ 35 | -------------------------------------------------------------------------------- /sass/evolutility.scss: -------------------------------------------------------------------------------- 1 | /*! 2 | evolutility-ui-jquery 3 | 4 | https://github.com/evoluteur/evolutility-ui-jquery 5 | */ 6 | 7 | // sass for evolutility-ui-jquery.css 8 | 9 | @import 'sass/variables'; 10 | 11 | //@import 'sass/header'; 12 | //@import 'sass/navbar'; 13 | @import 'sass/toolbar'; 14 | 15 | @import 'sass/one'; 16 | @import 'sass/one-mini'; 17 | //@import 'sass/one-wizard'; 18 | 19 | @import 'sass/many'; 20 | @import 'sass/many-cards'; 21 | @import 'sass/many-bubbles'; 22 | @import 'sass/many-charts'; 23 | 24 | @import 'sass/action-export'; 25 | @import 'sass/action-import'; 26 | @import 'sass/action-filter'; 27 | //@import 'sass/action-doc'; 28 | 29 | @import 'sass/print'; 30 | 31 | //@import 'sass/dico'; 32 | //@import 'sass/doc'; 33 | 34 | //@import 'sass/theme'; 35 | -------------------------------------------------------------------------------- /sass/one-wizard.scss: -------------------------------------------------------------------------------- 1 | 2 | // --- Wizard --- 3 | 4 | .evo-p-wiz{ 5 | display:none; 6 | float:left; 7 | &:first-child, 8 | &:nth-child(2) { 9 | display:block; 10 | } 11 | } 12 | .evo-wiz-bsteps{ 13 | 14 | >li>div{ 15 | display:inline-block; 16 | margin-right:5px; 17 | cursor: pointer; 18 | 19 | >div{ 20 | float:left; 21 | margin-right: 4px; 22 | 23 | &:first-child{ 24 | &.past{ 25 | background-color: black; 26 | } 27 | &.present{ 28 | background-color: grey; 29 | } 30 | &.future{ 31 | background-color: silver; 32 | } 33 | } 34 | } 35 | } 36 | } 37 | .evo-wiz-buttons{ 38 | @include evol-buttons; 39 | >[data-id="finish"]{ 40 | display:none; 41 | } 42 | } 43 | 44 | -------------------------------------------------------------------------------- /sass/action-import.scss: -------------------------------------------------------------------------------- 1 | // Evolutility-UI-jQuery :: action-import.css 2 | 3 | // https://github.com/evoluteur/evolutility-ui-jquery 4 | // (c) 2017 Olivier Giulieri 5 | 6 | $sample-import-height: 160px; 7 | 8 | .evol-import{ 9 | margin-bottom: $xpt-padding; 10 | }/* 11 | .evol-fset>.checkbox>label{ 12 | margin-top: 20px; 13 | }*/ 14 | .evol-ipt-fh{ 15 | transition: all 0.6s ease; 16 | height: 0; 17 | width: 100%; 18 | margin-left: 10px; 19 | overflow-y: hidden; 20 | } 21 | .evol-ipt-format{ 22 | overflow: auto; 23 | height: $sample-import-height; 24 | width: 100%; 25 | padding: $xpt-padding; 26 | } 27 | .evo-ipt{ 28 | margin-top: 20px; 29 | } 30 | .ipt-ssample{ 31 | margin: 5px 10px 0 10px; 32 | } 33 | #iptFormat{ 34 | width:auto; 35 | display: inline; 36 | } 37 | .lbl-block{ 38 | display: block; 39 | } 40 | -------------------------------------------------------------------------------- /sass/many-cards.scss: -------------------------------------------------------------------------------- 1 | // Evolutility-UI-jQuery :: many-cards.css 2 | 3 | // https://github.com/evoluteur/evolutility-ui-jquery 4 | // (c) 2017 Olivier Giulieri 5 | 6 | /* --- cards --- */ 7 | 8 | .evol-cards-body { 9 | > .panel { 10 | float:left; 11 | position: relative; 12 | width:240px; 13 | min-width:140px; 14 | height:182px; 15 | margin: 5px; 16 | padding:2px 10px 10px; 17 | @include b-radius(2px); 18 | overflow: auto; 19 | border-color: $color-border; 20 | 21 | >div { 22 | >h4{ 23 | @include ellipsis; 24 | } 25 | >label{ 26 | vertical-align: top; 27 | /*text-align: right; 28 | min-width:80px;*/ 29 | } 30 | } 31 | } 32 | .evol-c-center{ 33 | text-align: center; 34 | margin: 5px 2px; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /sass/many-bubbles.scss: -------------------------------------------------------------------------------- 1 | // Evolutility-UI-jQuery :: many-bubbles.css 2 | 3 | // https://github.com/evoluteur/evolutility-ui-jquery 4 | // (c) 2017 Olivier Giulieri 5 | 6 | .evol-bubble-tooltip{ 7 | >.panel{ 8 | padding: 0 10px; 9 | } 10 | } 11 | .evol-bubbles-body{ 12 | overflow: hidden; 13 | width:100%; 14 | height:800px; 15 | svg{ 16 | margin-top:10px; 17 | } 18 | } 19 | .bubbles-opts{ 20 | @include panel-top-bar(); 21 | } 22 | // override Bootstrap 23 | .popover-content{ 24 | padding: 4px 10px 10px 10px 25 | } 26 | .a{ 27 | min-height: 50px; 28 | padding: 0 1px 1px 6px; 29 | } 30 | 31 | circle { 32 | stroke: white; 33 | stroke-width: 2px; 34 | opacity: .7; 35 | &:hover{ 36 | stroke: grey; 37 | cursor: pointer; 38 | } 39 | } 40 | 41 | text.label{ 42 | font-size:100%; 43 | text-shadow: 0px 0px 3px #ffffff; 44 | } 45 | -------------------------------------------------------------------------------- /js/view-one/one-edit.js: -------------------------------------------------------------------------------- 1 | /*! *************************************************************************** 2 | * 3 | * evolutility-ui-jquery :: one-edit.js 4 | * 5 | * View "one edit" to edit one backbone model. 6 | * 7 | * https://github.com/evoluteur/evolutility-ui-jquery 8 | * (c) 2017 Olivier Giulieri 9 | * 10 | *************************************************************************** */ 11 | 12 | Evol.ViewOne.Edit = Evol.View_One.extend({ 13 | 14 | viewName: 'edit', 15 | icon: 'edit', // glyphicon-edit 16 | prefix: 'oe', 17 | 18 | postRender:function(){ 19 | var pref = '#' + this.prefix + '-', 20 | fs= _.filter(this.getFields(), function(f){ 21 | return f.type === 'list' && !f.readonly; 22 | }); 23 | _.each(fs, function(f){ 24 | this.$(pref + f.id).select2( 25 | { 26 | data: f.list, 27 | multiple:true 28 | } 29 | ); 30 | }); 31 | } 32 | }); 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Olivier Giulieri 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /sass/one-mini.scss: -------------------------------------------------------------------------------- 1 | // Evolutility-UI-jQuery :: one-mini.css 2 | 3 | // https://github.com/evoluteur/evolutility-ui-jquery 4 | // (c) 2017 Olivier Giulieri 5 | 6 | /* --- mini --- */ 7 | 8 | //.evol-mini-holder{ 9 | // margin: 10px -10px; 10 | //} 11 | .evol-mini-label{ 12 | float:left; 13 | width:25%; 14 | padding-right:10px; 15 | 16 | >div{ 17 | text-align: right; 18 | 19 | @media only screen and (max-width: $screen1) { 20 | text-align: left; 21 | } 22 | 23 | >label{ 24 | margin-top:5px; 25 | } 26 | 27 | } 28 | } 29 | .evol-mini-content{ 30 | float:left; 31 | width:75%; 32 | 33 | > [type="checkbox"]{ 34 | margin-top:10px; 35 | } 36 | 37 | > .help-block{ 38 | min-width:50px; 39 | clear:left; 40 | } 41 | 42 | .img-thumbnail{ 43 | max-height: 150px; 44 | } 45 | 46 | } 47 | .evol-p-mini{ 48 | width:100%; 49 | padding-left: 0 !important; 50 | margin-bottom: 10px; 51 | fieldset{ 52 | padding: 10px 10px 5px 0; 53 | } 54 | } 55 | 56 | @media only screen and (max-width: $screen1) { 57 | .evol-mini-label, 58 | .evol-mini-content, 59 | { 60 | float:none; 61 | width:100%; 62 | } 63 | .evol-mini-content>fieldset{ 64 | width:100%; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "evolutility-ui-jquery", 3 | "description": "Set of model-driven views list, browse, edit, and chart your data (using jQuery, Backbone, and D3.js).", 4 | "version": "1.2.4", 5 | "copyright": "(c) 2021 Olivier Giulieri", 6 | "license": "MIT", 7 | "target": "dist", 8 | "homepage": "http://evoluteur.github.io/evolutility-ui-jquery/", 9 | "author": "Olivier Giulieri (https://evoluteur.github.io/)", 10 | "repository": { 11 | "type": "git", 12 | "url": "git://github.com/evoluteur/evolutility-ui-jquery.git" 13 | }, 14 | "bugs": "https://github.com/evoluteur/evolutility-ui-jquery/issues", 15 | "dependencies": { 16 | "bootstrap-sass": "^3.3.7", 17 | "jquery": "^3.6.0", 18 | "backbone": "^1.4.0", 19 | "backbone.localstorage": "^1.1.6", 20 | "underscore": "^1.13.1", 21 | "papaparse": "^5.3.0", 22 | "d3": "^3.5.17", 23 | "bootstrap": "^3.3.7", 24 | "bootstrap-datepicker": "^1.6.4", 25 | "select2": "^4.0.13", 26 | "toastr": "^2.1.4", 27 | "balloon-css": "^1.2.0" 28 | }, 29 | "devDependencies": { 30 | "grunt": "~1.3.0", 31 | "grunt-contrib-concat": "~1.0.1", 32 | "grunt-contrib-copy": "~1.0.0", 33 | "grunt-contrib-jshint": "~1.1.0", 34 | "grunt-contrib-uglify": "~4.0.1", 35 | "grunt-sass": "^3.1.0", 36 | "node-sass": "^6.0.1" 37 | }, 38 | "keywords": [ 39 | "low-code", 40 | "model", 41 | "metadata", 42 | "UI", 43 | "forms", 44 | "CRUD", 45 | "Backbone", 46 | "MDA", 47 | "javascript", 48 | "forms", 49 | "MVC", 50 | "evolutility" 51 | ] 52 | } 53 | -------------------------------------------------------------------------------- /js/dico/dom-charts.js: -------------------------------------------------------------------------------- 1 | 2 | /*! *************************************************************************** 3 | * 4 | * evolutility-ui-jquery :: dom-charts.js 5 | * 6 | * https://github.com/evoluteur/evolutility-ui-jquery 7 | * (c) 2017 Olivier Giulieri 8 | * 9 | *************************************************************************** */ 10 | 11 | Evol.DOM.Charts = { 12 | 13 | // same as d3.scale.category10() 14 | colors:['1f77b4','ff7f0e','2ca02c','d62728','9467bd','8c564b','e377c2','7f7f7f','bcbd22','17becf'], 15 | 16 | _colorsList: function(nbColors){ 17 | return this.colors.slice(0, nbColors).join(','); 18 | }, 19 | 20 | URL: 'http://chart.apis.google.com/chart', 21 | 22 | _HTML: function(title, urlPix, style){ 23 | return '
'+ 24 | title+'
'; 25 | }, 26 | 27 | Pie: function (label, data, labels, style, sizes){ 28 | var size=sizes?sizes:'390x200'; 29 | var urlGoogleChart = this.URL+'?chd=t:'+data.join(',')+ 30 | '&chco='+this._colorsList(data.length)+ 31 | '&chl='+labels.join('|')+ 32 | '&cht=p&chs='+size; 33 | return this._HTML(label, urlGoogleChart, style || 'panel-default'); 34 | }, 35 | 36 | Bars: function (label, data, labels, style, sizes){ 37 | var size=sizes?sizes:'360x200'; 38 | var maxCount = _.max(data), 39 | urlGoogleChart = this.URL+'?chbh=a&chs='+size+'&cht=bvg&chco='+this._colorsList(data.length)+'&chds=0,'+maxCount+ 40 | '&chd=t:'+data.join('|')+ 41 | '&chp=0.05&chts=676767,10.5&chdl='+labels.join('|'); 42 | return this._HTML(label, urlGoogleChart, style); 43 | } 44 | 45 | }; 46 | -------------------------------------------------------------------------------- /sass/variables.scss: -------------------------------------------------------------------------------- 1 | // Evolutility-UI-jQuery :: variables.css 2 | 3 | // https://github.com/evoluteur/evolutility-ui-jquery 4 | // (c) 2020 Olivier Giulieri 5 | 6 | // base 7 | $color-text: #0d0d0d; 8 | $color-label: grey; 9 | $color-title: #428bca; 10 | $color-cool: #92cddc; 11 | $color-disabled: silver; 12 | 13 | 14 | $color-border: #ddd; 15 | 16 | // responsive design 17 | $screen1: 500px; 18 | $screen2: 900px; 19 | 20 | // golden ratio 21 | $widthR1: 38%; 22 | $widthR2: 62%; 23 | 24 | // top nav bar 25 | $color-navbar: #336699; 26 | $color-header-link: #c6d9f0; 27 | $color-header-link-hover: #ffc107;//#ed991a; 28 | 29 | $color-icon: #31708f; 30 | $color-icon-hover: #428bca; 31 | $color-icon-background-hover: #ECEFF1; 32 | 33 | $toolbar-background-color: #fbfbfb; 34 | $toolbar-border-color: #bce8f1; 35 | 36 | // labels 37 | $weight-label: 500; 38 | 39 | // footer 40 | $color-text-footer: silver; 41 | 42 | // mixins 43 | @mixin ellipsis { 44 | white-space: nowrap; 45 | overflow: hidden; 46 | text-overflow: ellipsis; 47 | } 48 | @mixin b-radius($r:0) { 49 | border-radius: $r; 50 | -moz-border-radius: $r; 51 | -webkit-border-radius: $r; 52 | } 53 | @mixin flex-holder { 54 | display: -webkit-box; /* OLD - iOS 6-, Safari 3.1-6 */ 55 | display: -moz-box; /* OLD - Firefox 19- (buggy but mostly works) */ 56 | display: -ms-flexbox; /* TWEENER - IE 10 */ 57 | display: -webkit-flex; /* NEW - Chrome */ 58 | display: flex; 59 | flex-wrap: wrap; 60 | } 61 | @mixin flex-item { 62 | box-sizing: border-box; 63 | flex-grow: 1; 64 | } 65 | 66 | @mixin panel-top-bar { 67 | width:100%; 68 | padding: 8px; 69 | /*border-bottom: solid 1px $toolbar-border-color;*/ 70 | border-bottom-style: solid; 71 | border-bottom-width: 1px; 72 | background-color: $toolbar-background-color; 73 | > select{ 74 | display: inline-block; 75 | width: auto; 76 | } 77 | >label{ 78 | margin: 2px 10px; 79 | &:first-child{ 80 | margin-left: 0; 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /sass/action-filter.scss: -------------------------------------------------------------------------------- 1 | // Evolutility-UI-jQuery :: action-filter.css 2 | 3 | // https://github.com/evoluteur/evolutility-ui-jquery 4 | // (c) 2020 Olivier Giulieri 5 | 6 | $color-condition: #f0ad4e; 7 | 8 | .evo-bNew, .evo-bAdd, .evo-bDel, .evo-bSubmit { 9 | margin:1px 6px 6px 1px; 10 | } 11 | 12 | .evo-lBold{ 13 | font-weight: bold; 14 | } 15 | 16 | .evo-lLight{ 17 | font-weight: normal; 18 | } 19 | 20 | .evo-zfilters{ 21 | 22 | padding: 6px 0; 23 | 24 | > a { 25 | display: inline-block; 26 | margin: 1px 2px 2px 1px; 27 | padding: 0 5px 3px 10px; 28 | border: silver 1px solid; 29 | border-radius: 15px; 30 | clear: left; 31 | text-decoration: none; 32 | //background-color: $color-condition; 33 | //color: #fff; 34 | /* 35 | &:hover, 36 | &:active{ 37 | //background-color: $color-condition; 38 | //color: #fff; 39 | text-decoration: none; 40 | } 41 | */ 42 | >span.ui-button-text{ 43 | padding: 4px 33px 4px 12px; 44 | } 45 | >button{ 46 | float: none !important; 47 | margin: 2px 2px 0 10px; 48 | } 49 | } 50 | 51 | .glyphicon-remove{ 52 | margin:0 6px; 53 | } 54 | } 55 | 56 | .evo-filters.panel{ 57 | min-height:50px; 58 | padding:0 1px 1px 6px; 59 | 60 | > a { 61 | margin:1px 6px 6px 1px; 62 | } 63 | } 64 | .evo-filters{ 65 | position: relative; 66 | >.close{ 67 | position: absolute; 68 | right: 5px; 69 | top: 5px; 70 | margin-right: 4px; 71 | } 72 | } 73 | 74 | .evo-editFilter{ 75 | vertical-align: middle; 76 | 77 | &:last-child{ 78 | clear:left; 79 | } 80 | 81 | &:after, 82 | > button,>a{ 83 | clear: left; 84 | } 85 | 86 | .as-Txt{ 87 | line-height: 30px; 88 | } 89 | > #value{ 90 | margin-right:5px; 91 | line-height: 30px; 92 | >label{ 93 | margin-left:6px; 94 | margin-right:6px; 95 | >input[type="checkbox"], 96 | >input[type="radio"]{ 97 | margin-right: 10px; 98 | } 99 | } 100 | } 101 | > select, 102 | > input, 103 | > span{ 104 | float: left; 105 | margin:1px 6px 6px 1px; 106 | padding: 3px 5px; 107 | font-size: 1.1em; 108 | width:auto; 109 | } 110 | input[type="number"]#value, 111 | input[type="time"]#value, 112 | input[type="time"]#value2 { 113 | width:6em; 114 | } 115 | 116 | input.hasDatepicker{ 117 | width:7em; 118 | } 119 | 120 | } 121 | -------------------------------------------------------------------------------- /models/test.data.js: -------------------------------------------------------------------------------- 1 | var uiModels = uiModels || {}; 2 | uiModels.test_data = [ 3 | { 4 | "name": "Test 1", 5 | "text1": "hello", 6 | "text3": "world", 7 | "lov1": "Z", 8 | "lov3": "P", 9 | "list1": [ 10 | "E" 11 | ], 12 | "list3": [ 13 | "Y", 14 | "P", 15 | "M" 16 | ], 17 | "lovicon1": "red", 18 | "lovicon3": "white", 19 | "textmultiline1": "html test BOLD", 20 | "textmultiline3": "fdfd", 21 | "html1": "html test BOLD", 22 | "html3": "fdfd", 23 | "date1": "2015-04-16", 24 | "date3": "2015-04-24", 25 | "time1": "00:15", 26 | "time3": "01:45", 27 | "datetime1": "2015-04-16T14:22", 28 | "datetime3": "2015-04-15T15:30", 29 | "integer1": 2, 30 | "integer3": 3, 31 | "decimal1": 2.4, 32 | "decimal3": 3.14, 33 | "money1": 2, 34 | "money3": 9.99, 35 | "boolean1": true, 36 | "boolean3": false, 37 | "email1": "dsds@dffd.com", 38 | "email3": "aaa@bbb.edu", 39 | "url1": "http://google.com", 40 | "url3": "", 41 | "image1": "../pix/todo.gif", 42 | "image3": "", 43 | "color1": "#6aa895", 44 | "color3": "#000000", 45 | "hidden1": "hf1", 46 | "hidden3": "hf2", 47 | "json1": { 48 | "a": 1 49 | }, 50 | "json3": { 51 | "a": 3, 52 | "b": 5 53 | } 54 | }, 55 | { 56 | "name": "Test 2", 57 | "text1": "ggg", 58 | "text3": "", 59 | "lov1": "E", 60 | "lov3": "T", 61 | "list1": [ 62 | "Z", 63 | "T", 64 | "G" 65 | ], 66 | "list3": [ 67 | "h", 68 | "k" 69 | ], 70 | "lovicon1": "red", 71 | "lovicon3": "white", 72 | "textmultiline1": "gg", 73 | "textmultiline3": "", 74 | "html1": "gg", 75 | "html3": "", 76 | "date1": "2015-04-22", 77 | "date3": "2015-04-01", 78 | "time1": "14:22", 79 | "time3": "05:05", 80 | "datetime1": "2015-04-16T02:03", 81 | "datetime3": "2015-04-22T05:06", 82 | "integer1": 555, 83 | "integer3": 3, 84 | "decimal1": 45.45, 85 | "decimal3": 4.12, 86 | "money1": 54.99, 87 | "money3": 100, 88 | "boolean1": false, 89 | "boolean3": false, 90 | "email1": "gfgf@gfgf.com", 91 | "email3": "", 92 | "url1": "http://evolutility.com", 93 | "url3": "", 94 | "image1": "../pix/contact.gif", 95 | "image3": "", 96 | "color1": "#2c84bb", 97 | "color3": "#000000", 98 | "hidden1": "h1", 99 | "hidden3": "h2", 100 | "json1": { 101 | "a": 5 102 | }, 103 | "json3": { 104 | "a": 4 105 | }, 106 | }]; 107 | 108 | if(typeof module === "object" && typeof module.exports === "object"){ 109 | module.exports = uiModels.test_data; 110 | } 111 | -------------------------------------------------------------------------------- /sass/action-export.scss: -------------------------------------------------------------------------------- 1 | // Evolutility-UI-jQuery :: action-export.css 2 | 3 | // https://github.com/evoluteur/evolutility-ui-jquery 4 | // (c) 2017 Olivier Giulieri 5 | 6 | $xpt-padding: 10px; 7 | 8 | .evol-xpt{ 9 | margin-bottom: $xpt-padding; 10 | } 11 | 12 | .evol-xpt-form { 13 | @include flex-holder; 14 | border-collapse:collapse; 15 | border:0; 16 | width:100%; 17 | 18 | > div { 19 | @include flex-item; 20 | padding: $xpt-padding; 21 | vertical-align:top; 22 | } 23 | 24 | } 25 | .evol-xpt-flds { 26 | border-right: 0 !important; 27 | width:$widthR1; 28 | min-width: 200px; 29 | max-width:245px; 30 | 31 | @media only screen and (max-width: $screen1) { 32 | max-width: none; 33 | } 34 | 35 | >fieldset{ 36 | margin: 0 10px 10px 20px; 37 | label{ 38 | display: block; 39 | } 40 | } 41 | 42 | input[type="checkbox"]{ 43 | clear:left; 44 | float:left; 45 | margin-right:.5em; 46 | } 47 | 48 | } 49 | 50 | .evol-xpt-para{ 51 | width:$widthR2; 52 | min-width: 300px; 53 | border-left: 0 !important; 54 | textarea{ 55 | min-height:200px; 56 | } 57 | } 58 | .evol-xpt-format{ 59 | max-width: 270px; 60 | margin-bottom: 10px; 61 | } 62 | .evol-xpt-val{ 63 | display:block; 64 | padding:5px; 65 | min-height:150px; 66 | height: 200px; 67 | margin-top: 6px; 68 | } 69 | .top-btn-xpt{ 70 | float: right; 71 | padding:20px 10px 10px; 72 | 73 | @media only screen and (max-width: 800px) { 74 | display: none; 75 | } 76 | } 77 | .evol-xpt-opts { 78 | min-width: 120px; 79 | width: 220px; 80 | margin: 0 0 14px 30px; 81 | .evol-FLH{ 82 | margin-bottom:10px; 83 | } 84 | input[type="checkbox"]{ 85 | margin-right:.5em; 86 | } 87 | input[type="text"]{ 88 | max-width: 280px; 89 | } 90 | } 91 | 92 | .evol-xpt-format-hld{ 93 | float: left; 94 | &:after{ 95 | clear: both; 96 | } 97 | } 98 | .evol-xptf{ 99 | padding-bottom: 10px; 100 | min-height: 100px; 101 | } 102 | .evol-xpt-more{ 103 | display:block; 104 | margin-top: 10px; 105 | font-size: 14px; 106 | } 107 | .evol-xpt-more-fields{ 108 | clear: both; 109 | display: none; 110 | } 111 | .xpt-header{ 112 | margin-left: 20px; 113 | } 114 | .evo-inline-holder{ 115 | margin-top:10px; 116 | >div{ 117 | display: inline-block; 118 | margin:0 10px 0 0; 119 | } 120 | input[type="checkbox"]{ 121 | margin-top:10px; 122 | } 123 | } 124 | .evol-xpt-db{ 125 | width: auto; 126 | } 127 | .evol-w120{ 128 | max-width:120px; 129 | } 130 | .evol-xpt-cb1{ 131 | margin-top:26px; 132 | } 133 | .evol-xpt-pvl{ 134 | margin-top:15px 135 | } 136 | 137 | -------------------------------------------------------------------------------- /js/view-one/one-mini.js: -------------------------------------------------------------------------------- 1 | /*! *************************************************************************** 2 | * 3 | * evolutility-ui-jquery :: one-mini.js 4 | * 5 | * View "one mini" to "quick edit" one backbone model (only showing important or required fields). 6 | * 7 | * https://github.com/evoluteur/evolutility-ui-jquery 8 | * (c) 2017 Olivier Giulieri 9 | * 10 | *************************************************************************** */ 11 | 12 | Evol.ViewOne.Mini = function(){ 13 | 14 | var dom = Evol.DOM, 15 | fts = Evol.Def.fieldTypes; 16 | 17 | return Evol.ViewOne.Edit.extend({ 18 | 19 | events: { // TODO same as ViewOne ? 20 | 'click > .evol-buttons > button': 'click_button', 21 | 'click .evol-title-toggle': 'click_toggle', 22 | //'click .glyphicon-wrench': 'click_customize', 23 | 'click label > .glyphicon-question-sign': 'click_help' 24 | }, 25 | 26 | viewName: 'mini', 27 | icon: 'th-large', // glyphicon-th-large 28 | prefix: 'om', 29 | 30 | fieldsetFilter: function(f){ 31 | return (f.required || f.inMany || f.inMini);// && f.type!='formula'; 32 | }, 33 | 34 | _render: function (h, mode) { 35 | // TODO browse mode 36 | // in EDIT and BROWSE modes 37 | var miniUIModel= { 38 | id: 'p-mini', 39 | type: 'panel', 40 | class: 'evol-mini-holder', 41 | label: Evol.Format.capitalize(this.uiModel.name), 42 | width: 100, 43 | elements: this.getFields() 44 | }; 45 | 46 | this._renderPanel(h, miniUIModel, mode); 47 | this._renderButtons(h, mode); 48 | }, 49 | 50 | _renderPanel: function (h, p, mode, visible) { 51 | var that = this, 52 | iconsPath = this.iconsPath; 53 | 54 | h.push('
'+ 55 | dom.panelBegin(p, this.style, true)+ 56 | '
':'">')); 57 | _.each(p.elements, function (elem) { 58 | if(elem.type==fts.hidden){ 59 | h.push(dom.input.hidden(that.fieldViewId(elem.id), that.getModelFieldValue(elem.id, elem.defaultValue, mode))); 60 | }else{ 61 | h.push('
'+ 62 | '
'+Evol.Dico.HTMLFieldLabel(elem, mode)+ 63 | '
'); 64 | that.renderField(h, elem, mode, iconsPath, true); 65 | h.push("
"); 66 | } 67 | }); 68 | h.push('
'+ 69 | dom.panelEnd()+ 70 | '
'); 71 | return this; 72 | } 73 | 74 | }); 75 | 76 | }(); 77 | -------------------------------------------------------------------------------- /sass/demo.scss: -------------------------------------------------------------------------------- 1 | 2 | /* evolutility : demo.css */ 3 | 4 | @import "sass/variables"; 5 | @import "sass/header"; 6 | @import 'sass/doc'; 7 | 8 | body{ 9 | font-size: 16px !important; 10 | font-weight: 300; 11 | height:100%; 12 | } 13 | a{ 14 | color: #0099cc; 15 | font-weight: 400; 16 | } 17 | h1,h2,h3,h4{ 18 | color: #2072a7; 19 | } 20 | .demo-links{ 21 | >div { 22 | display: inline-block; 23 | margin: 10px 0 20px 16px; 24 | } 25 | } 26 | .mt20{ 27 | margin-top:20px; 28 | //color:$color-header !important; 29 | } 30 | 31 | .version{ 32 | position: relative; 33 | top: 16px; 34 | left: -36px; 35 | font-weight: normal; 36 | font-size: 0.3em; 37 | } 38 | #evol-views-params{ 39 | margin: 20px 0; 40 | min-height: 100px; 41 | display:block; 42 | select{ 43 | display: inline; 44 | margin: 0 5px; 45 | } 46 | } 47 | @media only screen and (max-width: $screen2) { 48 | #evol-views-params{ 49 | min-height: 40px; 50 | } 51 | .hideIfSmall{ 52 | display: none; 53 | } 54 | } 55 | .demo-controls{ 56 | padding: 10px; 57 | border: 2px solid #FFECB3; 58 | @include b-radius(2px); 59 | background-color: #FFF8E1; 60 | } 61 | #viewInfo{ 62 | margin: 10px 0; 63 | min-height:50px; 64 | } 65 | 66 | .blueBox{ 67 | float:left; 68 | padding:5px 10px; 69 | min-width:200px; 70 | 71 | >ul{ 72 | list-style:none; 73 | >li{ 74 | margin-left: -20px; 75 | } 76 | } 77 | } 78 | .biglinks > a{ 79 | font-size:2em; 80 | } 81 | .indent{ 82 | margin:5px; 83 | >li{ 84 | margin:4px; 85 | } 86 | } 87 | #evol{ 88 | margin-bottom: 16px; 89 | } 90 | 91 | .demoPanel{ 92 | border: 2px solid #A7C8E2; 93 | margin: 4px 3px; 94 | padding: 10px; 95 | @include b-radius(2px); 96 | } 97 | .demovalue { 98 | width: 100%; 99 | min-height: 60px; 100 | } 101 | #jsonmodel{ 102 | width:100%; 103 | height:200px; 104 | } 105 | .evo-icon-16{ 106 | margin-right: 6px !important; 107 | } 108 | 109 | /* index.html */ 110 | .title2{ 111 | font-size:smaller; 112 | font-weight: normal; 113 | color: $color-navbar; 114 | } 115 | 116 | @mixin mixin-badgeHeight($h) { 117 | .evol-badges-body > .panel { 118 | $height: $h !important; 119 | } 120 | } 121 | /* demo card view*/ 122 | [data-eid="todo"], 123 | [data-eid="contact"] { 124 | .evol-cards-body > .panel { 125 | height: 145px !important; 126 | } 127 | } 128 | [data-eid="winecellar"] .evol-cards-body { 129 | > div.panel { 130 | height: 320px !important; 131 | } 132 | } 133 | [data-eid="comics"] { 134 | .evol-cards-body > .panel { 135 | height: 500px !important; 136 | } 137 | } 138 | 139 | [data-eid="test"] .evol-cards-body > div.panel { 140 | height: 532px !important; 141 | } 142 | 143 | .cBlue{ 144 | color: #0277BD; 145 | } 146 | .cGreen{ 147 | color: #4CAF50; 148 | } 149 | .cRed{ 150 | color: #DD2C00; 151 | } 152 | -------------------------------------------------------------------------------- /demo/test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | Test :: Evolutility-UI-jQuery 30 | 31 | 32 | 33 | 34 |
35 | 36 | 42 |
43 |
44 | 45 |
46 |

Test

47 |
48 | 49 |
50 | 51 |
52 | 53 |

This app is made to easily test Evolutility-UI-jQuery. It provides an object which uses all possible field types.

54 |

Test object

55 | 56 |
57 | 58 | 59 |
60 | 61 |
62 | 63 | 79 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /js/view-one/one-json.js: -------------------------------------------------------------------------------- 1 | /*! *************************************************************************** 2 | * 3 | * evolutility-ui-jquery :: one-json.js 4 | * 5 | * View "one json" to edit one backbone model in JSON. 6 | * 7 | * https://github.com/evoluteur/evolutility-ui-jquery 8 | * (c) 2017 Olivier Giulieri 9 | * 10 | *************************************************************************** */ 11 | 12 | Evol.ViewOne.JSON = Evol.View_One.extend({ 13 | 14 | events: { 15 | 'click > .evol-buttons > button': 'click_button', 16 | 'click .evol-title-toggle': 'click_toggle', 17 | }, 18 | 19 | viewName: 'json', 20 | icon: 'barcode', // glyphicon-barcode 21 | 22 | render: function () { 23 | var dom=Evol.DOM; 24 | if(this.model){ 25 | var h = [], 26 | jsonStr=JSON.stringify(this.model, null, 2); 27 | 28 | h.push(dom.panelBegin({ 29 | id: 'p-json', 30 | label:Evol.Format.capitalize(this.uiModel.name), 31 | label2: 'JSON' 32 | }, this.style+' evo-p-json', true)+ 33 | '
'+ 34 | dom.label('uimjson', 'JSON')+ 35 | dom.input.textMJSON('uimjson', jsonStr, 16)+ 36 | '
'+ 37 | dom.panelEnd()); 38 | this._renderButtons(h, 'json'); 39 | this.$el.html(h.join('')); 40 | }else{ 41 | this.$el.html(dom.HTMLMsg(Evol.i18n.nodata, '', 'info')); 42 | } 43 | this.setData(this.model); 44 | //this.custOn=false; 45 | return this; 46 | }, 47 | 48 | validate: function () { 49 | var isValid=true, 50 | data=this.getData(), 51 | $fp=this._getDOMField().parent(); 52 | 53 | //this.clearMessages(); 54 | isValid=!Evol.DOM.addRemClass($fp, data===null, 'has-error'); 55 | this.$el.trigger('action', 'validate', {valid:isValid}); 56 | return isValid?[]:[Evol.i18n.validation.invalid]; 57 | }, 58 | 59 | getData: function () { 60 | var jsonStr=this._getDOMField().val(), 61 | obj; 62 | 63 | if(jsonStr===''){ 64 | return jsonStr; 65 | } 66 | try{ 67 | obj=$.parseJSON(jsonStr); 68 | }catch(err){ 69 | obj=null; 70 | } 71 | return obj; 72 | }, 73 | 74 | setData: function (m) { 75 | this.clearError()._getDOMField().val(JSON.stringify(m.toJSON(), null, 2)); 76 | return this.setTitle(); 77 | }, 78 | 79 | clear: function () { 80 | this._getDOMField().val(''); 81 | return this; 82 | }, 83 | 84 | clearError: function(){ 85 | this._getDOMField().parent().removeClass('has-error'); 86 | return this; 87 | }, 88 | 89 | _getDOMField: function(){ 90 | return this.$('textarea'); 91 | } 92 | 93 | }); 94 | -------------------------------------------------------------------------------- /models/todo.data.js: -------------------------------------------------------------------------------- 1 | var uiModels = uiModels || {}; 2 | uiModels.todo_data = [ 3 | {id: '1', title: 'Release Evolutility v1', priority: '3', category: 'others', complete: false, project:['1','2','3'], description: '10 generic views + a ui-modeling language.', notes:''}, 4 | {id: '2', title: 'Fix open bugs', duedate: '2016-07-25', priority: '3', category: 'work', project:['1','2'], complete: false, description: 'Not much left.'}, 5 | {id: '3', title: 'Testing App', duedate: '2016-06-11', priority: '3', category: 'work', complete: false, project:['1', '2','3'], description: 'test'}, 6 | {id: '4', title: 'Prepare demo', duedate: '2016-05-12', priority: '1', category: 'work', complete: false, project:['4'], description: 'Check this out'}, 7 | {id: '5', title: 'Test latest code', priority: '5', category: 'misc', complete: true, project:['1','2','3'], description: 'notes for my test todo task.'}, 8 | {id: '6', title: 'Car wash', priority: '4', category: 'work', project:['10'], complete: false}, 9 | {id: '7', title: 'Watch Inception', duedate: '2016-01-10', priority: '5', category: 'fun', project:['10'], complete: true}, 10 | {id: '8', title: 'Test TODO', duedate: '2017-01-01', priority: '1', category: 'work', project:['2','3'], complete: true, description: 'Test TODO '}, 11 | {id: '9', title: 'Dentist', priority: '3', category: 'home', complete: true}, 12 | {id: '10', title: 'French translation', priority: '3', category: 'work', project:['5'], complete: true}, 13 | {id: '11', title: 'Italian translation', priority: '4', category: 'work', project:['5']}, 14 | {id: '12', title: 'Chinese translation', priority: '3', category: 'work', project:['5']}, 15 | {id: '13', title: 'Japanese translation', priority: '4', category: 'work', project:['5']}, 16 | {id: '14', title: 'German translation', priority: '4', category: 'work', project:['5']}, 17 | {id: '15', title: 'Russian translation', priority: '4', category: 'work', project:['5']}, 18 | {id: '16', title: 'Polish translation', priority: '4', category: 'work', project:['5']}, 19 | {id: '17', title: 'Klingon translation', priority: '4', category: 'work', project:['5']}, 20 | {id: '18', title: 'Code optimization', duedate: '2017-01-01', priority: '4', category: 'work', project:['1','2','4'], complete: false}, 21 | {id: '19', title: 'Setup demo server', priority: '2', category: 'work', complete: false, project:['4']}, 22 | {id: '20', title: 'Add sample data', duedate: '2016-04-23', priority: '3', category: 'work', project:['1','2','3'], complete: true}, 23 | {id: '21', title: 'Make proposal', priority: '2', category: 'misc', project:['4'], complete: false}, 24 | {id: '22', title: 'Checkout cool restaurant', priority: '3', category: 'fun', project: ['4','10'], complete: false}, 25 | {id: '23', title: 'Kill the vampires', priority: '3', project:['10'], category: 'others'} 26 | ]; 27 | 28 | if(typeof module === "object" && typeof module.exports === "object"){ 29 | module.exports = uiModels.todo_data; 30 | } 31 | -------------------------------------------------------------------------------- /models/todo.js: -------------------------------------------------------------------------------- 1 | var uiModels = uiModels || {}; 2 | 3 | uiModels.todo = { 4 | id: 'todo', 5 | label: 'To Do', 6 | name: 'task', 7 | namePlural: 'tasks', 8 | icon: 'todo.gif', 9 | fnTitle:'title', 10 | fnSearch: ['title', 'description'], 11 | elements: [ 12 | { 13 | type: 'panel', label: 'Task', width: 62, 14 | elements: [ 15 | { 16 | id: 'title', attribute: 'title', type: 'text', label: 'Title', required: true, 17 | //placeholder: 'Call John', 18 | maxLength: 255, 19 | width: 100, inMany: true 20 | }, 21 | { 22 | id: 'duedate', attribute: 'duedate', type: 'date', label: 'Due Date', width: 62, inMany: true 23 | }, 24 | { 25 | id: 'category', attribute: 'category', type: 'lov', label: 'Category', width: 38, inMany: true, 26 | list: [ 27 | {id: 1, text: 'Home'}, 28 | {id: 2, text: 'Work'}, 29 | {id: 3, text: 'Fun'}, 30 | {id: 4, text: 'Others'}, 31 | {id: 5, text: 'Misc.'} 32 | ], 33 | typeChart:'bars' 34 | } 35 | ] 36 | }, 37 | { 38 | type: 'panel', label: 'Status', width: 38, 39 | elements: [ 40 | { 41 | id: 'priority', attribute: 'priority', type: 'lov', label: 'Priority', required: true, 42 | width: 100, inMany: true, 43 | list: [ 44 | {id: 1, text: '1 - ASAP'}, 45 | {id: 2, text: '2 - Urgent'}, 46 | {id: 3, text: '3 - Important'}, 47 | {id: 4, text: '4 - Medium'}, 48 | {id: 5, text: '5 - Low'} 49 | ] 50 | }, 51 | { 52 | id: 'complete', attribute: 'complete', type: 'boolean', width: 100, inMany: true, 53 | label: 'Complete', 54 | labelCharts:'Tasks completion', labelTrue: 'Complete', labelFalse:'Incomplete', 55 | typeChart:'pie' 56 | } 57 | ] 58 | }, 59 | { 60 | type: 'panel', label: 'Task Description', label2:'and Notes', width: 100, 61 | elements: [ 62 | { 63 | id: 'description', attribute: 'description', type: 'textmultiline', 64 | label: 'Description', 65 | maxLength: 1000, 66 | width: 100, height: 5, inMany: false 67 | } 68 | ] 69 | } 70 | ] 71 | }; 72 | 73 | if(typeof module === "object" && typeof module.exports === "object"){ 74 | module.exports = uiModels.todo; 75 | } 76 | -------------------------------------------------------------------------------- /js/dico/format.js: -------------------------------------------------------------------------------- 1 | /*! *************************************************************************** 2 | * 3 | * evolutility-ui-jquery :: format.js 4 | * 5 | * Helpers for string manipulation and date formats 6 | * 7 | * https://github.com/evoluteur/evolutility-ui-jquery 8 | * (c) 2017 Olivier Giulieri 9 | * 10 | *************************************************************************** */ 11 | 12 | var Evol = Evol || {}; 13 | 14 | Evol.Format = { 15 | 16 | // --- string helpers --- 17 | capitalize: function(word){ // TODO use _.string.capitalize(word); 18 | if(word && word.length>0){ 19 | return word.substring(0,1).toUpperCase() + word.substring(1);//.toLowerCase(); 20 | } 21 | return ''; 22 | }, 23 | trim: function(stringValue){ // TODO use _.string.trim(word); 24 | if(_.isString(stringValue) && stringValue!==''){ 25 | return stringValue.replace(/^\s+|\s+$/g, ''); 26 | } 27 | return ''; 28 | }, 29 | cr2br: function(v, escape){ 30 | if(v==='' || v===null || _.isUndefined(v)){ 31 | return ''; 32 | } 33 | var txt=escape?_.escape(v):v; 34 | return txt.replace(/[\r\n]/g, '
'); 35 | }, 36 | 37 | // --- date formats --- 38 | dateString: function(d){ 39 | if(d){ 40 | d=d.substring(0, 10); 41 | } 42 | if(!_.isUndefined(d) && d!==null){ 43 | var dateParts=d.split('-'); 44 | if(dateParts.length>1){ 45 | return dateParts[1]+'/'+dateParts[2]+'/'+dateParts[0]; 46 | } 47 | } 48 | return ''; 49 | }, 50 | timeString: function(d){ 51 | if(!_.isUndefined(d) && d!==null && d!==''){ 52 | var timeParts=d.split(':'), 53 | hour=parseInt(timeParts[0],10); 54 | if(hour>12){ 55 | return (hour-12)+':'+timeParts[1]+' PM'; 56 | }else{ 57 | return hour+':'+timeParts[1]+' AM'; 58 | } 59 | } 60 | return ''; 61 | }, 62 | datetimeString: function(d){ 63 | if(!_.isUndefined(d) && d!==null && d!==''){ 64 | var dateParts=d.split('T'); 65 | if(dateParts.length>1){ 66 | return this.dateString(dateParts[0])+', '+this.timeString(dateParts[1]); 67 | }else{ 68 | return this.dateString(dateParts[0]); 69 | } 70 | } 71 | return ''; 72 | }, 73 | 74 | // --- JSON formats --- 75 | jsonString: function(d, cr2br){ 76 | var dd; 77 | try{ 78 | dd=(_.isString(d) && d!=='') ? $.parseJSON(_.unescape(d)) : d; 79 | }catch(err){ 80 | alert('Error: format.jsonString'+ err); 81 | dd={"error": "Evol.Format.jsonString"}; 82 | } 83 | if(dd===''){ 84 | return dd; 85 | }else{ 86 | //var txt=JSON.stringify(dd, null, '\t'); 87 | var txt=JSON.stringify(dd, null, 2); 88 | if(cr2br){ 89 | txt=this.cr2br(txt); 90 | } 91 | return txt; 92 | } 93 | } 94 | 95 | }; 96 | -------------------------------------------------------------------------------- /sass/many.scss: -------------------------------------------------------------------------------- 1 | // Evolutility-UI-jQuery :: many.css 2 | 3 | // https://github.com/evoluteur/evolutility-ui-jquery 4 | // (c) 2017 Olivier Giulieri 5 | 6 | /* --- list --- */ 7 | 8 | .evol-many-icon{ 9 | margin-right: 6px !important; 10 | } 11 | 12 | .evol-many-list{ 13 | 14 | > div { 15 | overflow-x: auto; 16 | overflow-y: hidden; 17 | > .table { 18 | border: 1px solid $color-border; 19 | margin-bottom: 0; 20 | 21 | textarea{ 22 | min-width:200px; 23 | } 24 | 25 | img { 26 | max-height: 60px; 27 | padding:0; 28 | } 29 | tr{ 30 | transition: all 0.3s ease; 31 | } 32 | td{ 33 | position: relative; 34 | } 35 | th { 36 | font-weight: $weight-label !important; 37 | background-color: $toolbar-background-color; 38 | 39 | .glyphicon { 40 | display:none; 41 | position:absolute; 42 | opacity: .8; 43 | margin-left: 6px; 44 | background-color: white; 45 | cursor: pointer; 46 | width:22px; 47 | height: 22px; 48 | } 49 | 50 | &:hover .glyphicon { 51 | display: inline !important; 52 | } 53 | 54 | } 55 | .evol-ellipsis{ 56 | @include ellipsis(); 57 | max-width: 120px; 58 | } 59 | } 60 | } 61 | 62 | .glyphicon.evol-last-sort { 63 | display:none; 64 | position:absolute; 65 | } 66 | 67 | } 68 | .evo-many-summary{ 69 | margin-top:10px; 70 | } 71 | .evol-r-align{ 72 | text-align: right; 73 | } 74 | 75 | .badge-list{ 76 | position: relative; 77 | top:-2px; 78 | margin-left:5px; 79 | } 80 | 81 | /* --- list > sort icons --- */ 82 | 83 | .evol-sort-icons { 84 | position: relative; 85 | top:3px; 86 | padding: 3px; 87 | width:300px; 88 | > .glyphicon { 89 | color:$color-icon; 90 | position: absolute; 91 | top:2px; 92 | &:hover{ 93 | color:$color-icon-hover; 94 | } 95 | } 96 | > .glyphicon-chevron-up { 97 | left:7px; 98 | } 99 | > .glyphicon-chevron-down { 100 | left:24px; 101 | } 102 | } 103 | 104 | .panel-heading { 105 | 106 | > .evol-title-toggle{ 107 | display: none; 108 | } 109 | 110 | &:hover > .evol-title-toggle{ 111 | display: inline; 112 | } 113 | 114 | } 115 | 116 | .list-td-sel{ 117 | width:30px; 118 | } 119 | 120 | .evo-col-pix{ 121 | width: 100px; 122 | } 123 | // from Bootstrap normalize.scss (only pieces needed for Evolutility views) 124 | /*! normalize.css v3.0.2 | MIT License | git.io/normalize */ 125 | 126 | // 127 | // 1. Set default font family to sans-serif. 128 | // 2. Prevent iOS text size adjust after orientation change, without disabling 129 | // user zoom. 130 | // 131 | 132 | html { 133 | font-family: sans-serif; // 1 134 | -ms-text-size-adjust: 100%; // 2 135 | -webkit-text-size-adjust: 100%; // 2 136 | } 137 | 138 | // 139 | // Remove default margin. 140 | // 141 | 142 | body { 143 | margin: 0; 144 | } 145 | 146 | // Tables 147 | // ========================================================================== 148 | 149 | // 150 | // Remove most spacing between table cells. 151 | // 152 | 153 | table { 154 | border-collapse: collapse; 155 | border-spacing: 0; 156 | } 157 | -------------------------------------------------------------------------------- /sass/doc.scss: -------------------------------------------------------------------------------- 1 | // Evolutility-UI-jQuery :: doc.css 2 | 3 | // https://github.com/evoluteur/evolutility-ui-jquery 4 | // (c) 2017 Olivier Giulieri 5 | 6 | .evol-doc-views{ 7 | >section { 8 | //float:left; 9 | //width:500px; 10 | margin:10px; 11 | img{ 12 | width:500px; 13 | } 14 | } 15 | h4{ 16 | margin-top: 25px; 17 | } 18 | } 19 | img.shadow { 20 | border: 1px solid #e0e0e0; 21 | box-shadow: 4px 4px 2px rgba(0, 0, 0, 0.25); 22 | -moz-box-shadow: 4px 4px 2px rgba(0, 0, 0, 0.25); 23 | -webkit-box-shadow: 4px 4px 2px rgba(0, 0, 0, 0.25); 24 | } 25 | img.pixEvoPos{ 26 | width: 350px !important; 27 | } 28 | .pixEvoView, .pixEvoPos{ 29 | margin: 10px 0 10px 20px; 30 | } 31 | .pixEvoPos img{ 32 | width: 250px; 33 | } 34 | 35 | .view-fullname{ 36 | color: silver; 37 | font-size: 16px; 38 | font-weight: 300; 39 | margin-left:5px; 40 | } 41 | .evo-asection{ 42 | display:block; 43 | margin-top:200px; 44 | content: " "; 45 | } 46 | 47 | .evo-links-views { 48 | > div{ 49 | margin: 4px 0 10px 20px; 50 | } 51 | >li{ 52 | margin: 5px 0 10px; 53 | } 54 | a > i{ 55 | margin:5px; 56 | } 57 | } 58 | 59 | #evol-views-params{ 60 | >div>div{ 61 | float:left; 62 | margin-right:5px; 63 | } 64 | } 65 | .Icon{ 66 | position: relative; 67 | top: -3px; 68 | margin-right: 4px; 69 | } 70 | 71 | code{ 72 | display: block; 73 | padding: 10px; 74 | overflow: auto; 75 | font-size: 85%; 76 | background-color: #f7f7f7; 77 | @include b-radius(2px); 78 | } 79 | 80 | .list-views{ 81 | position:absolute; 82 | top: 7px; 83 | left: 225px; 84 | >div{ 85 | color: white; 86 | padding: 0 4px; 87 | a{ 88 | color: white; 89 | padding: 0 4px; 90 | } 91 | } 92 | i{ 93 | margin-right:4px; 94 | } 95 | } 96 | .docViewType{ 97 | display: inline-block; 98 | width: 170px; 99 | text-align: right; 100 | } 101 | 102 | // index 103 | .page-index{ 104 | >section{ 105 | margin:40px 0; 106 | } 107 | } 108 | .titleindex{ 109 | font-size:50px; 110 | margin-bottom: 36px; 111 | color: #3399cc;/* 112 | > img{ 113 | width:74px; 114 | height:120px; 115 | margin-right:20px; 116 | }*/ 117 | } 118 | #s-splash{ 119 | margin: -20px -30px 30px -30px; 120 | background-color: #2072a7; 121 | padding:30px; 122 | text-align: center; 123 | color:white; 124 | >h1{ 125 | color:white; 126 | } 127 | >h2{ 128 | font-weight: 300; 129 | } 130 | } 131 | #s-intro{ 132 | font-weight: 500; 133 | } 134 | .page-docidx{ 135 | >section{ 136 | margin:20px 0 30px; 137 | } 138 | } 139 | 140 | .links-bh, 141 | .links-bih{ 142 | a { 143 | margin: 10px 5px; 144 | padding: 5px; 145 | @include b-radius(5px); 146 | /*&:hover{ 147 | background-color: #E3F2FD; 148 | text-decoration: none; 149 | }*/ 150 | >img { 151 | position: relative; 152 | top:-2px; 153 | } 154 | } 155 | } 156 | .links-bih a { 157 | padding: 5px 10px 3px 5px; 158 | } 159 | 160 | .mt10{ 161 | margin-top: 10px; 162 | } 163 | .pl10{ 164 | padding-left: 10px; 165 | } 166 | 167 | .t-props{ 168 | tr td:first-child{ 169 | width:140px; 170 | font-weight: 600; 171 | } 172 | } 173 | .t-row{ 174 | background-color: #E3F2FD; 175 | } 176 | 177 | -------------------------------------------------------------------------------- /demo/demo.js: -------------------------------------------------------------------------------- 1 | /*! *************************************************************************** 2 | * 3 | * evolutility-ui-jquery :: demo.js 4 | * 5 | * Demo 6 | * 7 | * https://github.com/evoluteur/evolutility-ui-jquery 8 | * (c) 2020 Olivier Giulieri 9 | * 10 | *************************************************************************** */ 11 | 12 | var uidef=null; 13 | 14 | var ViewDescriptions = { 15 | 'browse': {name: 'Browse', desc: 'The "Browse" view shows all fields for viewing (in read only mode). Fields are grouped in panels and tabs.'}, 16 | 'edit': {name: 'Edit', desc: 'The "Edit" view shows all fields for edition to create or update models. It automatically performs validation based on the UI-model and supports the Master-Details pattern (nested collections). Fields are grouped in panels and tabs.'}, 17 | 'mini': {name: 'Mini (quick-edit)', desc: 'The "Mini" (quick-edit) view only shows important fields (required or showing as a column in grids). Fields are grouped in a single panel.'}, 18 | 'json': {name: 'JSON', desc: 'The "JSON" view shows the JSON representation of the data.'}, 19 | 'list': {name: 'List', desc: 'The "List" view gives a tabular view of a collection with paging.'}, 20 | 'cards': {name: 'Cards', desc: 'The "Cards" Shows records side by side as cards.'}, 21 | 'bubbles': {name: 'Bubbles', desc: 'The "Bubbles" view displays the data as bubbles with controls to group them and set their color and size (this view uses D3.js).'}, 22 | 'charts': {name: 'Charts', desc: 'The "Charts" view draws charts about the collection.'}, 23 | 'filter': {name: 'Filter', desc: 'The "Filter" view is used to build a structured query to filter a collection.'}, 24 | 'export': {name: 'Export', desc: 'The "Export" view let\'s you define export options and preview the collection export in different data formats (CSV, TAB, HTML, XML, SQL and JSON).'} 25 | }; 26 | 27 | function createSampleDataIfEmpty(entityName){ 28 | var M, MS; 29 | if(EvoConfig.localStorage){ 30 | var lc = new Backbone.LocalStorage('evol-'+entityName); 31 | M = Backbone.Model.extend({ 32 | localStorage: lc 33 | }); 34 | Ms = Backbone.Collection.extend({ 35 | model: M, 36 | localStorage: lc 37 | }); 38 | }else{ 39 | M = Backbone.Model.extend({ 40 | urlRoot: EvoConfig.url+entityName 41 | }); 42 | Ms = Backbone.Collection.extend({ 43 | model: M, 44 | url: EvoConfig.url+entityName/*, 45 | sync : function(method, collection, options) { 46 | //options.dataType = "jsonp"; 47 | return Backbone.sync(method, collection, options); 48 | }*/ 49 | }); 50 | } 51 | 52 | var ms = new Ms(); 53 | ms.fetch({ 54 | success: function(collection){ 55 | // TODO remove sample data 56 | if(collection.length===0){ 57 | _.each(uiModels[entityName+'_data'], function(d){ 58 | collection.create(d); 59 | }); 60 | } 61 | } 62 | }); 63 | } 64 | 65 | function showUIModel(uiModel){ 66 | if(_.isString(uiModel)){ 67 | uiModel=uiModels[uiModel]; 68 | } 69 | $('#uimodel').html(Evol.DOM.input.textMJSON('uimodel2', uiModel, 12)) 70 | .slideDown(); 71 | $('#hide_def').show(); 72 | } 73 | 74 | function hideUIModel(){ 75 | $('#uimodel').slideUp(); 76 | $('#hide_def').hide(); 77 | } 78 | 79 | function showApp(entity, view){ 80 | var m=uiModels[entity]; 81 | if(m){ 82 | $('#title').html(m.label); 83 | window.location.href = '#'+entity+'/'+(view||'list'); 84 | }else{ 85 | alert('App not defined "'+entity+'".'); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /sass/toolbar.scss: -------------------------------------------------------------------------------- 1 | // Evolutility-UI-jQuery :: toolbar.css 2 | 3 | // https://github.com/evoluteur/evolutility-ui-jquery 4 | // (c) 2017 Olivier Giulieri 5 | 6 | #title{ 7 | >i{ 8 | color: #c6d9f0; 9 | margin-right: 0.4em; 10 | } 11 | } 12 | 13 | .evo-toolbar{ 14 | border: 1px solid $toolbar-border-color; 15 | @include b-radius(2px); 16 | margin-bottom:10px; 17 | padding:3px; 18 | background-color: $toolbar-background-color; 19 | 20 | > [data-cid="views"]{ 21 | color:black; 22 | } 23 | 24 | .evo-dropdown-icons i{ 25 | margin-right: 10px; 26 | } 27 | 28 | .caret{ 29 | display: inline-block; 30 | position: relative; 31 | margin-left: -4px; 32 | top: -2px; 33 | } 34 | 35 | > ul { 36 | > .evo-sel .glyphicon:before{ 37 | color:black; 38 | } 39 | > li { 40 | &.divider-h{ 41 | height: 39px; 42 | width: 1px; 43 | background-color: $toolbar-border-color; 44 | } 45 | >a { 46 | position: relative; 47 | transition: all 0.5s ease; 48 | padding: 8px; 49 | text-align: center; 50 | >i{ 51 | display: block; 52 | // font-size: 22px !important; 53 | padding: 4px 3px; 54 | } 55 | .glyphicon-menu-hamburger{ 56 | display: inline-block; 57 | } 58 | } 59 | 60 | } 61 | } 62 | /* 63 | [data-id="prev"].nav-disabled, 64 | [data-id="next"].nav-disabled{ 65 | a { 66 | color: $color-disabled; 67 | &:hover{ 68 | background-color: transparent; 69 | cursor:default; 70 | } 71 | } 72 | } 73 | */ 74 | .evo-dropdown-icons{ 75 | min-width: 50px; 76 | } 77 | 78 | // bootstrap override 79 | .dropdown-menu>li>a{ 80 | padding: 3px 10px; 81 | } 82 | 83 | } 84 | 85 | .evo-filter-on{ 86 | background-color: #e0f2f1; 87 | } 88 | .evo-view-on{ 89 | color: $color-icon-hover; 90 | } 91 | 92 | .evo-tb-status{ 93 | color: #0f0f0f !important; 94 | min-height: 35px; 95 | line-height: 35px; 96 | margin-top: 2px; 97 | margin-right: 5px; 98 | //max-width:200px; 99 | //.evol-ellipsis(); 100 | 101 | } 102 | 103 | // -- search 104 | .evo-search{ 105 | position:relative; 106 | top: 2px; 107 | width:200px; 108 | margin: auto; 109 | .evo-field{ 110 | &:not(:valid) ~ .clear-icon { 111 | opacity: 0; 112 | } 113 | } 114 | >.btn{ 115 | position: relative; 116 | top:0; 117 | } 118 | } 119 | 120 | .clear-icon { 121 | z-index: 3; 122 | position: absolute; 123 | top: 12px; 124 | right: 47px; 125 | color: #90a4ae; 126 | cursor: pointer; 127 | } 128 | 129 | // -- mini vertical toolbar in views 130 | .evol-actions, 131 | .evol-actions-nxtTd{ 132 | position: absolute; 133 | display: flex; 134 | flex-direction: column; 135 | padding: 5px; 136 | background-color: $toolbar-background-color; 137 | border: 1px solid #bce8f1; 138 | >i{ 139 | color: $color-icon; 140 | padding: 10px; 141 | cursor: pointer; 142 | @include b-radius(2px); 143 | &:hover{ 144 | color: $color-icon-hover; 145 | background-color: $color-icon-background-hover; 146 | } 147 | } 148 | } 149 | .evol-actions{ 150 | top: 35px; 151 | right: 1px; 152 | border-color: $color-border; 153 | border-right: none; 154 | border-top-left-radius: 5px; 155 | border-bottom-left-radius: 5px; 156 | } 157 | .evol-many-list .evol-actions{ 158 | border: 1px solid $color-border; 159 | border-radius: 5px; 160 | } 161 | .evol-actions-nxtTd{ 162 | top:0; 163 | left: 0; 164 | z-index: 2; 165 | border-top-right-radius: 5px; 166 | border-bottom-right-radius: 5px; 167 | } 168 | 169 | .evol-many-list{ 170 | .evol-actions{ 171 | top:0; 172 | flex-direction: row; 173 | } 174 | } 175 | 176 | -------------------------------------------------------------------------------- /sass/dependencies.scss: -------------------------------------------------------------------------------- 1 | /*! 2 | evolutility-ui-jquery 3 | 4 | dependencies: bootstrap-sass 3.3.7 + bootstrap-datepicker 1.6.4 + select2 4.0.13 + toastr 2.1.4 + balloon-css 1.2.0 5 | 6 | https://github.com/evoluteur/evolutility-ui-jquery 7 | */ 8 | 9 | /*! 10 | * Bootstrap v3.3.7 (http://getbootstrap.com) 11 | * Copyright 2011-2016 Twitter, Inc. 12 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 13 | */ 14 | 15 | // Core variables and mixins 16 | @import "../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/_variables"; 17 | @import "../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/_mixins"; 18 | 19 | // Reset and dependencies 20 | @import "../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/_normalize"; 21 | @import "../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/_print"; 22 | @import "../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/_glyphicons"; 23 | 24 | // Core CSS 25 | @import "../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/_scaffolding"; 26 | @import "../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/_type"; 27 | //@import "../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/_code"; 28 | //@import "../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/_grid"; 29 | @import "../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/_tables"; 30 | @import "../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/_forms"; 31 | @import "../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/_buttons"; 32 | 33 | // Components 34 | @import "../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/_component-animations"; 35 | @import "../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/_dropdowns"; 36 | @import "../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/_button-groups"; 37 | @import "../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/_input-groups"; 38 | @import "../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/_navs"; 39 | //@import "../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/_navbar"; 40 | //@import "../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/_breadcrumbs"; 41 | @import "../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/_pagination"; 42 | //@import "../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/_pager"; 43 | @import "../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/_labels"; 44 | @import "../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/_badges"; 45 | //@import "../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/_jumbotron"; 46 | @import "../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/_thumbnails"; 47 | @import "../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/_alerts"; 48 | //@import "../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/_progress-bars"; 49 | //@import "../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/_media"; 50 | //@import "../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/_list-group"; 51 | @import "../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/_panels"; 52 | //@import "../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/_responsive-embed"; 53 | //@import "../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/_wells"; 54 | @import "../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/_close"; 55 | 56 | // Components w/ JavaScript 57 | @import "../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/_modals"; 58 | //@import "../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/_tooltip"; 59 | @import "../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/_popovers"; 60 | //@import "../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/_carousel"; 61 | 62 | // Utility classes 63 | @import "../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/_utilities"; 64 | //@import "../node_modules/bootstrap-sass/assets/stylesheets/bootstrap/_responsive-utilities"; 65 | /* 66 | // Other third party 67 | @import '../node_modules/react-datepicker/dist/react-datepicker'; 68 | //@import '../node_modules/react-select/dist/react-datepicker-cssmodules'; 69 | @import '../node_modules/react-select/dist/react-select'; 70 | 71 | 72 | */ 73 | // Widgets 74 | @import '../node_modules/bootstrap-datepicker/dist/css/bootstrap-datepicker'; 75 | @import '../node_modules/toastr/toastr.scss'; 76 | @import '../node_modules/select2/dist/css/select2'; 77 | @import '../node_modules/balloon-css/balloon'; 78 | 79 | .select2{ 80 | width: 100% !important; 81 | 82 | .select2-selection__rendered{ 83 | padding: 0 5px 5px !important; 84 | } 85 | } 86 | // override balloon.css 87 | [data-balloon]:after{ 88 | border-radius: 1px; 89 | font-weight: 500; 90 | } 91 | -------------------------------------------------------------------------------- /models/contacts.data.js: -------------------------------------------------------------------------------- 1 | var uiModels = uiModels || {}; 2 | uiModels.contact_data = [{ 3 | id: '1', 4 | lastname: 'Smallwood', 5 | firstname: 'Diane', 6 | jobtitle: 'Director', 7 | company: 'EasyDoesIt', 8 | email: 'vsw@EasyDoesIt.com', 9 | phone: '415 234 4323', 10 | phonehome: '415 378 3577', 11 | phonecell: '415 135 3454', 12 | web: 'http://EasyDoesIt.com', 13 | address: '12, Liverpool Street', 14 | city: 'San Francisco', 15 | state: 'CA', 16 | zip: '94123', 17 | country: 'US', 18 | category: '4' 19 | }, { 20 | id: '2', 21 | lastname: 'Shackleford ', 22 | firstname: 'Rusty ', 23 | email: 'rustyshackleford@gmail.com', 24 | address: '123 Main Street', 25 | city: 'Dallas', 26 | state: 'TX', 27 | country: 'US', 28 | category: '3' 29 | }, { 30 | id: '3', 31 | lastname: 'Inoue', 32 | firstname: 'Akemi', 33 | jobtitle: 'QA Engineer', 34 | company: 'Testing evol-utility', 35 | email: 'test@test.com', 36 | phone: '423 233 3523', 37 | phonehome: '423 523 4523', 38 | address: '5665 Poplar Street', 39 | city: 'San Jose', 40 | state: 'CA', 41 | zip: '93112', 42 | country: 'US', 43 | category: '3' 44 | }, { 45 | id: '4', 46 | lastname: 'Reina Moyano', 47 | firstname: 'Sergio', 48 | jobtitle: 'Mr', 49 | company: 'Innova Creaciones', 50 | email: 'sreina@innovacreaciones.es', 51 | phone: '411 444 2222', 52 | phonehome: '411 576 4566', 53 | phonecell: '411 579 4566', 54 | fax: '411 444 2224', 55 | address: '654 Union Street', 56 | city: 'San Francisco', 57 | state: 'CA', 58 | zip: '94567', 59 | country: 'US', 60 | category: '3' 61 | }, { 62 | id: '5', 63 | lastname: 'Paulus', 64 | firstname: 'Henry', 65 | company: 'TEST the TEST', 66 | phone: '652 491 2345', 67 | address: '1234 That Street', 68 | city: 'San Mateo', 69 | state: 'CA', 70 | zip: '94401', 71 | country: 'US', 72 | category: '2' 73 | }, { 74 | id: '6', 75 | lastname: 'Dupond', 76 | firstname: 'Patrick', 77 | jobtitle: 'Sales Manager', 78 | company: 'Au Bon Pain', 79 | email: 'pdupond@aubonpain.fr', 80 | phone: '45 456 414 45', 81 | web: 'http://aubonpain.fr', 82 | city: 'Paris', 83 | state: '', 84 | country: 'FR', 85 | category: '1' 86 | }, { 87 | id: '7', 88 | lastname: 'Giulieri', 89 | firstname: 'Olivier', 90 | company: 'Evolutility', 91 | city: 'San Mateo', 92 | state: 'CA', 93 | country: 'US', 94 | email: 'olivier@evolutility.org', 95 | web: 'http://www.evolutility.org' 96 | }, { 97 | id: '8', 98 | lastname: 'Martin', 99 | firstname: 'Mary', 100 | jobtitle: 'President', 101 | company: 'Acme Corp', 102 | email: 'pm@acme.com', 103 | phone: '444 580 7007', 104 | phonehome: '449 512 0230', 105 | phonecell: '589 499 2065', 106 | address: '123 Redville Lane', 107 | city: 'Musnonville', 108 | state: 'NH', 109 | zip: '03434', 110 | category: '1' 111 | }, { 112 | id: '9', 113 | lastname: 'Munar', 114 | firstname: 'Roman', 115 | jobtitle: 'Mr', 116 | company: 'Informatics', 117 | email: 'romano@informatics.com', 118 | phone: '322 234 5143', 119 | phonehome: '322 784 3453', 120 | phonecell: '322 538 2568', 121 | fax: '322 234 5345', 122 | web: 'http://roman.munar.com', 123 | address: 'Washington', 124 | city: 'Makati', 125 | state: '', 126 | zip: '1300', 127 | country: 'PH', 128 | category: '3' 129 | }, { 130 | id: '10', 131 | lastname: 'Smith', 132 | firstname: 'George', 133 | company: 'Blabla', 134 | email: 'george@blabla.com', 135 | web: 'http://www.blabla.com', 136 | phone: '415 123 1234', 137 | phonecell: '415 789 4556', 138 | address: '768 5th Ave', 139 | city: 'San Francisco', 140 | state: 'CA', 141 | zip: '93123', 142 | country: 'US', 143 | category: '1' 144 | }, { 145 | id: '11', 146 | lastname: 'Kumar', 147 | firstname: 'Madhukar', 148 | jobtitle: 'CEO', 149 | company: 'CoolWeb', 150 | email: 'mkumar@coolweb.com', 151 | web: 'http://www.coolweb.com', 152 | phone: '7225 8252', 153 | phonecell: '7325 8245', 154 | address: '434 Cool Place', 155 | city: 'Bengaluru', 156 | state: '', 157 | country: 'IN', 158 | category: '4' 159 | }, { 160 | id: '12', 161 | lastname: 'Cheng', 162 | firstname: 'Chris', 163 | jobtitle: 'CTO', 164 | company: 'MyGreatCorporation', 165 | email: 'ccheng@MyGreatCorporation.com', 166 | phonecell: '650 234 8245', 167 | city: 'Sunnyvalle', 168 | state: 'CA', 169 | country: 'US', 170 | category: '4' 171 | }]; 172 | 173 | if(typeof module === "object" && typeof module.exports === "object"){ 174 | module.exports = uiModels.contact_data; 175 | } 176 | -------------------------------------------------------------------------------- /js/view-one/one-browse.js: -------------------------------------------------------------------------------- 1 | /*! *************************************************************************** 2 | * 3 | * evolutility-ui-jquery :: one-browse.js 4 | * 5 | * View "one browse" to browse one model in readonly mode. 6 | * 7 | * https://github.com/evoluteur/evolutility-ui-jquery 8 | * (c) 2017 Olivier Giulieri 9 | * 10 | *************************************************************************** */ 11 | 12 | Evol.ViewOne.Browse = Evol.View_One.extend({ 13 | 14 | viewName: 'browse', 15 | editable: false, 16 | icon: 'eye-open', // glyphicon-eye-open 17 | prefix: 'ovw', 18 | 19 | getData: function () { 20 | // TODO make JSON obj w/ model limited to fields in uimodel? 21 | return {}; 22 | }, 23 | 24 | setData: function (model) { 25 | if(!_.isUndefined(model) && model!==null){ 26 | var that=this, 27 | uii=Evol.DOM.input, 28 | fts = Evol.Def.fieldTypes, 29 | fieldHTML_ReadOnly = Evol.Dico.fieldHTML_RO, 30 | $f, fv, 31 | prefix='#'+ that.prefix + '-', 32 | subCollecs=this.getSubCollecs(), 33 | iconsPath=this.iconsPath||''; 34 | _.each(this.getFields(), function (f) { 35 | $f=that.$(prefix + f.id); 36 | if(f.value){ 37 | fv=f.value(model); 38 | }else{ 39 | fv=model.get(f.attribute || f.id); 40 | } 41 | if(model){ 42 | switch(f.type){ 43 | case fts.lov: 44 | case fts.list: 45 | case fts.bool: 46 | case fts.email: 47 | case fts.url: 48 | case fts.html: 49 | $f.html(fieldHTML_ReadOnly(f, fv, Evol.hashLov, iconsPath)); 50 | break; 51 | case fts.formula: 52 | $f.html(f.formula?f.formula(model):''); 53 | break; 54 | case fts.pix: 55 | $f.html((fv)?(''):('

'+Evol.i18n.nopix+'

')); 56 | break; 57 | case fts.color: 58 | $f.html(uii.colorBox(f.id, fv, fv)); 59 | break; 60 | case fts.textml: 61 | if(fv){ 62 | $f.html(_.escape(fv).replace(/[\r\n]/g, '
')); 63 | }else{ 64 | $f.html(''); 65 | } 66 | break; 67 | case fts.json: 68 | $f.val(Evol.Format.jsonString(fv, false)); 69 | break; 70 | default: 71 | $f.text(fieldHTML_ReadOnly(f, fv, Evol.hashLov, iconsPath) || ' '); 72 | } 73 | } 74 | }); 75 | if(subCollecs){ 76 | _.each(subCollecs, function (sc) { 77 | var h=[]; 78 | that._renderPanelListBody(h, sc, fv, 'browse'); 79 | that.$('[data-pid="'+sc.id+'"] tbody') 80 | .html(h.join('')); 81 | }); 82 | } 83 | } 84 | return this.setTitle(); 85 | }, 86 | 87 | clear: function () { 88 | var that=this, 89 | $f, 90 | fts = Evol.Def.fieldTypes, 91 | prefix='#'+ that.prefix + '-', 92 | subCollecs=this.getSubCollecs(); 93 | 94 | this.clearMessages(); 95 | _.each(this.getFields(), function (f) { 96 | $f=that.$(prefix + f.id); 97 | switch(f.type) { 98 | case fts.bool: 99 | $f.prop('checked', f.defaultValue?'checked':false); 100 | break; 101 | case fts.pix: 102 | // TODO 103 | 104 | break; 105 | default: 106 | $f.html(f.defaultValue || ''); 107 | } 108 | }); 109 | if(subCollecs){ 110 | _.each(subCollecs, function (sc) { 111 | that.$('[data-pid="'+sc.id+'"] tbody') 112 | .html(that._TRnodata(sc.elements.length, 'browse')); 113 | }); 114 | } 115 | return this; 116 | }, 117 | 118 | _renderButtons: function (h) { 119 | h.push(Evol.DOM.html.clearer+ 120 | '
'+ 121 | Evol.DOM.button('cancel', Evol.i18n.tools.bCancel, 'btn-default')+ 122 | Evol.DOM.button('edit', Evol.i18n.tools.bEdit, 'btn-primary')+ 123 | '
'); 124 | } 125 | 126 | }); 127 | -------------------------------------------------------------------------------- /models/winecellar.data.js: -------------------------------------------------------------------------------- 1 | var uiModels = uiModels || {}; 2 | uiModels.winecellar_data = [ 3 | { 4 | name: "Macrostie", 5 | label_img: "wine/macrostie.gif", 6 | vintage: 2008, 7 | winery: "Mc Williams", 8 | bsize: 1, 9 | type: 1, 10 | price: 20, 11 | grape: 1, 12 | country: 18, 13 | region: "Sonoma", 14 | buying_date: "2008-05-12", 15 | value: 24, 16 | purchased: 24, 17 | remaining: 16, 18 | drink_from: 2009, 19 | drink_to: 2020, 20 | peak_from: 2014, 21 | peak_to: 2017, 22 | degustations: [ 23 | { 24 | "ddate": "2008-05-08", 25 | "robe": "light", 26 | "nose": "fruity", 27 | "taste": "fruity", 28 | "notes": "too young" 29 | }, 30 | { 31 | "ddate": "2011-03-10", 32 | "robe": "light", 33 | "nose": "light fruit", 34 | "taste": "", 35 | "notes": "" 36 | }, 37 | { 38 | "ddate": "2012-12-12", 39 | "robe": "light", 40 | "nose": "light fruit", 41 | "taste": "", 42 | "notes": "Great" 43 | } 44 | ] 45 | }, 46 | { 47 | name: "Château d'Yquem", 48 | label_img: 'wine/yquem.gif', 49 | vintage: 2012, 50 | winery:'Lur Saluces', 51 | bsize: 1, 52 | type: 2, 53 | grape: 59, 54 | buying_date: "2012-12-12", 55 | price: 399, 56 | value: 460, 57 | drink_from: 2012, 58 | drink_to: 2017, 59 | purchased: 3, 60 | remaining: 1, 61 | country: 7, 62 | region: "Bordeaux", 63 | area:'Sauternes and Barsac', 64 | score_parker: 92, 65 | score_winespectator: 94, 66 | degustations: [ 67 | { 68 | ddate: '2013-04-23', 69 | robe: 'golden', 70 | nose: 'fruity', 71 | taste: 'incredible' 72 | }, 73 | { 74 | ddate: '2013-05-12', 75 | robe: 'clear', 76 | nose: 'strong and sweet', 77 | taste: 'outstanding' 78 | } 79 | ] 80 | }, 81 | { 82 | name: 'Château St Jean', 83 | label_img: 'wine/stjean.gif', 84 | vintage: 2008, 85 | winery:'Ch St Jean', 86 | bsize: 1, 87 | type: 1, 88 | price: 34, 89 | value: 32, 90 | purchased: 12, 91 | remaining: 5, 92 | drink_from: 2009, 93 | grape: 'shiraz', 94 | country: 7, 95 | score_parker: 68, 96 | score_winespectator: 72, 97 | degustations: [ 98 | { 99 | ddate: '2013-24-12', 100 | robe: 'thick', 101 | nose: 'strong', 102 | taste: 'good', 103 | notes:'Great w/ beef.' 104 | } 105 | ] 106 | }, 107 | { 108 | name: 'Vine Cliff', 109 | label_img: 'wine/vinecliff.gif', 110 | vintage: 2013, 111 | winery:'Vine Cliff', 112 | bsize: 1, 113 | type: 1, 114 | buying_date: "2013-05-05", 115 | price: 28, 116 | drink_from: 2014, 117 | grape: 3, 118 | country: 18, 119 | score_parker: 67, 120 | score_winespectator: 62, 121 | degustations: [ 122 | { 123 | ddate: '2013-05-05', 124 | robe: 'light', 125 | nose: 'strong', 126 | taste: 'good' 127 | }, 128 | { 129 | ddate: '2013-08-05', 130 | robe: 'light', 131 | nose: 'strong', 132 | taste: 'good' 133 | }, 134 | { 135 | ddate: '2013-08-18', 136 | robe: 'light', 137 | nose: 'strong', 138 | taste: 'ok' 139 | } 140 | ] 141 | }, 142 | { 143 | name: 'Château Montelena', 144 | label_img: 'wine/montelena.gif', 145 | vintage: 2005, 146 | winery:'Château Montelena', 147 | bsize: 4, 148 | grape: 3, 149 | type: 1, 150 | drink_from: 2005, 151 | region:'California', 152 | price: 62, 153 | value: 32, 154 | purchased: 12, 155 | remaining: 8, 156 | country: 18, 157 | score_parker: 64, 158 | score_winespectator: 64, 159 | degustations: [ 160 | { 161 | ddate: '2012-05-05', 162 | nose: 'strong+', 163 | taste: 'excellent' 164 | }, 165 | { 166 | ddate: '2013-10-22', 167 | robe: 'rich', 168 | nose: 'strong', 169 | taste: 'very good' 170 | } 171 | ] 172 | } 173 | ]; 174 | 175 | if(typeof module === "object" && typeof module.exports === "object"){ 176 | module.exports = uiModels.winecellar_data; 177 | } 178 | 179 | -------------------------------------------------------------------------------- /sass/header.scss: -------------------------------------------------------------------------------- 1 | // Evolutility-UI-jQuery :: header.css 2 | 3 | // https://github.com/evoluteur/evolutility-ui-jquery 4 | // (c) 2017 Olivier Giulieri 5 | 6 | /* --- header, navbar, content and footer --- */ 7 | 8 | @import "sass/variables"; 9 | 10 | $width-toolbar-left: 170px; 11 | $width-toolbar-top: 620px; 12 | 13 | // --- top navbar --- 14 | .evo-logo{ 15 | float:left; 16 | line-height: 30px; 17 | font-size: 2em; 18 | margin: 10px 80px 20px 10px; 19 | 20 | >a{ 21 | line-height: 24px; 22 | text-decoration: none; 23 | color: #ffc107 !important; 24 | &:hover{ 25 | color:$color-cool !important; 26 | >span{ 27 | color:#ffc107; 28 | } 29 | } 30 | 31 | >span{ 32 | color:white; 33 | } 34 | } 35 | 36 | @media print { 37 | a[href]:after { 38 | content: none !important; 39 | } 40 | } 41 | } 42 | .logop1,.logop3{ 43 | font-weight: bold; 44 | color:white; 45 | } 46 | .logop2{ 47 | font-weight: bold; 48 | color: #ed991a; 49 | } 50 | 51 | .evo-header{ 52 | position: absolute; // fixed; 53 | top:0; 54 | left:0; 55 | //opacity: .9; 56 | overflow: none; 57 | background-color: $color-navbar; 58 | //border-bottom: #366092 solid 1px; 59 | min-height: 75px; 60 | width:100%; 61 | min-width: $width-toolbar-top; 62 | padding:2px 5px 2px 10px; 63 | z-index: 1001; 64 | //-webkit-box-shadow: 0 0 12px rgba(0, 0, 0, 0.5); 65 | //-moz-box-shadow: 0 0 12px rgba(0, 0, 0, 0.5); 66 | //box-shadow: 0 0 12px rgba(0, 0, 0, 0.5); 67 | 68 | a{ 69 | color:$color-header-link; 70 | text-decoration: none; 71 | 72 | &:hover{ 73 | color:$color-header-link; 74 | } 75 | } 76 | 77 | @media only screen and (min-width: $screen2) { 78 | position: fixed; 79 | width:$width-toolbar-left; 80 | min-width:$width-toolbar-left; 81 | height:100%; 82 | } 83 | 84 | } 85 | 86 | .evo-head-links, 87 | .evo-head-links2{ 88 | display: block; 89 | display: flex; 90 | flex-wrap: wrap; 91 | flex-direction: column; 92 | @media only screen and (max-width: $screen2) { 93 | flex-direction: row; 94 | } 95 | >div{ 96 | margin-left:10px; 97 | } 98 | >li{ 99 | display: inline; 100 | padding:0 10px; 101 | } 102 | a{ 103 | text-decoration: none; 104 | &:hover{ 105 | color:$color-header-link-hover; 106 | } 107 | &.sel{ 108 | color: white; 109 | } 110 | } 111 | @media print{ 112 | display: none; 113 | } 114 | } 115 | .evo-link2{ 116 | li li{ 117 | margin-left:-12px; 118 | } 119 | @media only screen and (max-width: $screen2) { 120 | margin-left: 30px; 121 | order: 100; 122 | width:100%; 123 | li ul{ 124 | display: none; 125 | } 126 | } 127 | } 128 | .evo-head-links2 { 129 | .sel{ 130 | color: #ffc107; 131 | } 132 | } 133 | .evo-head-links{ 134 | font-size: 1.5em; 135 | margin-top:5px; 136 | margin-left:-40px; 137 | >li.spaced{ 138 | margin-top:50px; 139 | @media only screen and (max-width: $screen2) { 140 | margin-top:0; 141 | margin-left:30px; 142 | } 143 | } 144 | } 145 | 146 | .evo-head-links2{ 147 | font-size: .7em; 148 | margin: 0 5px 0 -40px; 149 | @media only screen and (min-width: $screen2) { 150 | margin: 0 0 10px; 151 | padding:0; 152 | >li{ 153 | display:block; 154 | } 155 | } 156 | } 157 | 158 | // --- page title --- 159 | .evo-title,.evo-title2{ 160 | background-color: $color-navbar; 161 | position: absolute; //fixed; 162 | z-index: 1002; // above bootstrap dropdown 163 | width: 100%; 164 | overflow: hidden; 165 | >h1{ 166 | margin-left: 16px; 167 | color:white; 168 | font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; 169 | font-weight: $weight-label; 170 | } 171 | @media only screen and (min-width: $screen2) { 172 | width: calc(100% - 170px); 173 | top:0 !important; 174 | margin-left: $width-toolbar-left; 175 | //background-color: white; 176 | >h1{ 177 | margin-left: 0; 178 | // color: $color-text; 179 | } 180 | } 181 | } 182 | 183 | .evo-title{ 184 | top: 65px; 185 | padding:20px 10px; 186 | min-height: 120px; 187 | } 188 | .evo-title2{ 189 | top: 65px; 190 | padding:5px 10px; 191 | z-index: 1001; 192 | } 193 | 194 | // --- content --- 195 | .evo-content{ 196 | padding: 85px 30px 30px; 197 | margin-top: 10px; 198 | @media only screen and (min-width: $screen2) { 199 | margin-left: $width-toolbar-left; 200 | padding-top: 10px; 201 | } 202 | } 203 | .evo-content2{ 204 | padding: 150px 30px 30px; 205 | margin-top: 10px; 206 | } 207 | 208 | @media only screen and (min-width: $screen2) { 209 | .evo-content2{ 210 | margin-left: $width-toolbar-left; 211 | padding-top: 85px; 212 | } 213 | //.evo-anchor{ 214 | // top:-65px !important; 215 | //} 216 | } 217 | //.evo-anchor{ 218 | //position:relative; 219 | //top:-140px; 220 | //} 221 | 222 | $height-footer: 120px; 223 | .evo-page{ 224 | min-height: 100%; 225 | margin-bottom: -$height-footer; 226 | &:after { 227 | content: ""; 228 | display: block; 229 | } 230 | } 231 | 232 | // --- footer --- 233 | .footer{ 234 | padding-top:80px; 235 | height:$height-footer; 236 | text-align: center; 237 | font-size:smaller; 238 | color:$color-text-footer; 239 | a{ 240 | color:$color-text-footer; 241 | } 242 | } 243 | -------------------------------------------------------------------------------- /models/comics.js: -------------------------------------------------------------------------------- 1 | var uiModels = uiModels || {}; 2 | 3 | uiModels.comics = { 4 | id: 'comics', 5 | label: 'Graphic Novels', 6 | name: 'serie', 7 | namePlural: 'series', 8 | icon: 'comics.png', 9 | fnTitle: 'title', 10 | fnSearch: ['title', 'authors', 'notes'], 11 | fnBadge: function(m){ 12 | if(m){ 13 | var hNb=m.get('have_nb'), 14 | sNb=m.get('serie_nb'); 15 | return (hNb==sNb)?hNb:(hNb||'-')+'/'+(sNb||'-'); 16 | } 17 | return ''; 18 | }, 19 | elements: [ 20 | { 21 | type: 'panel', label: 'Serie', width: 70, 22 | elements: [ 23 | { 24 | id: 'title', attribute: 'title', type: 'text', label: 'Title', required: true, 25 | maxLength: 255, 26 | width: 100, inMany: true 27 | }, 28 | { 29 | id: 'authors', attribute: 'authors', type: 'text', width: 62, inMany: true, 30 | label: 'Authors' 31 | }, 32 | { 33 | id: 'genre', attribute: 'genre', type: 'lov', label: 'Genre', width: 38, inMany: true, 34 | list: [ 35 | {id: 1, text: 'Adventure'}, 36 | {id: 2, text: 'Fairy tale'}, 37 | {id: 4, text: 'Fantastic'}, 38 | {id: 5, text: 'Heroic Fantasy'}, 39 | {id: 6, text: 'Historic'}, 40 | {id: 7, text: 'Humor'}, 41 | {id: 9, text: 'Youth'}, 42 | {id: 10, text: 'Thriller'}, 43 | {id: 11, text: 'Science-fiction'}, 44 | {id: 12, text: 'Super Heros'}, 45 | {id: 13, text: 'Western'} 46 | ] 47 | }, 48 | { 49 | id: 'serie_nb', attribute: 'serie_nb', type: 'integer', width: 15, inMany: false, 50 | label: 'Albums', inCharts:false 51 | }, 52 | { 53 | id: 'have_nb', attribute: 'have_nb', type: 'integer', width: 15, inMany: false, 54 | label: 'Owned', inCharts:false 55 | }, 56 | { 57 | id: 'have', attribute: 'have', type: 'text', width: 32, inMany: false, 58 | label: 'Have' 59 | }, 60 | { 61 | id: 'complete', attribute: 'complete', type: 'boolean', width: 19, inMany: true, 62 | label: 'Complete', labelFalse:'Incomplete', labelTrue:'Complete' 63 | }, 64 | { 65 | id: 'finished', attribute: 'finished', type: 'boolean', width: 19, inMany: true, 66 | label: 'Finished', labelTrue:'Finished', labelFalse:'Not finished', css:'cBlue' 67 | }, 68 | 69 | { 70 | id: 'language', attribute: 'language', type: 'lov', label: 'Language', width: 30, inMany: true, 71 | list: [ 72 | {id: 2, text: 'French', icon:'flag_fr.gif'}, 73 | {id: 1, text: 'American', icon:'flag_us.gif'} 74 | ] 75 | }, 76 | { 77 | id:'amazon', label:'Amazon', type:'formula', width:32, css:'evol-ellipsis', 78 | formula:function(m){ 79 | if(m){ 80 | var urlData=m.get('title')+' '+(m.get('authors')||''), 81 | link=m.get('language')=='FR' ? 82 | 'http://www.amazon.fr/s/ref=sr_nr_n_1?keywords=' 83 | :'http://www.amazon.com/s/ref=nb_sb_noss?field-keywords='; 84 | return ''+_.escape(urlData)+''; 85 | } 86 | return 'N/A'; 87 | } 88 | }, 89 | { 90 | id:'bdfugue', label:'BDFugue', type:'formula', width:38, css:'evol-ellipsis', 91 | formula:function(m){ 92 | if(m){ 93 | var urlData=m.get('title')+' '+(m.get('authors')||''), 94 | link='http://www.bdfugue.com/catalogsearch/result/?q='; 95 | return ''+_.escape(urlData)+''; 96 | } 97 | return 'N/A'; 98 | } 99 | }, 100 | { 101 | id: 'notes', attribute: 'notes', type: 'textmultiline', label: 'Notes', maxLength: 1000, 102 | width: 100, height: 7, inMany: false 103 | } 104 | ] 105 | }, 106 | { 107 | type: 'panel', label: 'Cover', width: 30, 108 | elements: [ 109 | { 110 | id: 'pix', attribute: 'pix', type: 'image', width: 100, inMany: true, 111 | label: 'Album Cover', labelList:'Cover', labelBrowse:'', labelCards:'' 112 | } 113 | ] 114 | } 115 | ] 116 | }; 117 | 118 | if(typeof module === "object" && typeof module.exports === "object"){ 119 | module.exports = uiModels.comics; 120 | } 121 | -------------------------------------------------------------------------------- /js/view-many/many-cards.js: -------------------------------------------------------------------------------- 1 | /*! *************************************************************************** 2 | * 3 | * evolutility-ui-jquery :: many-cards.js 4 | * 5 | * View "many cards" to show a collection as many cards. 6 | * 7 | * https://github.com/evoluteur/evolutility-ui-jquery 8 | * (c) 2017 Olivier Giulieri 9 | * 10 | *************************************************************************** */ 11 | 12 | Evol.ViewMany.Cards = Evol.View_Many.extend({ 13 | 14 | viewName: 'cards', 15 | // TODO icon should be different than view Mini 16 | icon: 'th-large', // glyphicon-th-large 17 | 18 | events: _.extend({ 19 | 'mouseenter .evol-cards-body>div': 'enterItem', 20 | 'mouseleave .evol-cards-body>div': 'leaveItem' 21 | }, Evol.ViewMany.eventsMany), 22 | 23 | fieldsetFilter: function (f) { 24 | return f.inMany || f.inCards; 25 | }, 26 | 27 | _render: function (models) { 28 | var pSize = this.pageSize || 50, 29 | pSummary = this.pageSummary(0, pSize, models.length); 30 | 31 | this.$el.html('
'+ 32 | this._HTMLbody(this.getFields(), pSize, this.uiModel.icon, 0, this.selectable)+ 33 | '
'+Evol.DOM.html.clearer+ 34 | this._HTMLpagination(0, pSize, models.length)+ 35 | '
'+pSummary+'
'+ 36 | '
'); 37 | return this; 38 | }, 39 | 40 | _$body: function(){ 41 | return this.$('.evol-cards-body'); 42 | }, 43 | 44 | HTMLItem: function(h, fields, model, icon, selectable, route, isTooltip){ 45 | var that = this, 46 | v, 47 | fts = Evol.Def.fieldTypes, 48 | link = (this.links!==false), 49 | domInput = Evol.DOM.input; 50 | 51 | if(isTooltip){ 52 | h.push('
'); 53 | }else{ 54 | h.push('
'); 55 | } 56 | _.each(fields, function(f, idx){ 57 | if(f.type===fts.color) { 58 | v = model.escape(f.attribute || f.id); 59 | v = domInput.colorBox(f.id, v, v); 60 | }else if(f.type==='formula'){ 61 | v = domInput.formula(null, f, model); 62 | }else if(f.type==='image' && !isTooltip){ 63 | v = ''+ 64 | that._HTMLField(f, model.escape(f.attribute || f.id))+ 65 | ''; 66 | }else if(f.type===fts.json){ 67 | v = model.get(f.attribute || f.id); 68 | }else{ 69 | v = that._HTMLField(f, model.escape(f.attribute || f.id)); 70 | } 71 | if (idx === 0) { 72 | h.push('
'); 73 | // Item badge 74 | var bf=that.uiModel.fnBadge; 75 | if(bf){ 76 | h.push(''); 77 | if(_.isFunction(bf)){ 78 | h.push(bf(model)); 79 | }else if(_.isString(bf)){ 80 | h.push(model.escape(bf)); 81 | } 82 | h.push(''); 83 | } 84 | // Item title 85 | h.push('

'+(selectable?that._HTMLCheckbox(model.id):'')+ 86 | Evol.Dico.fieldLink(null, f, v, icon, !link, route?route+model.id:null)+ 87 | '

'); 88 | }else{ 89 | var label2 = f.labelCards, 90 | css2=(f.type==fts.email || f.type==fts.url?'evol-ellipsis"':''); 91 | if(label2===''){ 92 | css2 += (f.type==fts.pix?'evol-c-center"':''); 93 | h.push(''+v+'
'); 94 | }else { 95 | if(!label2){ 96 | label2 = f.labelMany || f.label; 97 | } 98 | h.push('
'+v+'
'); 99 | } 100 | } 101 | }); 102 | h.push('
'); 103 | return this; 104 | }, 105 | 106 | /* customize: function () { 107 | var labels = this.$('h4 > a.evol-nav-id'); 108 | if(this._custOn){ 109 | labels.find('i').remove(); 110 | this._custOn=false; 111 | }else{ 112 | labels.append(Evol.DOM.iconCustomize('id','field')); 113 | this._custOn=true; 114 | } 115 | return this; 116 | }*/ 117 | 118 | enterItem: Evol.ViewMany.actionEvents.enterItem(Evol.ViewMany.menuOne), 119 | 120 | leaveItem: Evol.ViewMany.actionEvents.leaveItem, 121 | 122 | clickAction: function(evt){ 123 | var that = this, 124 | e = $(evt.currentTarget), 125 | aid = e.data('id'), 126 | id = e.parent().siblings().eq(0).data('mid'), 127 | p = e.closest('.panel'); 128 | 129 | if(aid==='edit'){ 130 | this.$el.trigger('navigate', {id: id, view: aid}); 131 | }else{ 132 | this.$el.trigger('action', { 133 | id: aid, 134 | mid: id, 135 | title: Evol.Dico.getItemTitle(p), 136 | skipWarning: evt.shiftKey, 137 | fnSuccess: function(escape){ 138 | p.fadeOut(500, function(){ 139 | p.remove(); 140 | that.$el.trigger('status', that.pageSummary()); 141 | }); 142 | } 143 | }); 144 | } 145 | } 146 | 147 | }); 148 | 149 | -------------------------------------------------------------------------------- /js/view-one/one-wizard.js: -------------------------------------------------------------------------------- 1 | /*! *************************************************************************** 2 | * 3 | * evolutility-ui-jquery :: one-wizard.js 4 | * 5 | * View "one wizard" to edit one backbone model using a wizard (one step for each panel in the ui-model). 6 | * 7 | * https://github.com/evoluteur/evolutility-ui-jquery 8 | * (c) 2017 Olivier Giulieri 9 | * 10 | *************************************************************************** */ 11 | 12 | Evol.ViewOne.Wizard = function(){ 13 | 14 | var dom = Evol.DOM; 15 | 16 | return Evol.View_One.extend({ 17 | 18 | viewName: 'wizard', 19 | prefix: 'wiz', 20 | 21 | events:{ 22 | 'click .evo-wiz-bsteps>div,.evo-wiz-buttons>button':'click_nav', 23 | 'click label > .glyphicon-question-sign': 'click_help', 24 | 'click [data-id="bPlus"],[data-id="bMinus"]':'click_detailsAddDel' 25 | }, 26 | 27 | stepIndex: function(stepIdx){ 28 | if(_.isUndefined(stepIdx)){ 29 | return this._stepIdx; 30 | }else if(stepIdx0){ 44 | steps.hide() 45 | .eq(--this._stepIdx).show(); 46 | }else if(bId==='next' && this._stepIdx'); 75 | _.each(elems, function(p, idx){ 76 | h.push('
  • ', idx+1,'
    ', p.label, '
  • '); 85 | }); 86 | h.push(''); 87 | return this; 88 | }, 89 | 90 | _renderPanels: function (h, elems, mode) { 91 | // WIZARD forms 92 | var that=this; 93 | h.push('
    '); 94 | _.each(elems, function(pnl, idx){ 95 | if(!pnl.id){ 96 | pnl.id='p'+idx; 97 | } 98 | switch (pnl.type) { 99 | case 'panel': 100 | that._renderPanel(h, pnl, mode, idx===0); 101 | break; 102 | case 'panel-list': 103 | that._renderPanelList(h, pnl, mode, idx===0); 104 | break; 105 | } 106 | }); 107 | h.push('
    '); 108 | return this; 109 | }, 110 | 111 | _renderButtons: function (h) { 112 | var bLabel=Evol.i18n.tools, 113 | b=dom.button; 114 | h.push(dom.html.clearer, 115 | '
    ', 116 | b('prev', bLabel.prev, 'btn-default disabled'), 117 | b('next', bLabel.next, 'btn-primary'), 118 | b('finish', bLabel.finish, 'btn-default'), 119 | '
    '); 120 | return this; 121 | }, 122 | 123 | click_nav: function(evt){ 124 | var bId=$(evt.currentTarget).data('id'); 125 | this.clearMessages(); 126 | if(bId==='finish'){ 127 | var v=this.validate(); 128 | if(v===''){ 129 | //TODO what? got ot OneView.View 130 | this.$el.trigger('action', 'save'); 131 | }else{ 132 | this.sendMessage(Evol.i18n.validation.incomplete, v, 'warning'); 133 | } 134 | }else{ 135 | var stepIdx=parseInt(bId,10); 136 | this._showStep(stepIdx, bId); 137 | } 138 | this._refreshBreadcrumb(); 139 | }, 140 | 141 | _getButtons: function(){ 142 | if(_.isUndefined(this._buttons)){ 143 | var bh=this.$('.evo-wiz-buttons>button'); 144 | this._buttons = {}; 145 | for(var i=0;idiv>div'); 156 | _.each(divs, function(d, idx){ 157 | if(idx>stepIdx){ 158 | $(d).attr('class', 'badge future'); 159 | }else if(idx .panel{ 39 | margin-bottom: 12px; 40 | } 41 | > div > fieldset{ 42 | padding: 10px 10px 5px 2px; 43 | } 44 | } 45 | } 46 | 47 | .evo-plist{ 48 | overflow-x: auto; 49 | input{ 50 | &[type="date"]{ 51 | max-width: 160px; 52 | } 53 | &[type="number"]{ 54 | min-width: 100px; 55 | } 56 | &[type="text"]{ 57 | min-width: 120px; 58 | } 59 | } 60 | textarea{ 61 | min-width: 120px; 62 | } 63 | select{ 64 | min-width: 120px; 65 | } 66 | 67 | .table{ 68 | margin-bottom: 0; 69 | } 70 | } 71 | 72 | .panel-heading { // panel-heading from Bootstrap 73 | >.panel-title{ // panel-title from Bootstrap 74 | display: inline-block; 75 | } 76 | >.evol-subtitle{ 77 | display: inline-block; 78 | margin-left:.4em; 79 | } 80 | } 81 | 82 | .evo-panel-help{ 83 | margin-top:5px; 84 | } 85 | .evol-tabs{ 86 | margin: 0 10px 10px !important; 87 | >li>a{ 88 | transition: all 0.6s ease; 89 | } 90 | } 91 | 92 | /* --- fields --- */ 93 | .evol-fset{ 94 | @include flex-holder; 95 | padding: 10px 10px 5px 0; 96 | //input[type="checkbox"]{ 97 | // height: 30px; 98 | //} 99 | } 100 | .evol-fld{ 101 | @include flex-item; 102 | padding-left:10px !important; 103 | margin-bottom: 6px; 104 | > .evo-rdonly{ 105 | // todo: use or remove line below? 106 | // border-bottom: 1px solid silver; 107 | > img{ 108 | position: relative; 109 | top: -2px; 110 | margin-right: 3px; 111 | } 112 | } 113 | > .text-danger{ 114 | margin-bottom: 0 !important; 115 | } 116 | } 117 | label { 118 | color:$color-label; 119 | font-size: 14px; 120 | font-weight: 300; 121 | } 122 | 123 | .evol-field-label > label { 124 | color:$color-label; 125 | font-size: 14px; 126 | font-weight: 300; 127 | 128 | > .glyphicon-question-sign{ 129 | cursor: pointer; 130 | padding-left: 4px; 131 | color: silver; 132 | 133 | &:hover{ 134 | color:$color-icon-hover; 135 | } 136 | } 137 | } 138 | 139 | .evol-required, 140 | .evol-asterix{ 141 | margin-left:3px; 142 | font-weight:bold; 143 | } 144 | .evol-required{ 145 | color:#b94a48; 146 | } 147 | .evol-asterix{ 148 | color:#0099cc; 149 | } 150 | .evo-rdonly{ 151 | min-height: 32px; 152 | padding-top: 5px; 153 | } 154 | .evol-buttons{ 155 | clear:both; 156 | margin-top:0 !important; 157 | //background-color: $toolbar-background-color; 158 | > button{ 159 | margin:1em; 160 | } 161 | } 162 | 163 | .evol-ellipsis { 164 | @include ellipsis; 165 | } 166 | .evol-title-toggle{ 167 | cursor: pointer; 168 | float:right; 169 | } 170 | .evol-json{ 171 | width:100%; 172 | //height:350px; 173 | margin: 0 0 10px; 174 | } 175 | .evo-p-json{ 176 | margin-bottom:10px; 177 | fieldset{ 178 | padding:10px !important; 179 | } 180 | } 181 | .glyphicon-wrench{ 182 | margin-left: 5px; 183 | display: inline !important; 184 | } 185 | 186 | /* bootstrap customizations*/ 187 | .table > thead > tr > th{ 188 | font-weight: $weight-label; 189 | background-color: #fbfbfb; 190 | } 191 | .evol-fset label{ 192 | margin-bottom: 2px; 193 | } 194 | .help-block{ 195 | padding:2px 5px; 196 | background-color: #FFF8E1; 197 | border: 1px solid #FFECB3; 198 | @include b-radius(2px); 199 | } 200 | .evol-mini-holder, 201 | .evolw-edit { 202 | .help-block{ 203 | color: #737373 !important; 204 | clear: both; 205 | } 206 | } 207 | 208 | .evo-one-edit, 209 | .evo-one-browse, 210 | .evo-one-wiz{ 211 | margin-left:-10px; 212 | } 213 | 214 | .evol-pl-nodata{ 215 | text-align: center; 216 | 217 | [data-id="bPlus"]{ 218 | margin-left:10px; 219 | cursor: pointer; 220 | } 221 | } 222 | 223 | .evo-td-plusminus{ 224 | 225 | width:70px; 226 | min-width:70px; 227 | 228 | > div{ 229 | float:left; 230 | margin-top: 10px; 231 | margin-left:10px; 232 | cursor: pointer; 233 | color: $color-icon; 234 | &:hover{ 235 | color: $color-icon-hover; 236 | } 237 | } 238 | > div:last-child:after { 239 | clear:left; 240 | } 241 | 242 | } 243 | 244 | .evo-msg{ 245 | &.alert-warning{ 246 | padding: 10px 10px 3px; 247 | >.close{ 248 | top:0 !important; 249 | right:0 !important; 250 | } 251 | } 252 | ul{ 253 | margin-top:10px; 254 | } 255 | } 256 | 257 | #isDirty [data-id="nosave"]{ 258 | float: left; 259 | } 260 | 261 | .evo-color-box{ 262 | display: inline-block; 263 | height:20px; 264 | width:20px; 265 | border: solid 1px silver; 266 | span{ 267 | margin-left:24px; 268 | } 269 | } 270 | .badge-one{ 271 | position: relative; 272 | top: -14px; 273 | font-size: .5em; 274 | margin-left: 5px; 275 | } 276 | 277 | .w-100{ 278 | width:100% 279 | } 280 | .w-62{ 281 | width:62% 282 | } 283 | .w-38{ 284 | width:38% 285 | } 286 | 287 | // -- select2 288 | .evo-f-list > div{ 289 | margin: 0 5px 0 0; 290 | padding: 2px 4px!important; 291 | border: 1px solid silver; 292 | margin-bottom:5px; 293 | } 294 | .evo-f-list > div, 295 | .select2-search-choice{ 296 | display: inline-block; 297 | background-image: none !important; 298 | background-color: aliceblue !important; 299 | } 300 | .select2-search-choice{ 301 | padding: 5px 10px 5px 20px !important; 302 | } 303 | .evol-many-list .evo-f-list > div{ 304 | font-size: 15px; 305 | } 306 | .evol-cards-body .evo-f-list > div{ 307 | margin-bottom:5px; 308 | } 309 | -------------------------------------------------------------------------------- /js/view-many/many-list.js: -------------------------------------------------------------------------------- 1 | /*! *************************************************************************** 2 | * 3 | * evolutility-ui-jquery :: many-list.js 4 | * 5 | * View "many list" to display a collection as a list (table w/ sorting and paging). 6 | * 7 | * https://github.com/evoluteur/evolutility-ui-jquery 8 | * (c) 2017 Olivier Giulieri 9 | * 10 | *************************************************************************** */ 11 | 12 | Evol.ViewMany.List = Evol.View_Many.extend({ 13 | 14 | viewName: 'list', 15 | icon: 'th-list', // glyphicon-th-list 16 | 17 | events: _.extend({ 18 | 'mouseenter tbody>tr': 'enterItem', 19 | 'mouseleave tbody>tr': 'leaveItem', 20 | 'click .evol-sort-icons>i': 'click_sort' 21 | }, Evol.ViewMany.eventsMany), 22 | 23 | fieldsetFilter: function (f) { 24 | return f.inMany || f.inList; 25 | }, 26 | 27 | _render: function (models) { 28 | var h = '', 29 | that = this, 30 | fields = this.getFields(), 31 | pSize = this.pageSize || 50, 32 | link = (this.links!==false); 33 | 34 | h+='
    '+ 35 | '
    '; 36 | if(this.selectable){ 37 | h+=''; 38 | } 39 | _.each(fields, function(field){ 40 | h+=that._HTMLlistHeader(field); 41 | }); 42 | h+=''+ 43 | this._HTMLbody(fields, pSize, this.uiModel.icon, 0, this.selectable)+ 44 | '
    '+this._HTMLCheckbox('cbxAll')+'
    '+ 45 | this._HTMLpagination(0, pSize, models.length)+ 46 | '
    '+this.pageSummary(this.pageIndex, pSize, models.length)+'
    '+ 47 | '
    '; 48 | this.$el.html(h); 49 | }, 50 | 51 | _$body: function(){ 52 | return this.$('.table > tbody'); 53 | }, 54 | 55 | HTMLItem: function(h, fields, model, icon, selectable, route){ 56 | var that = this, 57 | v, 58 | bf = that.uiModel.fnBadge, 59 | link = (this.links!==false), 60 | ft = Evol.Def.fieldTypes, 61 | input = Evol.DOM.input; 62 | 63 | h.push(''); 64 | if(selectable){ 65 | h.push(''+this._HTMLCheckbox(model.id)+''); 66 | } 67 | _.each(fields, function(f, idx){ 68 | if(f.type===ft.color){ 69 | v = input.colorBox(f.id, model.escape(f.attribute || f.id)); 70 | }else if(f.type===ft.formula){ 71 | v = input.formula(null, f, model); 72 | }else if(f.type===ft.json || f.type===ft.html){ 73 | v = model.get(f.attribute || f.id); 74 | //if(v && v.length>200){ 75 | //v = v.subString(0,200)+'...'; 76 | //} 77 | }else{ 78 | v = that._HTMLField(f, model.escape(f.attribute || f.id)); 79 | } 80 | if(idx===0){ 81 | v = Evol.Dico.fieldLink(null, f, v, icon, !link, route?route+model.id:null); 82 | // Item badge 83 | if(bf){ 84 | var badgeText; 85 | if(_.isFunction(bf)){ 86 | badgeText=bf(model)||''; 87 | }else if(_.isString(bf)){ 88 | badgeText=model.escape(bf)||''; 89 | } 90 | if(badgeText){ 91 | v+=''+badgeText+''; 92 | } 93 | } 94 | } 95 | var css=f.css || ''; 96 | if(f.type===ft.email || f.type===ft.url){ 97 | css+=' evol-ellipsis'; 98 | }else if(f.type===ft.pix){ 99 | css+=' evol-td-pix'; 100 | }else if(Evol.Def.fieldIsNumber(f)){ 101 | css+=' evol-r-align'; 102 | } 103 | h.push(''+v+''); 104 | }); 105 | h.push(''); 106 | }, 107 | 108 | _HTMLlistHeader: function (f) { 109 | var h=''+ 110 | (f.labelList || f.labelMany || f.label); 111 | if(f.sortable!==false){ 112 | h+=''+ 113 | Evol.DOM.icon('chevron-up')+//'sort-by-alphabet' 114 | Evol.DOM.icon('chevron-down')+//'sort-by-alphabet-alt' 115 | ''; 116 | } 117 | h+=''; 118 | return h; 119 | }, 120 | 121 | click_sort: function (evt) { 122 | var target = $(evt.currentTarget), 123 | fid = target.parent().data('fid'), 124 | f = this.getField(fid), 125 | down = target.attr('class').indexOf('-down') > 0; 126 | this.sortList(f, down); 127 | //target.addClass('evol-last-sort'); 128 | }, 129 | 130 | enterItem: Evol.ViewMany.actionEvents.enterItem( 131 | Evol.ViewMany.menuOne, 132 | function(e){ 133 | return e.children().eq(0); 134 | }, 135 | true 136 | ), 137 | 138 | leaveItem: Evol.ViewMany.actionEvents.leaveItem, 139 | 140 | clickAction: function(evt){ 141 | var that=this, 142 | e=$(evt.currentTarget), 143 | aid=e.data('id'), 144 | tr=e.closest('tr'), 145 | id=tr.data('mid'); 146 | 147 | if(aid==='edit'){ 148 | this.$el.trigger('navigate', {id: id, view: aid}); 149 | }else{ 150 | this.$el.trigger('action', { 151 | id: aid, 152 | mid: id, 153 | title: e.closest('tr').find('a>span').text(), 154 | skipWarning: evt.shiftKey, 155 | fnSuccess: function(escape){ 156 | tr.fadeOut(500, function(){ 157 | tr.remove(); 158 | that.$el.trigger('status', that.pageSummary()); 159 | }); 160 | } 161 | }); 162 | } 163 | } 164 | 165 | }); 166 | 167 | -------------------------------------------------------------------------------- /js/view-many/many-bubbles.js: -------------------------------------------------------------------------------- 1 | /*! *************************************************************************** 2 | * 3 | * evolutility-ui-jquery :: many-bubbles.js 4 | * 5 | * View "many bubbles" to show a Bubble Chart of a collection of many models. 6 | * 7 | * https://github.com/evoluteur/evolutility-ui-jquery 8 | * (c) 2017 Olivier Giulieri 9 | * 10 | *************************************************************************** */ 11 | 12 | Evol.ViewMany.Bubbles = Evol.View_Many.extend({ 13 | 14 | viewName: 'bubbles', 15 | icon: 'adjust', // glyphicon-adjust 16 | 17 | events: { 18 | //'click .evol-buttons>button': 'click_button', 19 | //'click .evol-title-toggle': 'click_toggle', 20 | //'click .glyphicon-wrench': 'click_customize', 21 | 'click .btn': 'clickGroup', 22 | 'change .bubble-group': 'changeGroup', 23 | 'change .bubble-color': 'changeColor', 24 | 'change .bubble-size': 'changeSize', 25 | 'click svg>circle': 'clickCircle' 26 | }, 27 | 28 | fieldsetFilter: Evol.Def.fieldChartable, 29 | 30 | setupBubbles: function() { 31 | var that=this, 32 | ui=this.uiModel, 33 | models = this.collection.models; 34 | 35 | if(!this._bubblesInitialized){ 36 | var flds = Evol.Def.getFields(this.uiModel, Evol.Def.fieldChartable), 37 | fd=flds.length?flds[0].id:null; 38 | this.bubbles = new Evol.Bubbles({ 39 | //selector:'.evol-bubbles-body', 40 | elem: this.$('.evol-bubbles-body').get(0), 41 | width:1200, 42 | height:700, 43 | fields: flds, 44 | colorFieldId: fd, 45 | groupFieldId: fd, 46 | sizeFieldId: null, 47 | uiModel: this.uiModel, 48 | tooltip: function(d){ 49 | var h=[], 50 | flds=that.getFields(); 51 | Evol.ViewMany.Cards.prototype.HTMLItem.call(that, h, flds, new Backbone.Model(d), null, null, null, true); 52 | return h.join(''); 53 | } 54 | }); 55 | this.bubbles.setData(_.map(models, function(m){ 56 | return _.extend({ 57 | id: m.id 58 | }, m.attributes); 59 | })); 60 | 61 | this._bubblesInitialized=true; 62 | } 63 | }, 64 | 65 | _render: function (models) { 66 | var dom = Evol.DOM, 67 | i18nTools = Evol.i18n.tools, 68 | hOpt = dom.input.option, 69 | hOptNull = dom.html.emptyOption, 70 | fo, 71 | fs2 = Evol.Def.getFields(this.uiModel, Evol.Def.fieldChartable), 72 | h = '
    '+ 73 | '
    '; 74 | //h+=this._HTMLbody(this.getFields(), pSize, this.uiModel.icon, 0, this.selectable); 75 | 76 | h+='
    '; 77 | if(fs2.length){ 78 | // --- Group --- 79 | h+=''; 80 | if(fs2.length>5){ 81 | fo=_.map(fs2, function(f, idx){ 82 | return hOpt(f.id, f.label, idx===0); 83 | }); 84 | h+=''; 85 | }else{ 86 | h+='
    '+ 87 | _.map(fs2, function(f, idx){ 88 | if(_.isUndefined(f.groupable) || f.groupable){ 89 | return ''; 91 | } 92 | }).join('')+ 93 | '
    '; 94 | } 95 | // --- Color --- 96 | fo=_.map(fs2, function(f, idx){ 97 | return (_.isUndefined(f.colorable) || f.colorable) ? hOpt(f.id, f.label, idx===0) : ''; 98 | }); 99 | h+=''; 100 | // --- Size --- 101 | fs2=_.filter(fs2, function(f){ 102 | return (_.isUndefined(f.sizable) || f.sizable) ? Evol.Def.fieldIsNumber(f) : ''; 103 | }); 104 | fo=_.map(fs2, function(f, idx){ 105 | return hOpt(f.id, f.label); 106 | }); 107 | if(fo.length){ 108 | h+=''; 109 | } 110 | //h+=dom.html.clearer; 111 | }else{ 112 | h+=Evol.i18n.notEnoughdata; 113 | } 114 | h+='
    '; 115 | this.$el.html(h); 116 | this.setupBubbles(); 117 | return this; 118 | }, 119 | 120 | _HTMLbody: function(){ 121 | 122 | }, 123 | 124 | _HTMLlegend: function(){ 125 | // todo 126 | }, 127 | 128 | _$body: function(){ 129 | return this.$('.evol-bubbles-body'); 130 | }, 131 | 132 | setCollection: function(collec){ 133 | this.collection = collec; 134 | this.bubbles.setData(_.map(collec.models, function(m){ 135 | return _.extend({ 136 | id: m.id 137 | }, m.attributes); 138 | })); 139 | return this; 140 | }, 141 | 142 | clickGroup: function(evt){ 143 | this.bubbles.changeBubblesGroup(evt.currentTarget.id); 144 | }, 145 | changeGroup: function(evt){ 146 | this.bubbles.changeBubblesGroup(evt.target.value); 147 | }, 148 | 149 | changeColor: function(evt){ 150 | this.bubbles.changeBubblesColor(evt.target.value); 151 | }, 152 | 153 | changeSize: function(evt){ 154 | this.bubbles.changeBubblesSize(evt.target.value); 155 | }, 156 | 157 | clickCircle: function(evt){ 158 | var id=$(evt.currentTarget).data('mid'); 159 | this.$el.trigger('click.bubble', {id:id}); 160 | window.location.href = '#'+ this.uiModel.id + '/browse/'+id; 161 | } 162 | 163 | }); 164 | 165 | -------------------------------------------------------------------------------- /models/comics.data.js: -------------------------------------------------------------------------------- 1 | var uiModels = uiModels || {}; 2 | uiModels.comics_data = [{ 3 | "title": "Do Androids Dream Of Electric Sheep?", 4 | "genre": 11, 5 | "authors": "Philip K Dick, Tony Parker", 6 | "complete": true, 7 | "finished": true, 8 | "have": "1-6", 9 | "have_nb": 6, 10 | "serie_nb": 6, 11 | "language": 1, 12 | "pix": "comics/androitsheep1.jpeg" 13 | }, 14 | { 15 | "title": "Saga", 16 | "genre": 11, 17 | "authors": "Brian K. Vaughan and Fiona Staples", 18 | "complete": false, 19 | "finished": false, 20 | "have": "1-5", 21 | "have_nb": 5, 22 | "serie_nb": 6, 23 | "language": 1, 24 | "pix": "comics/saga1.jpeg" 25 | }, 26 | { 27 | "title": "Alim le Tanneur", 28 | "genre": 5, 29 | "authors": "Wilfrid Lupano, Virginie Augustin", 30 | "complete": true, 31 | "finished": true, 32 | "have": "1-4", 33 | "have_nb": 4, 34 | "serie_nb": 4, 35 | "language": 2, 36 | "pix": "comics/alim1.jpg" 37 | }, 38 | { 39 | "title": "La Caste des Meta-Barons", 40 | "genre": 11, 41 | "authors": "Alexandro Jodorowsky et Juan Gimenez", 42 | "complete": false, 43 | "finished": true, 44 | "have": "1-5", 45 | "have_nb": 5, 46 | "serie_nb": 8, 47 | "language": 2, 48 | "pix": "comics/metabaron1.jpeg" 49 | }, 50 | { 51 | "title": "Garulfo", 52 | "genre": 7, 53 | "have": "1-6", 54 | "have_nb": 6, 55 | "serie_nb": 6, 56 | "language": 2, 57 | "authors": "Alain Ayroles et Bruno Maïorana", 58 | "complete": true, 59 | "finished": true, 60 | "pix": "comics/garulfo1.jpeg" 61 | }, 62 | { 63 | "title": "Lanfeust de Troy", 64 | "genre": 5, 65 | "authors": "Didier Tarquin, Christophe Arleston", 66 | "complete": true, 67 | "finished": true, 68 | "have": "1-8", 69 | "have_nb": 8, 70 | "serie_nb": 8, 71 | "language": 2, 72 | "pix": "comics/lanfeust1.jpeg" 73 | }, 74 | { 75 | "title": "Salammbo", 76 | "genre": 4, 77 | "authors": "Philippe Druillet et Gustave Flaubert", 78 | "complete": true, 79 | "finished": true, 80 | "have": "1-3", 81 | "have_nb": 3, 82 | "serie_nb": 3, 83 | "language": 2, 84 | "pix": "comics/salammbo1.jpeg" 85 | }, 86 | { 87 | "title": "Carmen McCallum", 88 | "genre": 11, 89 | "authors": "Fred Duval et Gess", 90 | "complete": false, 91 | "finished": false, 92 | "have": "1-5", 93 | "have_nb": 5, 94 | "serie_nb": 12, 95 | "language": 2, 96 | "pix": "comics/carmenmc1.jpeg" 97 | }, 98 | { 99 | "title": "Code McCallum", 100 | "genre": 11, 101 | "authors": "Fred Duval et Didier Cassegrain", 102 | "complete": true, 103 | "finished": true, 104 | "have": "5", 105 | "have_nb": 5, 106 | "serie_nb": 5, 107 | "language": 2, 108 | "pix": "comics/codemc1.jpeg" 109 | }, 110 | { 111 | "title": "La Nef des Fous", 112 | "genre": 7, 113 | "authors": "Turf", 114 | "complete": true, 115 | "finished": true, 116 | "have": "1-7", 117 | "have_nb": 7, 118 | "serie_nb": 7, 119 | "language": 2, 120 | "pix": "comics/neffous1.jpeg" 121 | }, 122 | { 123 | "title": "La Quete de l'Oiseau du Temps", 124 | "genre": 5, 125 | "authors": "Serge Le Tendre et Régis Loisel", 126 | "complete": true, 127 | "finished": true, 128 | "have": "1-4", 129 | "have_nb": 4, 130 | "serie_nb": 4, 131 | "language": 2, 132 | "pix": "comics/quete1.jpeg" 133 | }, 134 | { 135 | "title": "Le Lama Blanc", 136 | "genre": 1, 137 | "authors": "Alejandro Jodorowsky et Georges Bess", 138 | "complete": true, 139 | "finished": true, 140 | "have": "1-6", 141 | "have_nb": 6, 142 | "serie_nb": 6, 143 | "language": 2, 144 | "pix": "comics/lama1.jpeg" 145 | }, 146 | { 147 | "title": "Le Surfer d'Argent", 148 | "genre": 12, 149 | "authors": "Moebius, Stan Lee", 150 | "complete": true, 151 | "finished": true, 152 | "have": "1", 153 | "have_nb": 1, 154 | "serie_nb": 1, 155 | "language": 2, 156 | "pix": "comics/surfer.jpeg" 157 | }, 158 | { 159 | "title": "L'Incal", 160 | "genre": 11, 161 | "authors": "Moebius et Alexandro Jodorowsky", 162 | "complete": true, 163 | "finished": true, 164 | "have": "1-6", 165 | "have_nb": 6, 166 | "serie_nb": 6, 167 | "language": 2, 168 | "pix": "comics/incal1.jpeg" 169 | }, 170 | { 171 | "title": "Ou le regard ne porte pas", 172 | "genre": 1, 173 | "authors": "Pont et Abolin", 174 | "complete": true, 175 | "finished": true, 176 | "have": "1,2", 177 | "have_nb": 2, 178 | "serie_nb": 2, 179 | "language": 2, 180 | "pix": "comics/regard1.jpeg" 181 | }, 182 | { 183 | "title": "Péma Ling", 184 | "genre": 1, 185 | "authors": "Georges Bess", 186 | "complete": true, 187 | "finished": true, 188 | "have": "1-5", 189 | "have_nb": 5, 190 | "serie_nb": 5, 191 | "language": 2, 192 | "pix": "comics/pemaling1.jpeg" 193 | }, 194 | { 195 | "title": "Sky Doll", 196 | "genre": 4, 197 | "authors": "Alessandro Barbucci et Barbara Canepa", 198 | "complete": true, 199 | "finished": true, 200 | "have": "1-3", 201 | "have_nb": 3, 202 | "serie_nb": 3, 203 | "language": 2, 204 | "pix": "comics/skydoll1.jpeg" 205 | }, 206 | { 207 | "title": "Ronin", 208 | "genre": 11, 209 | "authors": "Franck Miller", 210 | "complete": true, 211 | "finished": true, 212 | "have": "1", 213 | "have_nb": 1, 214 | "serie_nb": 1, 215 | "language": 1, 216 | "pix": "comics/ronin.jpeg" 217 | }, 218 | { 219 | "title": "Le Fleau des Dieux", 220 | "genre": 11, 221 | "authors": "Valérie Mangin et Aleksa Gajic", 222 | "complete": true, 223 | "finished": true, 224 | "have": "1-6", 225 | "have_nb": 6, 226 | "serie_nb": 6, 227 | "language": 2, 228 | "pix": "comics/fleaudieux1.jpeg" 229 | }, 230 | { 231 | "title": "The Shaolin Cowboy", 232 | "genre": 4, 233 | "authors": "Geof Darrow and Lana and Andy Wachowski", 234 | "complete": true, 235 | "finished": true, 236 | "have": "1", 237 | "have_nb": 1, 238 | "serie_nb": 1, 239 | "language": 1, 240 | "pix": "comics/shaolin-cowboy.jpeg" 241 | }, 242 | { 243 | "title": "Tales of an Imperfect Future", 244 | "genre": 11, 245 | "authors": "Alfonso Font", 246 | "complete": true, 247 | "finished": true, 248 | "have": "1", 249 | "have_nb": 1, 250 | "serie_nb": 1, 251 | "language": 1, 252 | "pix": "comics/imperfect-future.jpeg" 253 | }, 254 | { 255 | "title": "Ghost in the Shell", 256 | "genre": 11, 257 | "authors": "Masamune Shirow", 258 | "complete": false, 259 | "finished": true, 260 | "have": "1", 261 | "have_nb": 1, 262 | "serie_nb": 2, 263 | "language": 1, 264 | "pix": "comics/ghost-in-the-shell.jpeg" 265 | }]; 266 | 267 | if(typeof module === "object" && typeof module.exports === "object"){ 268 | module.exports = uiModels.comics_data; 269 | } 270 | -------------------------------------------------------------------------------- /demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | Demo :: Evolutility-UI-jQuery 34 | 35 | 36 | 37 | 38 |
    39 | 40 |
    41 | 42 | 55 |
    56 |
    57 | 58 |
    59 |

    Demos

    60 |
    61 | 62 |
    63 | 64 |
    65 |
    66 | 67 |


    These sample applications are not anything you haven't seen before. 68 | The interesting thing is that these demos are not done with templates, CSS and custom Javascript but 69 | are only configured with UI-models. 70 |

    71 | 72 |

    By changing the ui-model, Evolutility-UI-jQuery set of views can behave as any of the following: 73 |

    79 |

    ... or anything you can imagine by making new ui-models.

    80 | 81 |

    The demo apps are configured with these UI models: To Do, 82 | Addressbook, 83 | Wine Cellar, 84 | Graphic novels. 85 |

    86 |

    87 | 88 | 89 |

    If you are really curious, you may want to play with the Test Object which is a contrived object with fields of all possible field types. 90 |

    91 | 92 |

    The data for these demos is stored in your browser's local storage 93 | (using Backbone.localStorage) but Evolutility-UI-jQuery can be configured for a REST API. 94 | 95 | For the server-side of Evolutility, use Evolutility-Server-Node with Node.js, Express.js and PostgreSQL. 96 |

    97 |
    98 |
    99 | 100 |
    101 | 102 |
    103 | 104 |
    105 | 106 | 107 | 140 | 141 | 142 | 143 | -------------------------------------------------------------------------------- /demo/custom-app.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | Evolutility-UI-jQuery Demo 30 | 31 | 32 | 33 | 34 |
    35 | 36 | 50 |
    51 |
    52 | 53 |
    54 | 55 |

    See how the different views adapt to changes to the ui-model.

    56 | 57 |

    58 | Make changes to the UI-model below, choose the view to display and click the "Refresh" button. 59 |

    60 | 61 |
    62 |
    63 | 64 | 65 |
    66 |
    67 | 68 |
    69 | 87 | 88 |
    89 | 90 |
    91 | 92 |
    93 | 94 | 95 |
    96 |
    97 |
    98 | 99 |

    100 |
    101 | 102 |

     

    103 | 104 |
    105 | 106 | 107 |
    108 | 109 | 172 | 173 | 174 | 175 | -------------------------------------------------------------------------------- /doc/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 11 | Documentation :: Evolutility-UI-jQuery 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 |
    26 | 27 | 39 |
    40 |
    41 | 42 |
    43 |

    Evolutility-UI-jQuery Documentation

    44 |
    45 | 46 |
    47 | 48 |
    49 |

    Metadata-driven Web UI for CRUD and more.

    50 | 51 |

    Evolutility-UI-jQuery provides a set of model-driven views which adapt to different data structures. 52 | For each entity, a single UI-model defines the UI for all views. 53 | 54 |

    55 |
    56 | 57 |

    Views

    58 |
    88 |
    89 | 90 |

    UI-Models

    91 |
    92 | A declarative language to configure the views and map fields on screen to attributes in your Backbone.js models. 93 | 94 | 101 | 102 |
    103 |
    104 |
    105 |

    Controller

    106 |
    107 | A controller and a toolbar to manage the views and make them act together as a Single Page App. 108 | 109 | 113 | 114 |
    115 |
    116 |
    117 |

    Code

    118 |

    Evolutility-UI-jQuery is using Javascript, HTML5, CSS3, 119 | with these open source libraries: 120 | Backbone.js, 121 | Underscore.js, 122 | jQuery, 123 | D3.js, 124 | Bootstrap, 125 | and a few UI widgets: Select2, 126 | bootstrap-datepicker, 127 | toastr. 128 |

    129 | 130 |

    The code is available at GitHub under the MIT license.

    131 | 132 |
    133 | 134 |
    135 | 136 |

    The meaning of Evolutility

    137 |

    In biology, Evolutility means "The faculty possessed by all substances capable of self-nourishment of manifesting the nutritive acts by changes of form, of volume, or of structure."

    138 |

    This open source project is a UI which changes form, volume and structure. It's DNA is metadata.

    139 |
    140 | 141 |


    Get Evolutility-UI-jQuery at GitHub

    142 | 143 |
    144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | -------------------------------------------------------------------------------- /js/view-many/many-charts.js: -------------------------------------------------------------------------------- 1 | /*! *************************************************************************** 2 | * 3 | * evolutility-ui-jquery :: many-charts.js 4 | * 5 | * View "many charts" to display a collection as a set of charts. 6 | * 7 | * https://github.com/evoluteur/evolutility-ui-jquery 8 | * (c) 2017 Olivier Giulieri 9 | * 10 | *************************************************************************** */ 11 | 12 | // Quick and easy implementation w/ the old version of google charts 13 | // must be re-written to use D3.js or other cool stuff 14 | 15 | Evol.ViewMany.Charts = function() { 16 | 17 | var dom = Evol.DOM, 18 | eDico = Evol.Dico, 19 | i18n = Evol.i18n; 20 | 21 | return Evol.View_Many.extend({ 22 | 23 | viewName: 'charts', 24 | icon: 'stats', // glyphicon-stats 25 | 26 | isChart: true, 27 | 28 | options: { 29 | //sizes: '600x300', 30 | style: 'panel-info', 31 | fieldsetFilter: Evol.Def.fieldInCharts, 32 | autoUpdate: false 33 | }, 34 | 35 | events: { 36 | 'mouseenter .evol-many-charts>div': 'enterItem', 37 | 'mouseleave .evol-many-charts>div': 'leaveItem', 38 | 'click .evol-actions>i': 'clickAction' 39 | //'click .evol-field-label .glyphicon-wrench': 'click_customize' 40 | }, 41 | 42 | render: function () { 43 | this.entityName=Evol.Format.capitalize(this.uiModel.namePlural); 44 | if(this.collection && this.collection.length>0){ 45 | this.$el.html('
    '+ 46 | this._HTMLcharts(this.style || 'panel-info', this.sizes)+ 47 | '
    '); 48 | }else{ 49 | this.$el.html(dom.HTMLMsg(i18n.nodata, '', 'info')); 50 | } 51 | return this.setTitle(); 52 | }, 53 | 54 | _HTMLcharts: function (style, sizes) { 55 | var h='', 56 | fTypes = Evol.Def.fieldTypes, 57 | uiModel = this.uiModel, 58 | models = this.collection.models, 59 | iconsPath = this.iconsPath || '', 60 | chartFields = this.getFields(), 61 | chartType, 62 | cData={}, 63 | entityName=this.entityName; 64 | 65 | if(chartFields && chartFields.length){ 66 | var groups, 67 | lb; 68 | _.each(chartFields, function(f){ 69 | var trData = Evol.Def.countBy(models, f, cData, iconsPath); 70 | var data=trData.data, 71 | labels=trData.labels, 72 | nb, dataSetName, 73 | isList=f.type===fTypes.lov || f.type===fTypes.list; 74 | /* 75 | if(f.type===fTypes.bool){ 76 | groups = _.countBy(models, function(m) { 77 | return m.get(f.id)===true; 78 | }); 79 | for(dataSetName in groups) { 80 | nb=groups[dataSetName]; 81 | if(dataSetName==='true'){ 82 | lb = f.labelTrue || i18n.yes; 83 | }else{ 84 | lb = f.labelFalse || i18n.no; 85 | } 86 | data.push(nb); 87 | labels.push(lb+' ('+nb+')'); 88 | } 89 | }else{ 90 | groups = _.countBy(models, function(m) { 91 | return m.get(f.id); 92 | }); 93 | for(dataSetName in groups) { 94 | nb=groups[dataSetName]; 95 | if(dataSetName==='undefined'){ 96 | lb = i18n.na; 97 | }else if(dataSetName==='' || dataSetName==='null'){ 98 | lb = i18n.none; 99 | }else if(isList){ 100 | if(f.list && f.list.length && f.list[0].icon){ 101 | lb = eDico.lovItemTextNoPix(f, dataSetName); 102 | }else{ 103 | lb = eDico.lovItemText(f, dataSetName, Evol.hashLov, iconsPath); 104 | } 105 | }else{ 106 | lb = dataSetName; 107 | } 108 | data.push(nb); 109 | labels.push(lb+' ('+nb+')'); 110 | } 111 | } 112 | */ 113 | chartType = f.typeChart || (f.type===fTypes.lov ? 'pie':'bars'); 114 | h+='
    '+ 115 | '
    '; 116 | if(chartType==='pie'){ 117 | h+=dom.Charts.Pie(f.labelCharts?f.labelCharts:i18n.getLabel('charts.aByB', entityName, f.label), data, labels, style, sizes); 118 | }else if(chartType==='bars'){ 119 | h+=dom.Charts.Bars(f.labelCharts?f.labelCharts:i18n.getLabel('charts.aB', entityName, f.label), data, labels, style, sizes); 120 | } 121 | h+='

    '; 122 | }); 123 | this._cData=cData; 124 | }else{ 125 | h+=dom.HTMLMsg(i18n.nochart, i18n.badchart); 126 | } 127 | h+=dom.html.clearer; 128 | return h; 129 | }, 130 | 131 | setPage: function(){ 132 | // do nothing 133 | // b/c it can be invoked for all view Many 134 | }, 135 | 136 | enterItem: Evol.ViewMany.actionEvents.enterItem([ 137 | {id:'bars', type:null, icon:'stats'}, 138 | {id:'pie',type: null, icon:'record'}, 139 | //{id:'big',type: null, icon:'resize-full'} // resize-small 140 | ]), 141 | 142 | leaveItem: Evol.ViewMany.actionEvents.leaveItem, 143 | 144 | clickAction: function(evt){ 145 | var el=$(evt.currentTarget), 146 | cType=el.data('id'), 147 | holder=el.parent().parent().find('.chart-holder'), 148 | oType=holder.data('ctype'), 149 | fid=holder.data('fid'), 150 | oldData=this._cData[fid], 151 | f=oldData.field, 152 | chart=dom.Charts, 153 | c, cl; 154 | 155 | if(cType!=oType){ 156 | if(cType==='bars'){ 157 | c='Bars'; 158 | cl='charts.aB'; 159 | }else{ 160 | c='Pie'; 161 | cl='charts.aByB'; 162 | } 163 | holder.html(chart[c](f.labelCharts?f.labelCharts:i18n.getLabel(cl, this.entityName, f.label), oldData.data, oldData.labels, oldData.style, oldData.sizes)); 164 | holder.data('ctype', cType); 165 | } 166 | } 167 | 168 | }); 169 | 170 | }(); 171 | -------------------------------------------------------------------------------- /js/dico/app.js: -------------------------------------------------------------------------------- 1 | /*! *************************************************************************** 2 | * 3 | * evolutility-ui-jquery :: app.js 4 | * 5 | * View "app" to manage the single page app for all objects/ui-models. 6 | * 7 | * https://github.com/evoluteur/evolutility-ui-jquery 8 | * (c) 2017 Olivier Giulieri 9 | * 10 | *************************************************************************** */ 11 | 12 | EvoConfig = EvoConfig || {}; 13 | 14 | Evol.App = Backbone.View.extend({ 15 | 16 | //events: { 17 | //'click .evo-head-links2>li': 'click_entity' 18 | //}, 19 | 20 | options: { 21 | //uiModels: [], 22 | elements:{ 23 | nav: '.evo-head-links', 24 | nav2: '.evo-head-links2', 25 | content: '#evol' 26 | }, 27 | style: 'panel-default', 28 | useRouter: true, 29 | pageSize: 20, 30 | prefix: 'evol-' 31 | }, 32 | 33 | initialize: function (opts) { 34 | _.extend(this, this.options, opts); 35 | var uims = {}; 36 | _.forEach(this.uiModels, function(uim, idx){ 37 | uims[uim.id||'uim'+idx] = uim; 38 | }); 39 | this.uiModelsObj = uims; 40 | this._tbs={}; 41 | this._ents={}; 42 | var es = this.elements; 43 | //this.$nav = $(es.nav); 44 | this.$nav2 = $(es.nav2); 45 | //this.$content = $(es.content); 46 | this.setupRouter(); 47 | }, 48 | 49 | //render: function() { 50 | //this.$el.html(... 51 | //this.$nav2.html(this._HTMLentities(this.uiModels)); 52 | //this.$content.html(...; 53 | //return this; 54 | //}, 55 | 56 | setupRouter: function(){ 57 | var that=this, 58 | EvolRouter = Backbone.Router.extend ({ 59 | routes: { 60 | '' : 'nav', 61 | //':entity/:view/:id': 'nav', 62 | //':entity/:view': 'nav', 63 | //':entity': 'nav', 64 | ':entity(/:view)(/:id)': 'nav', 65 | '*noroute': that.noRoute 66 | }, 67 | nav: function(entity, view, id){ 68 | if(entity && that.uiModelsObj[entity]){ 69 | that.setEntity(entity, view, id); 70 | }else { 71 | // TODO !!! 72 | //alert('Error: Invalid route.'); 73 | } 74 | } 75 | }); 76 | 77 | this.router = new EvolRouter(); 78 | Backbone.history.start(); 79 | }, 80 | 81 | setRoute: function(id, triggerRoute){ 82 | var cView = this._tbs[this._curEntity].curView; 83 | if(cView){ 84 | Evol.Dico.setRoute(this.router, cView.uiModel.id, cView.viewName, id, triggerRoute); 85 | Evol.Dico.setPageTitle(cView.getTitle()); 86 | }else{ 87 | alert('Error: Invalid route (for app).'); 88 | } 89 | return this; 90 | }, 91 | 92 | noRoute: function(route){ 93 | alert('Error: Invalid route "'+route+'".'); 94 | }, 95 | 96 | setEntity: function(eName, view, options){ 97 | var that=this, 98 | tb=this._tbs[this._curEntity], 99 | cbOK=function(){ 100 | that._setEntity(eName, view, options); 101 | }, 102 | cbCancel=function(){ 103 | //TODO case w/ no/new model 104 | if(tb && tb.curView){ // TODO this "if" should not be necessary 105 | that.setRoute(tb.curView.model.id, false); 106 | } 107 | }; 108 | 109 | if(this._curEntity){ 110 | if(tb){ 111 | tb.proceedIfReady(cbOK, cbCancel); 112 | }else{ 113 | //alert('Error calling proceedIfReady'); 114 | cbCancel(); 115 | } 116 | }else{ 117 | cbOK(); 118 | } 119 | }, 120 | 121 | _setEntity: function(eName, view, options){ 122 | var that=this; 123 | 124 | view = view || 'list'; 125 | 126 | function cb(){ 127 | that._ents[eName].show().siblings().hide(); 128 | var tb=that._tbs[eName]; 129 | if(tb){ 130 | that._curEntity = eName; 131 | if(tb.curView.viewName !== view){ 132 | tb.setView(view, false, false) //tb.setView(view, true, false) 133 | .setTitle(); 134 | } 135 | if(options){ 136 | if(tb.curView.cardinality==='1'){ 137 | tb.setModelById(options); 138 | that.setRoute(options, false); 139 | }else{ 140 | that.setRoute('', false); 141 | } 142 | } 143 | } 144 | } 145 | 146 | if(this._ents[eName]){ 147 | cb(); 148 | }else{ 149 | var $v=$('
    '); 150 | this._ents[eName]=$v; 151 | this.$el.children().hide(); 152 | this.$el.append($v); 153 | this.createEntity($v, this.uiModelsObj[eName], [], view, options, cb); 154 | } 155 | if(this._curEntity!==eName){ 156 | this.$nav2.find('>li>a').removeClass('sel') 157 | .filter('[data-id="'+eName+'"]').addClass('sel'); 158 | this._curEntity=eName; 159 | } 160 | return this; 161 | }, 162 | 163 | createEntity: function($v, uiModel, data, defaultView, options, cb){ 164 | var that=this, url, M, Ms; 165 | 166 | if(EvoConfig){ 167 | if(EvoConfig.localStorage){ 168 | var lc = new Backbone.LocalStorage(this.prefix+(uiModel.table || uiModel.id)); 169 | M = Backbone.Model.extend({ 170 | localStorage: lc 171 | }); 172 | Ms = Backbone.Collection.extend({ 173 | model: M, 174 | localStorage: lc 175 | }); 176 | }else{ 177 | url = EvoConfig.url+uiModel.id; 178 | M = Backbone.Model.extend({ 179 | urlRoot: url 180 | }); 181 | Ms = Backbone.Collection.extend({ 182 | model: M, 183 | url: url 184 | }); 185 | } 186 | }else{ 187 | alert('Error: missing config file.'); 188 | } 189 | 190 | var ms = new Ms(); 191 | ms.fetch({ 192 | success: function(collection){ 193 | var m = ms.at(0), 194 | config = { 195 | el: $v, 196 | mode: 'list', 197 | model: m, 198 | modelClass: M, 199 | collection: ms, 200 | collectionClass: Ms, 201 | uiModel: uiModel, 202 | pageSize: that.pageSize, 203 | titleSelector: '#title', 204 | style: that.style 205 | }; 206 | 207 | if(defaultView){ 208 | config.defaultView = defaultView; 209 | } 210 | if(that.useRouter){ 211 | config.router = that.router; 212 | } 213 | var toolbar = new Evol.Toolbar(config).render();//.setTitle(); 214 | if(options && toolbar.cardinality==='1'){ 215 | toolbar.setModelById(options); 216 | } 217 | if(that._tbs){ 218 | that._tbs[uiModel.id] = toolbar; 219 | } 220 | if(cb){ 221 | cb(toolbar); 222 | } 223 | }, 224 | error: function(err){ 225 | alert('Error: invalid route (for app).'); 226 | } 227 | }); 228 | }, 229 | 230 | _HTMLentities: function (es) { 231 | return _.map(es, function(e){ 232 | return '
  • ' + e.namePlural + '
  • '; 233 | }).join(''); 234 | } 235 | 236 | }); 237 | 238 | -------------------------------------------------------------------------------- /doc/controller.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | Controller :: Evolutility-UI-jQuery 26 | 27 | 28 | 29 |
    30 | 31 | 48 |
    49 |
    50 | 51 |
    52 |

    Controller

    53 |
    54 | 55 |
    56 | 57 |

    Still under construction, Evolutility-UI-jQuery controller is not the usual "C" in "MVC". 58 | Very likely you will want to write your own (at least for now). 59 |

    60 | 61 |

    With Evolutility you can decide what to automate and what to code yourself.

    62 |
      63 |
    • You can instantiate any view directly and write your own controller to manage it.
    • 64 |
    • You can instantiate a toolbar which will manage all views for a specific entity (Backbone model and collection).
    • 65 |
    • You can instantiate an app which will manage several toolbars which will each manage a set of views.
    • 66 |
    67 |

    App and Toolbar use the same UI-models as the views.

    68 | 69 | 70 |   71 |
    72 |

    App

    73 |

    The class "Evol.App" handles routing for all views for several entities. 74 | For each entity it creates a toolbar which manages the views for that entity. 75 |

    76 | 77 |

     78 | new Evol.App({
     79 |     el: $('#evol'),
     80 |     uiModels: [
     81 |         uiModels.todo,
     82 |         uiModels.contact,
     83 |         uiModels.winecellar,
     84 |         uiModels.comics
     85 |     ]
     86 | });
     87 |     

    88 | 89 | 90 |
    91 |

    Options

    92 | 93 |

    el: DOM element to hold the views.

    94 |

    uiModels: Array of UI-models.

    95 |

    style: Bootstrap style for panels (possible values: "panel-default" (grey), "panel-primary" (dark blue), "panel-success" (green), "panel-info" (light blue), "panel-warning" (yellow), "panel-danger" (red)).

    96 |

    useRouter: Set to true for Evolutility-UI-jQuery to automatically handle routing.

    97 |

    pageSize: Page size for list and cards views.

    98 | 99 |
    100 | 101 | 102 |
    103 |

    Methods

    104 | 105 |

    setRoute(id, triggerRoute): Change the route and display the corresponding view.

    106 | 107 |

    setEntity(entityName, view, options): Change the entity and display the corresponding entity in the currently selected view.

    108 | 109 |
    110 | 111 | 112 |
    113 |

    Events

    114 | 115 |

    None (for now). 116 |

    117 | 118 | 119 | 120 |
    121 | 122 | 123 |   124 |
    125 |

    Toolbar

    126 |

    The toolbar manages all views for a specific UI-model. It displays different options based on the context.

    127 | 128 |

    Toolbar for One model:

    129 |

    130 | 131 | 132 |

    Toolbar for Many models:

    133 |

    134 | 135 | 136 |

    137 | new Evol.Toolbar(
    138 |     el: $('#Evol'),
    139 |     uiModel: uiModel,
    140 |     model: myModel,
    141 |     collection: myCollection,
    142 |     titleSelector: '#title'
    143 | );
    144 |     

    145 | 146 |
    147 |

    Options

    148 | 149 |

    defaultViewOne: Default view when looking at a single model (possible values "browse", "edit", "mini", json").

    150 |

    defaultViewMany: Default view when looking at a collection (possible values "list", "cards", "bubbles", charts").

    151 | 152 |

    model: Backbone model for the toolbar to manage.

    153 |

    collection: Backbone collection for the toolbar to manage.

    154 |

    readonly: Provides read-only interaction (no update or delete).

    155 |

    style: Bootstrap style for panels (possible values: "panel-default" (grey), "panel-primary" (dark blue), "panel-success" (green), "panel-info" (light blue), "panel-warning" (yellow), "panel-danger" (red)).

    156 |

    titleSelector: Selector for the title element outside of the view (example: '#title').

    157 |

    pageSize: Page size for list and cards views.

    158 |
    159 | 160 | 161 |
    162 |

    Methods

    163 | 164 |

    render(): Render the toolbar and the default view.

    165 | 166 |

    setData(data): Set data.

    167 | 168 |

    getData(): Get data.

    169 | 170 |

    setView(viewName): Set the current view (possible values: "browse", edit", "mini", "list"...).

    171 | 172 |

    showFilter(): Expend the filter panel.

    173 | 174 |

    browse(direction): Moves to the next or previous record.

    175 | 176 |

    SaveItem(saveAndAdd): Save the currently edited record (if it passes validation).

    177 | 178 |

    newItem(): Create a new record.

    179 | 180 |

    deleteItem(): Delete the currently edited or browsed record.

    181 | 182 |

    clearMessage(): Clear the header message.

    183 | 184 |

    setMessage(): Set the value of the header message.

    185 | 186 |
    187 | 188 | 189 |
    190 |

    Events

    191 | 192 |

    item.added, item.saved, item.deleted: Triggered when a record is added/saved or deleted.

    193 |

    filter.change: Triggered when filter conditions are changed.

    194 |

    toolbar.X: Triggered when a toolbar button is clicked. X = toolbar button Ids in [ 195 | 'new', 'del', 'filter', 'export', 196 | 'browse', 'edit', 'mini', 'json', 197 | 'list', 'cards', 'bubbles', 'charts', 198 | 'prev', 'next' 199 | ].

    200 |
    201 | 202 |
    203 | 204 |


    Evolutility-UI-jQuery at GitHub

    205 | 206 | 207 |
    208 | 209 | 210 | 211 | 212 | -------------------------------------------------------------------------------- /js/dico/def.js: -------------------------------------------------------------------------------- 1 | /*! *************************************************************************** 2 | * 3 | * evolutility-ui-jquery :: def.js 4 | * 5 | * Library of helpers for metamodel 6 | * 7 | * https://github.com/evoluteur/evolutility-ui-jquery 8 | * (c) 2017 Olivier Giulieri 9 | * 10 | *************************************************************************** */ 11 | 12 | var Evol = Evol || {}; 13 | 14 | Evol.Def = function(){ 15 | 16 | var fts = { 17 | text: 'text', 18 | textml: 'textmultiline', 19 | bool: 'boolean', 20 | int: 'integer', 21 | dec: 'decimal', 22 | money: 'money', 23 | date: 'date', 24 | datetime: 'datetime', 25 | time: 'time', 26 | lov: 'lov', 27 | list: 'list', // many values for one field (behave like tags - return an array of strings) 28 | html: 'html', 29 | formula:'formula', // soon to be a field attribute rather than a field type 30 | email: 'email', 31 | pix: 'image', 32 | //geoloc: 'geolocation', 33 | //doc:'document', 34 | url: 'url', 35 | color: 'color', 36 | hidden: 'hidden', 37 | json: 'json' 38 | //rating: 'rating', 39 | //widget: 'widget' 40 | }; 41 | 42 | return { 43 | 44 | fieldTypes: fts, 45 | 46 | /* 47 | isViewOne: function(viewName){ 48 | return viewName==='new' || viewName==='edit' || viewName==='browse' || viewName==='json'; 49 | },*/ 50 | isViewMany: function(viewName){ 51 | return this.isViewCollection(viewName) || this.isViewCharts(viewName); 52 | }, 53 | 54 | isViewCollection: function(viewName){ 55 | return viewName==='list' || viewName==='cards'; 56 | }, 57 | 58 | isViewCharts: function(viewName){ 59 | return viewName==='charts' || viewName==='bubbles' || viewName==='scatter' || viewName==='sunburst'; 60 | }, 61 | 62 | fieldInCharts: function (f) { 63 | return (_.isUndefined(f.inCharts) || f.inCharts) && Evol.Def.fieldChartable(f); 64 | }, 65 | fieldChartable: function (f) { 66 | // || f.type===fts.list 67 | return f.type===fts.lov || f.type===fts.bool || f.type===fts.int || f.type===fts.money; 68 | }, 69 | 70 | fieldIsNumber: function(f){ 71 | return f.type===fts.int || f.type===fts.dec || f.type===fts.money; 72 | },/* 73 | fieldIsDateOrTime: function(fType){ 74 | return fType===fts.date || fType===fts.datetime || fType===fts.time; 75 | },*/ 76 | 77 | fnSearch: function(uiModel, searchString){ 78 | var sfn = uiModel.fnSearch; 79 | if(_.isFunction(sfn)){ 80 | return function(model){ 81 | return uiModel.fnSearch(model, searchString); 82 | }; 83 | }else{ 84 | if(_.isArray(sfn)){ 85 | return function(model){ 86 | var ln=sfn.length; 87 | for(var i=0;i-1){ 90 | return true; 91 | } 92 | } 93 | return false; 94 | }; 95 | }else if(_.isString(sfn)){ 96 | return function(model){ 97 | return model.get(fn) ? model.get(fn).toLowerCase().indexOf(searchString)>-1 : false; 98 | }; 99 | } 100 | } 101 | }, 102 | 103 | // get all "shallow" fields (no sub collections) from a UI model 104 | getFields: function (uiModel, fnFilter) { 105 | var fs = []; 106 | 107 | function collectFields(te) { 108 | if (te && te.elements && te.elements.length > 0) { 109 | _.each(te.elements, function (tec) { 110 | if(!tec.elements){ 111 | fs.push(tec); 112 | }else if(tec.type!='panel-list'){ 113 | collectFields(tec); 114 | } 115 | }); 116 | } else { 117 | fs.push(te); 118 | } 119 | } 120 | 121 | collectFields(uiModel); 122 | if (_.isFunction(fnFilter)) { 123 | fs= _.filter(fs, fnFilter); 124 | } 125 | return fs; 126 | }, 127 | 128 | getFieldsHash: function(fields){ 129 | var h = {}; 130 | _.each(fields, function(f){ 131 | h[f.id] = f; 132 | }); 133 | return h; 134 | }, 135 | 136 | // get sub collections 137 | getSubCollecs: function(uiModel){ 138 | var ls = {}; 139 | 140 | function collectCollecs(te) { 141 | if(te.type==='panel-list'){ 142 | ls[te.attribute]=te; 143 | }else if (te.type!=='panel' && te.elements && te.elements.length > 0) { 144 | _.each(te.elements, function (te) { 145 | if(te.type==='panel-list'){ 146 | ls[te.attribute]=te; 147 | }else if(te.type!=='panel'){ 148 | collectCollecs(te); 149 | } 150 | }); 151 | } else { 152 | ls[te.attribute]=te; 153 | } 154 | } 155 | 156 | collectCollecs(uiModel); 157 | return ls; 158 | }, 159 | 160 | countBy: function(models, f, cData, iconsPath){ 161 | var fTypes=Evol.Def.fieldTypes, 162 | i18n = Evol.i18n, 163 | data=[], 164 | labels=[], 165 | nb, dataSetName; 166 | 167 | if(f.type===fTypes.bool){ 168 | groups = _.countBy(models, function(m) { 169 | return m.get(f.id)===true; 170 | }); 171 | for(dataSetName in groups) { 172 | nb=groups[dataSetName]; 173 | if(dataSetName==='true'){ 174 | lb = f.labelTrue || i18n.yes; 175 | }else{ 176 | lb = f.labelFalse || i18n.no; 177 | } 178 | data.push(nb); 179 | labels.push(lb+' ('+nb+')'); 180 | } 181 | }else{ 182 | groups = _.countBy(models, function(m) { 183 | return m.get(f.id); 184 | }); 185 | for(dataSetName in groups) { 186 | nb=groups[dataSetName]; 187 | if(_.isUndefined(dataSetName)){ 188 | lb = i18n.na; 189 | }else if(dataSetName==='' || dataSetName==='null'){ 190 | lb = i18n.none; 191 | }else if(f.type===fTypes.lov || f.type===fTypes.list){ 192 | if(f.list && f.list.length && f.list[0].icon){ 193 | lb = Evol.Dico.lovItemTextNoPix(f, dataSetName); 194 | }else{ 195 | lb = Evol.Dico.lovItemText(f, dataSetName, Evol.hashLov, iconsPath); 196 | } 197 | }else{ 198 | lb = dataSetName; 199 | } 200 | data.push(nb); 201 | labels.push(lb+' ('+nb+')'); 202 | } 203 | } 204 | chartType = f.typeChart || (f.type===fTypes.lov ? 'pie':'bars'); 205 | cData[f.id] = { 206 | field: f, 207 | data: data, 208 | labels: labels, 209 | //style: style, 210 | //sizes: sizes 211 | }; 212 | return { data: data, labels: labels}; 213 | }, 214 | 215 | sampleDatum: function(f, idx){ 216 | function char(idx){ 217 | return String.fromCharCode(97 + idx)+ String.fromCharCode(98 + idx)+ String.fromCharCode(99 + idx); 218 | } 219 | switch(f.type){ 220 | case fts.bool: 221 | return true; 222 | case fts.date: 223 | return '2015-0'+(idx+1)+'-'+(idx+14); 224 | case fts.datetime: 225 | return '2015-04-23T17:15'; 226 | case fts.time: 227 | return '14:30'; 228 | case fts.url: 229 | return 'http://www.evolutility.org'; 230 | case fts.email: 231 | return 'abc@abc.com'; 232 | case fts.int: 233 | if(f.min){ 234 | return f.min+5+(idx*2); 235 | } 236 | return idx; 237 | case fts.dec: 238 | case fts.money: 239 | return (idx+1)*10.2; 240 | case fts.lov: 241 | if(f.list && f.list.length){ 242 | if(idx-1){ 14 | var ns=label.split('.'); 15 | l=this[ns[0]][ns[1]]; 16 | }else{ 17 | l=this[label]; 18 | } 19 | if(string1 && l){ 20 | l = l.replace('{0}', string1); 21 | //l = l.replace(/\{0\}/g, string1); 22 | if(string2){ 23 | l = l.replace('{1}', string2); 24 | //l = l.replace(/\{1\}/g, string2); 25 | } 26 | } 27 | return l; 28 | }, 29 | 30 | // --- toolbar & buttons --- 31 | tools:{ 32 | View: 'View', 33 | bBrowse: 'Browse', 34 | bEdit: 'Edit', 35 | bMini: 'Mini', // 'Quick Edit' 36 | // Login: 'Login', 37 | bNew: 'New', 38 | newEntity: 'New {0}', //'New Item', 39 | //NewUpload: 'New Upload', 40 | //Search: 'Search', 41 | //AdvSearch: 'Advanced Search', 42 | //NewSearch: 'New Search', 43 | //Selections: 'Selections', 44 | //Selection: 'Selection', 45 | bExport: 'Export', 46 | bImport: 'Import', 47 | //SearchRes: 'Search Result', 48 | //MassUpdate: 'Mass Update', 49 | bDelete: 'Delete', 50 | //bAll: 'All', 51 | bList: 'List', 52 | bCards: 'Cards', 53 | bJSON: 'JSON', 54 | bFilter: 'Filter', 55 | bBubbles: 'Bubbles', 56 | //bSunburst: 'Sunburst', 57 | //bScatter:'Scatter', 58 | bCharts: 'Charts', 59 | //bRefresh: 'Refresh', 60 | //bPrint: 'Print', 61 | bSave: 'Save', 62 | bSaveAdd: 'Save and Add Another', 63 | bOK: 'OK', 64 | bCancel: 'Cancel', 65 | 66 | // --- data visualization --- 67 | vizGroupBy: 'Group by', 68 | vizColorBy: 'Color by', 69 | vizSizeBy: 'Size by', 70 | 71 | //xAxis: 'X Axis', 72 | //yAxis: 'Y Axis', 73 | //zAxis: 'Z Axis', 74 | 75 | // --- wizard --- 76 | prev: 'Previous', 77 | next: 'Next', 78 | finish: 'Finish !' 79 | }, 80 | 81 | // --- msg & status --- 82 | //msg: { 83 | saved: '{0} saved.', 84 | unSavedTitle: 'Changes pending', 85 | unSavedChanges: 'Do you want to save the changes you made to "{0}"?', 86 | warnNoSave: 'Your changes will be lost if you don\'t save them.', 87 | bNoSave: 'Don\'t Save', 88 | deleteX: 'Delete {0}',// {0}=entity 89 | delete1: 'Do you really want to delete the {0} "{1}"?', // {0}=entity {1}=titlefield value, 90 | deleteN: 'Delete {0} {1}?', // delete 5 tasks 91 | deleted1: '{0} deleted.', // {0}=entity , 92 | 93 | notFound: 'Item not found.', 94 | //this.setMessage(i18n.notFound, i18n.getLabel('notFoundMsg', this.uiModel.name); 95 | notFoundMsg: 'No {0} found.', 96 | notFoundMsgId: 'No {0} found for ID="{1}".', 97 | 98 | //NoChange: 'No Change', 99 | //NoX: 'No {0}', 100 | //Back2SearchResults: 'Back to search results', 101 | yes: 'Yes', 102 | no: 'No', 103 | none: 'None', 104 | na: 'N/A', // 'not available' 105 | nodata: 'No data available.', 106 | notEnoughdata: 'Not enough data available.', 107 | nopix: 'No picture.', 108 | nochart: 'No charts available.', 109 | badchart: 'Not enough information provided to draw charts.', 110 | range: '{0} - {1} of {2} {3}', //rangeBegin, '-', rangeEnd, ' of ', mSize, ' ', entities' 111 | selected: '{0} selected', 112 | //}, 113 | 114 | // --- status --- 115 | msg:{ 116 | sgn_money: '$', // indicator for money 117 | sgn_email: '@', // indicator for email 118 | added: 'New {0} "{1}" added.', 119 | updated: '{0} "{1}" updated.', 120 | deleted: '{0} "{1}" deleted.' 121 | //error: 'Error', 122 | }, 123 | 124 | // --- validation --- 125 | validation:{ 126 | incomplete: 'Some information is missing or invalid.', 127 | invalid: 'Invalid format.', 128 | invalidList: '{0} values in "{1}" are invalid.', 129 | invalidList1: '1 value in "{1}" is invalid.', 130 | //intro: 'You are not finished yet: ', 131 | empty: '"{0}" must have a value.', 132 | email: '"{0}" must be a valid email formatted like "name@domain.com".', 133 | integer: '"{0}" must only use numbers.', 134 | decimal: '"{0}" must be a valid decimal numbers.', 135 | money: '"{0}" must be a valid number.', 136 | date: '"{0}" must be a valid date, format must be "MM/DD/YYYY" like "12/24/2015".', 137 | datetime: '"{0}" must be a valid date/time, format must be "MM/DD/YYYY hh:mm AM/PM" like "12/24/2015 10:30 AM".', 138 | time: '"{0}" must be a valid date/time, format must be "hh:mm AM/PM" like "10:30 AM".', 139 | json: '"{0}" must be a valid JSON expression like "{"a": 1}".', 140 | max: '"{0}" must be smaller or equal to {1}.', 141 | min: '"{0}" must be greater or equal to {1}.', 142 | maxLength: '"{0}" must be {1} characters long maximum.', 143 | minLength: '"{0}" must be at least {1} characters long.', 144 | minMaxLength: '"{0}" must be between {1} and {2} characters long.', 145 | regExp: '"{0}" is not of the expected format.' 146 | //regExp: '"{0}" must match the regular expression pattern for "{1}".' 147 | }, 148 | 149 | // --- charts --- 150 | charts:{ 151 | aByB: '{0} by {1}', 152 | aB: '{0}: {1}' 153 | }, 154 | 155 | // --- export --- 156 | export:{ 157 | exportOne: 'Export {0}', // {0}=entity 158 | exportMany: 'Export {0}', // {0}=entities 159 | preview: 'Export preview', 160 | header: 'Header', 161 | options: 'options', 162 | separator: 'Separator', 163 | firstLine: 'The first row is a header', 164 | format: 'Export format', 165 | xpFields: 'Fields to include in the export', 166 | IDkey: 'ID', 167 | allFields: 'Show all fields', 168 | formatCSV: 'Comma separated values (CSV, TXT, XLS...)', 169 | formatHTML: 'HTML', 170 | formatSQL: 'SQL Insert Statements (SQL)', 171 | formatTAB: 'Tab separated values (TXT)', 172 | formatXML: 'XML', 173 | formatJSON: 'Javascript Object Notation (JSON)', 174 | //xpColors: 'Header color-Color odd rows-Color even rows', 175 | //xpColMap: 'Columns map to', 176 | XMLroot: 'Element name', // 'Root element name' 177 | //xpXMLAttr: 'Attributes', 178 | //xpXMLElem: 'Elements', 179 | headerLabels: 'Field Labels', 180 | headerIds: 'Field Attributes or Ids', 181 | db: 'Database', 182 | SQL: 'SQL Options', 183 | SQLTable: 'Table name', 184 | SQLTrans: 'In transaction', 185 | SQLIdInsert: 'Identity insert', 186 | DownloadEntity: 'Download {0}' 187 | }, 188 | 189 | // --- import --- 190 | import:{ 191 | importOne: 'Import {0}', // {0}=entity 192 | importMany: 'Import {0}', // {0}=entities 193 | format: 'Source Format', 194 | fSample: 'Sample', 195 | allowDups: 'Allow duplicates', 196 | data: 'Data to Import', 197 | success: 'Import done.', 198 | empty: 'Nothing to Import.' 199 | }, 200 | 201 | // --- filters --- 202 | filters:{ 203 | sEqual: 'equals', 204 | sNotEqual: 'not equal', 205 | sStart: 'starts with', 206 | sContain: 'contains', 207 | sNotContain: 'doesn\'t contain', 208 | sFinish: 'finishes with', 209 | sInList: 'is any of', 210 | sIsNull: 'is empty', 211 | sIsNotNull: 'is not empty', 212 | sBefore: 'before', 213 | sAfter: 'after', 214 | sNumEqual: '=', 215 | sNumNotEqual: '!=', 216 | sGreater: '>', 217 | sSmaller: '<', 218 | sOn: 'on', 219 | sNotOn: 'not on', 220 | sAt: 'at', 221 | sNotAt: 'not at', 222 | sBetween: 'between', 223 | opAnd: 'and', 224 | //opOr: 'or', 225 | yes: 'Yes', 226 | no: 'No', 227 | bNewCond: 'New filter condition', 228 | bAddCond: 'Add condition', 229 | bUpdateFilter: 'Update filter', 230 | bSubmit: 'Submit', 231 | bCancel: 'Cancel' 232 | }/*, 233 | 234 | // --- documentation --- 235 | doc:{ 236 | entity: 'Entity', 237 | fields: 'Fields', 238 | uiModel: 'UI Model' 239 | }*/ 240 | 241 | }; 242 | -------------------------------------------------------------------------------- /js/view-many/many-bubbles-d3.js: -------------------------------------------------------------------------------- 1 | // Original code and blog post by Steve Hall http://www.delimited.io/blog/2013/12/19/force-bubble-charts-in-d3 2 | // Modified for Evolutility-UI-jQuery http://evoluteur.github.io/evolutility-ui-jquery/ 3 | 4 | var Evol=Evol||{}; 5 | 6 | Evol.Bubbles = function(){ 7 | 8 | var fts = Evol.Def.fieldTypes; 9 | 10 | var Bubbles = function(opts){ 11 | _.extend(this, opts); 12 | this.fieldsH={}; 13 | for(var i in this.fields){ 14 | var f=this.fields[i]; 15 | this.fieldsH[f.id]=f; 16 | } 17 | return this; 18 | }; 19 | 20 | Bubbles.prototype._initialize = function(){ 21 | if(!this.graphInitialized){ 22 | //var fill = d3.scale.ordinal().range(['#827d92','#827354','#523536','#72856a','#2a3285','#383435']) 23 | this.svg = d3.select(this.elem).append("svg") 24 | .attr("width", this.width) 25 | .attr("height", this.height); 26 | 27 | this.force = d3.layout.force(); 28 | this.graphInitialized=true; 29 | } 30 | }; 31 | 32 | Bubbles.prototype.fixData = function(data){ 33 | return _.map(data, function(d){ 34 | return d; 35 | }); 36 | }; 37 | 38 | Bubbles.prototype.setData = function(data){ 39 | var that=this, 40 | len=data.length, 41 | defaultSize=len<17 ? 20 : (len<100 ? 16 : 10); 42 | 43 | this.defaultSize=defaultSize; 44 | 45 | if(this.sizeFieldId){ 46 | var sizes = _.map(data, function(d){ 47 | var v= d[that.sizeFieldId]; 48 | if(v===null || _.isNaN(v)){ 49 | v=0; 50 | } 51 | return v; 52 | }); 53 | this.plotScale = d3.scale.log().domain([ _.min(sizes), _.max(sizes)]).range([defaultSize, defaultSize+20]); 54 | }else{ 55 | this.plotScale = function(d){ return defaultSize;}; 56 | } 57 | 58 | this.fill = len<11?d3.scale.category10():d3.scale.category20(); 59 | 60 | this.data = data; 61 | for (var j = 0; j < data.length; j++) { 62 | data[j].radius = defaultSize; 63 | data[j].x = Math.random() * this.width; 64 | data[j].y = Math.random() * this.height; 65 | } 66 | 67 | this._initialize(); 68 | 69 | this.maxRadius = d3.max(_.pluck(data, 'radius')); 70 | 71 | this.nodes = this.svg.selectAll("circle") 72 | .data(data); 73 | 74 | this.nodes.enter().append("circle") 75 | .attr("class", "node") 76 | .attr('data-mid', function (d) { return d.id;}) 77 | .attr("cx", function (d) { 78 | return d.x; 79 | }) 80 | .attr("cy", function (d) { 81 | return d.y; 82 | }) 83 | .attr("r", function (d) { 84 | return d.radius; 85 | }) 86 | .style("fill", function (d) { 87 | return that.fill(d[that.colorFieldId]); 88 | }) 89 | .on("mouseenter", showPopover) 90 | .on("mouseleave", removePopovers) 91 | .on("click", removePopovers); 92 | 93 | this.nodes 94 | .attr('data-mid', function (d) { return d.id;}) 95 | .attr("cx", function (d) { 96 | return d.x; 97 | }) 98 | .attr("cy", function (d) { 99 | return d.y; 100 | }) 101 | .attr("r", function (d) { 102 | return d.radius; 103 | }) 104 | .style("fill", function (d) { 105 | return that.fill(d[that.colorFieldId]); 106 | }); 107 | 108 | 109 | this.nodes.exit().remove(); 110 | 111 | this.changeBubblesSize (this.sizeFieldId); 112 | 113 | this.changeBubblesGroup(this.groupFieldId); 114 | 115 | function removePopovers () { 116 | $('.popover').each(function() { 117 | $(this).remove(); 118 | }); 119 | } 120 | 121 | function showPopover (d) { 122 | $(this).popover({ 123 | animation: true, 124 | placement: 'auto top', 125 | container: 'body', 126 | trigger: 'manual', 127 | html : true, 128 | content: that.tooltip(d) 129 | }); 130 | $(this).popover('show', 500); 131 | if(d3){ 132 | d3.select('.popover').style('opacity', 0) 133 | .transition().duration(500) 134 | .style('opacity', 1); 135 | } 136 | } 137 | 138 | }; 139 | 140 | Bubbles.prototype.getCenters = function (fId, size, data) { 141 | var f=this.fieldsH[fId], 142 | centers, 143 | map, 144 | na='N/A'; 145 | 146 | centers = _.uniq(_.pluck(data, fId)).map(function (d) { 147 | return {name: d, value: 1}; 148 | }); 149 | 150 | if(f){ 151 | if(f.type==='lov'){ 152 | var lovH={}; 153 | _.forEach(f.list, function(c){ 154 | lovH[c.id]=c.text; 155 | }); 156 | _.forEach(centers, function(c){ 157 | c.label=lovH[c.name]||na; 158 | }); 159 | centers=centers.sort(Evol.Dico.sortText('label')); 160 | }else if(f.type==='boolean'){ 161 | _.forEach(centers, function(c){ 162 | if(c.name===true){ 163 | c.label = f.labelTrue || Evol.i18n.yes; 164 | }else if(c.name===false){ 165 | c.label = f.labelFalse || Evol.i18n.no; 166 | }else{ 167 | c.label=na; 168 | } 169 | }); 170 | }else if(Evol.Def.fieldIsNumber(f)){ 171 | centers = centers.sort(Evol.Dico.sortNumber('name')); 172 | var c=_.findWhere(centers, {'name': null}); 173 | if(c){ 174 | c.label = na; 175 | } 176 | }/*else{ 177 | centers = _.sortBy(centers, 'name'); 178 | }*/ 179 | } 180 | map = d3.layout.treemap().size(size).ratio(1/1); 181 | map.nodes({children: centers}); 182 | 183 | return centers; 184 | }; 185 | 186 | Bubbles.prototype.changeBubblesGroup = function(groupFieldId){ 187 | var centers = this.getCenters(groupFieldId, [800, 600], this.data); 188 | 189 | this.groupFieldId = groupFieldId; 190 | this.force.on("tick", this.tick(centers, groupFieldId, this.data)); 191 | this.labels(centers); 192 | this.force.start(); 193 | }; 194 | 195 | Bubbles.prototype.changeBubblesColor = function (colorFieldId){ 196 | var that=this; 197 | this.colorFieldId=colorFieldId; 198 | this.fill = d3.scale.category10(); 199 | this.svg.selectAll('circle') 200 | .transition().duration(500) 201 | .style('fill', function(d){ 202 | return colorFieldId?that.fill(d[colorFieldId]):'rgb(31, 119, 180)'; 203 | }); 204 | }; 205 | 206 | Bubbles.prototype.changeBubblesSize = function (sizeFieldId){ 207 | var that=this; 208 | 209 | this.sizeFieldId=sizeFieldId; 210 | var cs=this.svg.selectAll('circle'); 211 | if(sizeFieldId){ 212 | var sizes = _.map(this.data, function(d){ 213 | var v=d[sizeFieldId]; 214 | return (v===null || v===isNaN || _.isUndefined(v))?0:v; 215 | }); 216 | this.plotScale = d3.scale.log().domain([ _.min(sizes), _.max(sizes)]).range([10, 25]); 217 | cs.transition().duration(500) 218 | .attr('r', function(d){ 219 | var v=sizeFieldId?that.plotScale(d[sizeFieldId]||0):10; 220 | if(v===null || _.isNaN(v)){ 221 | v=that.defaultSize; 222 | } 223 | return v; 224 | }); 225 | //.ease("elastic"); 226 | }else{ 227 | cs.transition().duration(500) 228 | .attr('r', that.defaultSize); 229 | //.ease("elastic"); 230 | } 231 | //this.force.start(); 232 | }; 233 | 234 | Bubbles.prototype.tick = function (centers, varname) { 235 | var that=this, 236 | foci = {}; 237 | 238 | for (var i = 0; i < centers.length; i++) { 239 | foci[centers[i].name] = centers[i]; 240 | } 241 | return function (e) { 242 | for (var i = 0; i < that.data.length; i++) { 243 | var o = that.data[i]; 244 | var f = foci[o[varname]]; 245 | o.y += ((f.y + (f.dy / 2)) - o.y) * e.alpha; 246 | o.x += ((f.x + (f.dx / 2)) - o.x) * e.alpha; 247 | } 248 | that.nodes.each(that.collide(0.12, that.data)) 249 | .attr("cx", function (d) { return d.x; }) 250 | .attr("cy", function (d) { return d.y; }); 251 | }; 252 | }; 253 | 254 | Bubbles.prototype.labels = function(centers) { 255 | this.svg.selectAll(".label").remove(); 256 | this.svg.selectAll(".label") 257 | .data(centers) 258 | .enter().append("text") 259 | .attr("class", "label") 260 | .text(function (d) { 261 | return d.label || d.name ; 262 | }) 263 | .attr("transform", function (d) { 264 | return "translate(" + (d.x + (d.dx / 2)) + ", " + (d.y + 20) + ")"; 265 | }); 266 | }; 267 | 268 | Bubbles.prototype.collide = function(alpha, data) { 269 | var quadtree = d3.geom.quadtree(data), 270 | maxRadius=this.maxRadius, 271 | padding=2; 272 | return function (d) { 273 | var r = d.radius + maxRadius + padding, 274 | nx1 = d.x - r, 275 | nx2 = d.x + r, 276 | ny1 = d.y - r, 277 | ny2 = d.y + r; 278 | quadtree.visit(function(quad, x1, y1, x2, y2) { 279 | if (quad.point && (quad.point !== d)) { 280 | var x = d.x - quad.point.x, 281 | y = d.y - quad.point.y, 282 | l = Math.sqrt(x * x + y * y), 283 | r = d.radius + quad.point.radius + padding; 284 | if (l < r) { 285 | l = (l - r) / l * alpha; 286 | d.x -= x *= l; 287 | d.y -= y *= l; 288 | quad.point.x += x; 289 | quad.point.y += y; 290 | } 291 | } 292 | return x1 > nx2 || x2 < nx1 || y1 > ny2 || y2 < ny1; 293 | }); 294 | }; 295 | }; 296 | 297 | return Bubbles; 298 | 299 | }(); 300 | --------------------------------------------------------------------------------