Cargador modulos: modulo ng, validaciones, traducciones

This commit is contained in:
Juan Ferrer Toribio 2017-01-31 14:13:06 +01:00
parent d36d619533
commit abf6a6c142
253 changed files with 5078 additions and 129 deletions

1
client/auth/index.js Normal file
View File

@ -0,0 +1 @@
export * from './src/auth'

10
client/auth/package.json Normal file
View File

@ -0,0 +1,10 @@
{
"name": "@salix/auth",
"version": "0.0.0",
"description": "",
"main": "index.js",
"repository": {
"type": "git",
"url": "http://git.verdnatura.es:/salix"
}
}

4
client/auth/src/auth.js Normal file
View File

@ -0,0 +1,4 @@
export * from './module';
import './config';
export {component as Login} from './login/login'

10
client/auth/src/config.js Normal file
View File

@ -0,0 +1,10 @@
import {module} from './module';
config.$inject = ['$translatePartialLoaderProvider', '$httpProvider'];
export function config($translatePartialLoaderProvider, $httpProvider) {
$translatePartialLoaderProvider.addPart('login');
$httpProvider.defaults.useXDomain = true;
delete $httpProvider.defaults.headers.common['X-Requested-With'];
}
module.config(config);

View File

@ -0,0 +1,6 @@
{
"User": "User",
"Password": "Password",
"Do not close session": "Do not close session",
"Enter": "Enter"
}

View File

@ -0,0 +1,6 @@
{
"User": "Usuario",
"Password": "Contraseña",
"Do not close session": "No cerrar sesión",
"Enter": "Entrar"
}

View File

@ -0,0 +1,19 @@
<div>
<div class="box-wrapper">
<div class="box">
<img src="./logo.svg"/>
<form name="form" ng-submit="$ctrl.submit()">
<vn-textfield label="User" field="$ctrl.model.email"></vn-textfield>
<vn-password label="Password" field="$ctrl.model.password"></vn-password>
<vn-check label="Do not close session" field="$ctrl.model.remember"></vn-check>
<div class="footer">
<vn-submit label="Enter"></vn-submit>
<div class="spinner-wrapper">
<vn-spinner enable="$ctrl.loading"></vn-spinner>
</div>
</div>
</form>
</div>
</div>
<vn-snackbar></vn-snackbar>
</div>

View File

@ -0,0 +1,57 @@
import {module} from '../module';
import './login.scss';
export const component = {
template: require('./login.html'),
controller: controller
};
module.component('vnLogin', component);
controller.$inject = ['$http', '$element'];
function controller($http, $element) {
Object.assign(this, {
submit: function() {
let model = this.model;
if (!(model && model.email && model.password)) {
this.showMessage('Please insert your email and password');
return;
}
this.loading = true;
model.appId = window.location.href;
$http.post('/account', this.model).then(
(json) => this.onLoginOk(json),
(json) => this.onLoginErr(json)
);
},
onLoginOk: function(json) {
this.loading = false;
let data = json.data;
window.location = `${data.location}?access_token=${data.location}`;
},
onLoginErr: function(json) {
this.loading = false;
this.model.password = '';
let message;
switch (json.status) {
case 401:
message = 'Invalid credentials';
break;
case -1:
message = 'Can\'t contact with server';
break;
default:
message = 'Something went wrong';
}
this.showMessage(message);
},
showMessage: function(message) {
let snackbar = $element.find('vn-snackbar').controller('vnSnackbar');
snackbar.show({message: message});
}
});
}

View File

@ -0,0 +1,47 @@
vn-login > div {
position: absolute;
height: 100%;
width: 100%;
margin: 0;
padding: 0;
color: #333;
font-size: 1.1em;
font-weight: normal;
background-color: #3c393b;
.box-wrapper {
position: relative;
max-width: 22em;
margin: auto;
height: inherit;
}
.box {
box-sizing: border-box;
position: absolute;
top: 50%;
width: 100%;
margin-top: -13.5em;
padding: 3em;
background-color: white;
box-shadow: 0 0 1em 0 rgba(1,1,1,.6);
border-radius: .5em;
}
img {
width: 100%;
padding-bottom: 1em;
}
.footer {
margin-top: 1em;
text-align: center;
position: relative;
}
.spinner-wrapper {
position: absolute;
width: 0;
top: .3em;
right: 4em;
overflow: visible;
}
}

View File

@ -0,0 +1,119 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg
xmlns:ns="&amp;#38;ns_sfw;"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
id="Capa_1"
x="0px"
y="0px"
width="400"
height="168.56424"
viewBox="0 0 400 168.56424"
enable-background="new 0 0 560 960"
xml:space="preserve"
inkscape:version="0.91 r13725"
sodipodi:docname="logo.svg"><defs
id="defs43" /><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1016"
id="namedview41"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:zoom="3.09"
inkscape:cx="200"
inkscape:cy="84.28212"
inkscape:window-x="1920"
inkscape:window-y="27"
inkscape:window-maximized="1"
inkscape:current-layer="Capa_1" /><metadata
id="metadata3"><ns:sfw><ns:slices /><ns:sliceSourceBounds
height="212.103"
width="503.32"
y="-235.507"
x="28.34"
bottomLeftOrigin="true" /></ns:sfw><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><g
id="g5"
transform="matrix(0.79472445,0,0,0.79472445,-22.522491,-18.600526)"><g
id="g7"><path
d="M 51.517,90.859 28.34,23.407 l 18.318,0 9.479,34.665 0.776,2.839 c 1.158,4.151 2.041,7.632 2.65,10.44 0.336,-1.372 0.747,-2.992 1.234,-4.854 0.487,-1.862 1.174,-4.306 2.057,-7.328 l 9.942,-35.763 18.22,0 -23.361,67.453 -16.138,0 z"
id="path9"
inkscape:connector-curvature="0"
style="clip-rule:evenodd;fill:#3e3d3d;fill-rule:evenodd" /><path
d="m 523.891,90.859 -16.591,0 c 0.036,-0.791 0.106,-1.614 0.209,-2.466 l 0.354,-2.653 c -2.932,2.285 -5.847,3.974 -8.737,5.071 -2.892,1.096 -5.879,1.644 -8.969,1.644 -4.8,0 -8.23,-1.32 -10.289,-3.957 -2.061,-2.639 -2.463,-6.202 -1.207,-10.688 1.154,-4.121 3.184,-7.47 6.091,-10.048 2.904,-2.577 6.718,-4.385 11.438,-5.423 2.602,-0.548 5.877,-1.144 9.821,-1.788 5.886,-0.915 9.079,-2.258 9.572,-4.027 l 0.337,-1.197 c 0.406,-1.449 0.171,-2.551 -0.706,-3.304 -0.873,-0.754 -2.383,-1.129 -4.521,-1.129 -2.325,0 -4.304,0.476 -5.93,1.43 -1.63,0.953 -2.868,2.353 -3.722,4.201 l -15.015,0 c 2.371,-5.631 5.874,-9.82 10.507,-12.573 4.636,-2.751 10.511,-4.128 17.628,-4.128 4.428,0 8.014,0.535 10.754,1.606 2.739,1.069 4.66,2.69 5.763,4.86 0.753,1.559 1.074,3.417 0.958,5.573 -0.112,2.157 -0.838,5.617 -2.173,10.386 l -5.283,18.874 c -0.633,2.254 -0.926,4.03 -0.884,5.327 0.043,1.295 0.416,2.141 1.118,2.537 l -0.523,1.872 z M 512.532,67.424 c -1.479,0.794 -3.889,1.528 -7.229,2.201 -1.618,0.304 -2.856,0.564 -3.71,0.777 -2.115,0.551 -3.698,1.255 -4.748,2.107 -1.052,0.854 -1.777,2 -2.179,3.435 -0.497,1.771 -0.346,3.199 0.452,4.285 0.801,1.084 2.104,1.626 3.911,1.626 2.787,0 5.284,-0.803 7.496,-2.406 2.208,-1.603 3.677,-3.703 4.402,-6.298 l 1.605,-5.727 z"
id="path11"
inkscape:connector-curvature="0"
style="clip-rule:evenodd;fill:#a3d131;fill-rule:evenodd" /><path
d="m 441.489,90.859 13.951,-49.816 15.682,0 -2.441,8.716 c 2.699,-3.419 5.567,-5.915 8.604,-7.489 3.039,-1.569 6.566,-2.386 10.587,-2.448 l -4.518,16.13 c -0.677,-0.089 -1.354,-0.161 -2.029,-0.206 -0.673,-0.046 -1.315,-0.068 -1.927,-0.068 -2.505,0 -4.682,0.374 -6.525,1.121 -1.843,0.749 -3.471,1.901 -4.886,3.46 -0.902,1.038 -1.758,2.527 -2.558,4.466 -0.803,1.939 -1.808,5.076 -3.026,9.414 l -4.681,16.72 -16.233,0 z"
id="path13"
inkscape:connector-curvature="0"
style="clip-rule:evenodd;fill:#a3d131;fill-rule:evenodd" /><path
d="m 447.466,41.043 -13.947,49.816 -15.961,0 1.923,-6.863 c -2.729,2.77 -5.509,4.812 -8.336,6.121 -2.823,1.309 -5.84,1.962 -9.048,1.962 -5.497,0 -9.239,-1.41 -11.23,-4.23 -1.99,-2.818 -2.208,-7.005 -0.655,-12.554 l 9.591,-34.251 16.325,0 -7.806,27.876 c -1.145,4.097 -1.424,6.917 -0.83,8.461 0.586,1.542 2.146,2.315 4.68,2.315 2.839,0 5.169,-0.94 6.993,-2.818 1.82,-1.881 3.329,-4.945 4.517,-9.194 l 7.459,-26.64 16.325,0 z"
id="path15"
inkscape:connector-curvature="0"
style="clip-rule:evenodd;fill:#a3d131;fill-rule:evenodd" /><path
d="m 361.923,50.894 2.757,-9.85 6.663,0 3.942,-14.073 16.322,0 -3.938,14.073 8.351,0 -2.759,9.85 -8.352,0 -6.042,21.585 c -0.924,3.3 -1.107,5.483 -0.551,6.553 0.559,1.068 2.014,1.603 4.369,1.603 l 1.223,-0.023 0.869,-0.068 -2.914,10.408 c -1.805,0.329 -3.551,0.586 -5.239,0.765 -1.686,0.18 -3.294,0.271 -4.819,0.271 -5.658,0 -9.141,-1.382 -10.447,-4.145 -1.304,-2.763 -0.694,-8.648 1.824,-17.655 l 5.402,-19.293 -6.661,0 z"
id="path17"
inkscape:connector-curvature="0"
style="clip-rule:evenodd;fill:#a3d131;fill-rule:evenodd" /><path
d="m 350.752,90.859 -16.594,0 c 0.037,-0.791 0.106,-1.614 0.21,-2.466 l 0.353,-2.653 c -2.934,2.285 -5.846,3.974 -8.737,5.071 -2.891,1.096 -5.881,1.644 -8.966,1.644 -4.805,0 -8.234,-1.32 -10.292,-3.957 -2.057,-2.639 -2.462,-6.202 -1.204,-10.688 1.152,-4.121 3.184,-7.47 6.088,-10.048 2.909,-2.577 6.72,-4.385 11.442,-5.423 2.599,-0.548 5.872,-1.144 9.818,-1.788 5.885,-0.915 9.077,-2.258 9.573,-4.027 l 0.338,-1.197 c 0.403,-1.449 0.171,-2.551 -0.706,-3.304 -0.873,-0.754 -2.383,-1.129 -4.525,-1.129 -2.324,0 -4.3,0.476 -5.93,1.43 -1.626,0.953 -2.867,2.353 -3.722,4.201 l -15.01,0 c 2.371,-5.631 5.873,-9.82 10.509,-12.573 4.634,-2.751 10.507,-4.128 17.626,-4.128 4.428,0 8.01,0.535 10.749,1.606 2.74,1.069 4.665,2.69 5.765,4.86 0.755,1.559 1.077,3.417 0.961,5.573 -0.117,2.157 -0.837,5.617 -2.178,10.386 l -5.281,18.874 c -0.633,2.254 -0.928,4.03 -0.883,5.327 0.045,1.295 0.417,2.141 1.119,2.537 l -0.523,1.872 z M 339.394,67.424 c -1.48,0.794 -3.893,1.528 -7.233,2.201 -1.616,0.304 -2.853,0.564 -3.71,0.777 -2.115,0.551 -3.696,1.255 -4.746,2.107 -1.052,0.854 -1.777,2 -2.18,3.435 -0.498,1.771 -0.345,3.199 0.456,4.285 0.796,1.084 2.102,1.626 3.908,1.626 2.786,0 5.285,-0.803 7.493,-2.406 2.212,-1.603 3.68,-3.703 4.407,-6.298 l 1.605,-5.727 z"
id="path19"
inkscape:connector-curvature="0"
style="clip-rule:evenodd;fill:#a3d131;fill-rule:evenodd" /><path
d="m 243.068,23.405 -18.893,67.455 -16.32,0 1.835,-6.548 c -2.596,2.712 -5.274,4.716 -8.033,6.011 -2.763,1.297 -5.747,1.946 -8.957,1.946 -6.232,0 -10.613,-2.406 -13.151,-7.215 -2.532,-4.812 -2.708,-11.11 -0.53,-18.896 2.199,-7.851 5.936,-14.246 11.217,-19.196 5.283,-4.947 10.963,-7.421 17.043,-7.421 3.268,0 5.996,0.659 8.181,1.975 2.181,1.316 3.737,3.259 4.668,5.83 l 6.706,-23.94 16.234,0 z m -50.367,42.038 c -1.25,4.457 -1.374,7.868 -0.373,10.234 1.003,2.366 3.062,3.552 6.172,3.552 3.112,0 5.798,-1.169 8.054,-3.505 2.259,-2.335 4.017,-5.764 5.282,-10.281 1.172,-4.181 1.238,-7.416 0.198,-9.706 -1.036,-2.292 -3.097,-3.437 -6.178,-3.437 -2.901,0 -5.534,1.177 -7.901,3.526 -2.367,2.352 -4.117,5.557 -5.254,9.617"
id="path21"
inkscape:connector-curvature="0"
style="clip-rule:evenodd;fill:#3e3d3d;fill-rule:evenodd" /><path
d="m 131.769,90.859 13.949,-49.816 15.682,0 -2.441,8.716 c 2.701,-3.419 5.569,-5.915 8.604,-7.489 3.039,-1.569 13.384,-2.386 17.405,-2.448 l -4.517,16.13 c -0.675,-0.089 -1.351,-0.161 -2.03,-0.206 -0.671,-0.046 -1.315,-0.068 -1.929,-0.068 -2.503,0 -11.494,0.374 -13.339,1.121 -1.845,0.749 -3.471,1.901 -4.886,3.46 -0.902,1.038 -1.756,2.527 -2.556,4.466 -0.803,1.939 -1.812,5.076 -3.029,9.414 l -4.682,16.72 -16.231,0 z"
id="path23"
inkscape:connector-curvature="0"
style="clip-rule:evenodd;fill:#3e3d3d;fill-rule:evenodd" /><path
d="m 114.704,75.192 15.667,0 c -2.994,5.465 -7.055,9.691 -12.186,12.683 -5.126,2.994 -10.866,4.487 -17.218,4.487 -7.727,0 -13.177,-2.345 -16.355,-7.033 -3.176,-4.689 -3.63,-11.081 -1.364,-19.175 2.309,-8.247 6.396,-14.773 12.263,-19.585 5.868,-4.809 12.634,-7.215 20.3,-7.215 7.909,0 13.439,2.446 16.586,7.336 3.151,4.891 3.52,11.644 1.106,20.264 l -0.528,1.813 -0.373,1.079 -33.689,0 c -0.978,3.502 -0.97,6.176 0.027,8.022 0.994,1.843 2.961,2.765 5.895,2.765 2.169,0 4.086,-0.457 5.748,-1.372 1.66,-0.914 3.034,-2.27 4.121,-4.069 m -13.672,-14.543 18.577,-0.043 c 0.834,-3.195 0.687,-5.692 -0.446,-7.489 -1.133,-1.794 -3.116,-2.693 -5.961,-2.693 -2.689,0 -5.083,0.883 -7.183,2.648 -2.1,1.765 -3.759,4.292 -4.987,7.577"
id="path25"
inkscape:connector-curvature="0"
style="clip-rule:evenodd;fill:#3e3d3d;fill-rule:evenodd" /><path
d="m 279.482,91.578 -14.248,-41.467 -14.362,41.467 -16.14,0 21.281,-67.454 18.224,0 9.862,34.664 0.778,2.84 c 1.156,4.151 2.041,7.633 2.65,10.443 l 1.234,-4.857 c 0.487,-1.862 1.172,-4.304 2.057,-7.327 l 9.942,-35.763 18.222,0 -23.364,67.454 -16.136,0 z"
id="path27"
inkscape:connector-curvature="0"
style="fill:#a3d131" /></g><g
id="g29"><path
d="m 122.886,124.71 c -4.603,-5.205 -9.749,-8.869 -15.438,-10.989 -5.693,-2.117 -12.352,-3.179 -19.98,-3.179 -13.804,0 -23.794,2.605 -29.97,7.81 -6.175,5.208 -9.263,12.169 -9.263,20.888 0,4.359 0.755,8.023 2.271,10.989 1.513,2.969 3.874,5.48 7.083,7.538 3.207,2.061 7.294,3.786 12.26,5.177 4.964,1.393 10.898,2.814 17.8,4.268 7.021,1.453 13.378,3.028 19.072,4.723 5.69,1.697 10.535,3.846 14.531,6.448 3.996,2.605 7.083,5.844 9.263,9.718 2.18,3.876 3.27,8.658 3.27,14.349 0,5.449 -1.09,10.234 -3.27,14.35 -2.18,4.117 -5.268,7.568 -9.263,10.353 -3.996,2.787 -8.81,4.876 -14.44,6.267 -5.631,1.391 -11.897,2.089 -18.799,2.089 -10.293,0 -19.557,-1.604 -27.79,-4.813 -8.236,-3.207 -15.802,-8.143 -22.705,-14.803 l 3.633,-4.541 c 6.054,6.176 12.956,10.838 20.707,13.985 7.748,3.15 16.529,4.723 26.337,4.723 12.107,0 21.643,-2.208 28.607,-6.63 6.961,-4.418 10.444,-11.17 10.444,-20.252 0,-4.601 -0.849,-8.506 -2.543,-11.715 -1.697,-3.207 -4.268,-5.932 -7.719,-8.174 -3.451,-2.239 -7.782,-4.178 -12.987,-5.813 -5.208,-1.635 -11.383,-3.179 -18.527,-4.632 -7.024,-1.453 -13.259,-2.966 -18.708,-4.541 -5.449,-1.572 -10.021,-3.57 -13.713,-5.993 -3.695,-2.421 -6.479,-5.387 -8.355,-8.9 -1.879,-3.511 -2.815,-7.93 -2.815,-13.259 0,-5.69 1.09,-10.745 3.27,-15.167 2.18,-4.419 5.236,-8.111 9.172,-11.08 3.934,-2.966 8.688,-5.236 14.258,-6.812 5.568,-1.572 11.806,-2.361 18.708,-2.361 8.355,0 15.649,1.212 21.887,3.633 6.235,2.424 11.957,6.297 17.165,11.625 l -3.453,4.721 z"
id="path31"
inkscape:connector-curvature="0"
style="fill:#f7931e" /><path
d="m 142.321,234.599 55.58,-128.96 5.267,0 55.581,128.96 -6.902,0 -19.072,-44.5 -64.662,0 -19.072,44.5 -6.72,0 z m 58.304,-120.968 -30.696,71.019 60.847,0 -30.151,-71.019 z"
id="path33"
inkscape:connector-curvature="0"
style="fill:#f7931e" /><path
d="m 280.18,234.599 0,-128.96 6.175,0 0,123.148 79.192,0 0,5.813 -85.367,0 z"
id="path35"
inkscape:connector-curvature="0"
style="fill:#f7931e" /><path
d="m 387.523,234.599 0,-128.779 6.176,0 0,128.779 -6.176,0 z"
id="path37"
inkscape:connector-curvature="0"
style="fill:#f7931e" /><path
d="m 420.58,105.639 47.588,60.666 47.77,-60.666 7.266,0 -51.402,65.388 49.949,63.572 -7.266,0 -46.316,-58.85 -46.135,58.85 -7.447,0 49.949,-63.572 -51.402,-65.388 7.446,0 z"
id="path39"
inkscape:connector-curvature="0"
style="fill:#f7931e" /></g></g></svg>

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -0,0 +1,4 @@
import {ng} from 'vendor';
import * as core from 'core';
export const module = ng.module('vnAuth', [core.NAME]);

1
client/client/index.js Normal file
View File

@ -0,0 +1 @@
export * from './src/client';

View File

@ -0,0 +1,10 @@
{
"name": "@salix/client",
"version": "0.0.0",
"description": "",
"main": "index.js",
"repository": {
"type": "git",
"url": "http://git.verdnatura.es:/salix"
}
}

75
client/client/routes.js Normal file
View File

@ -0,0 +1,75 @@
{
"module": "client",
"routes": [
{
"url": "/clients",
"state": "clients",
"component": "vn-client-index"
}, {
"url": "/clients/:id",
"state": "clientCard",
"component": "vn-client-card"
}, {
"url": "/basic-data",
"state": "clientCard.basicData",
"component": "vn-client-basic-data",
"params": {
"client": "card.client"
},
"description": "Datos básicos",
"icon": "person"
}, {
"url": "/fiscal-data",
"state": "clientCard.fiscalData",
"component": "vn-client-fiscal-data",
"params": {
"client": "card.client"
},
"description": "Datos facturación",
"icon": "assignment"
}, {
"url": "/addresses",
"state": "clientCard.addresses",
"component": "vn-client-addresses",
"params": {
"client": "card.client"
},
"description": "Consignatarios",
"icon": "local_shipping"
}, {
"url": "/web-access",
"state": "clientCard.webAccess",
"component": "vn-client-web-access",
"params": {
"client": "card.client"
},
"description": "Acceso web",
"icon": "language"
}, {
"url": "/notes",
"state": "clientCard.notes",
"component": "vn-client-notes",
"params": {
"client": "card.client"
},
"description": "Notas",
"icon": "insert_drive_file"
}, {
"url": "/new-note",
"state": "clientCard.newNote",
"component": "vn-new-note"
},{
"url": "/create",
"state": "create",
"component": "vn-client-create"
}, {
"url": "/address/create",
"state": "clientCard.addressDataCreate",
"component": "vn-client-addresses-data-create"
}, {
"url": "/address/:addressId",
"state": "clientCard.addressDataEdit",
"component": "vn-client-addresses-data-edit"
}
]
}

View File

@ -0,0 +1,39 @@
<form name="form" ng-submit="form.$valid && addressData.submit()" pad-medium>
<vn-card >
<vn-vertical pad-large>
<vn-title>Consignatario</vn-title>
<vn-horizontal>
<vn-check vn-one label="Predeterminado" field="addressData.address.default"></vn-check>
</vn-horizontal>
<vn-horizontal>
<vn-textfield vn-one label="Consignatario" field="addressData.address.consignee" focus></vn-textfield>
<vn-textfield vn-one label="Domicilio" field="addressData.address.street"></vn-textfield>
</vn-horizontal>
<vn-horizontal>
<vn-textfield vn-one label="Código Postal" field="addressData.address.postcode"></vn-textfield>
<vn-textfield vn-one label="Municipio" field="addressData.address.city"></vn-textfield>
<vn-autocomplete vn-one
field="addressData.address.province"
url="/client/api/Provinces"
show-field="name"
value-field="id"
label="Provincia">
</vn-autocomplete>
</vn-horizontal>
<vn-horizontal>
<vn-autocomplete vn-one
field="addressData.address.agency"
url="/client/api/Agencies"
show-field="name"
value-field="id"
label="Agencia">
</vn-autocomplete>
<vn-textfield vn-one label="Teléfono" field="addressData.address.phone"></vn-textfield>
<vn-textfield vn-one label="Móvil" field="addressData.address.mobile"></vn-textfield>
</vn-horizontal>
</vn-vertical>
</vn-card>
<vn-button-bar>
<vn-submit label="Guardar"></vn-submit>
</vn-button-bar>
</form>

View File

@ -0,0 +1,25 @@
import template from './index.html';
import {module} from '../module';
export const NAME = 'vnClientAddressesDataCreate';
export const COMPONENT = {
template: template,
controllerAs: 'addressData',
controller: function($http, $state)
{
var self = this;
this.clientId = $state.params.id;
this.address = {};
this.submit = function(){
this.address.client = self.clientId;
this.address.enabled = true;
$http.post('/client/api/Addresses', this.address).then(
json => $state.go('clientCard.addresses')
);
};
}
}
COMPONENT.controller.$inject = ['$http', '$state'];
module.component(NAME, COMPONENT);

View File

@ -0,0 +1,40 @@
<form name="form" ng-submit="form.$valid && addressData.submit()" pad-medium>
<vn-card>
<vn-vertical pad-large>
<vn-title>Consignatario</vn-title>
<vn-horizontal>
<vn-check vn-one label="Activo" field="addressData.address.enabled"></vn-check>
<vn-check vn-one label="Predeterminado" field="addressData.address.default"></vn-check>
</vn-horizontal>
<vn-horizontal>
<vn-textfield vn-one label="Consignatario" field="addressData.address.consignee"></vn-textfield>
<vn-textfield vn-one label="Domicilio" field="addressData.address.street"></vn-textfield>
</vn-horizontal>
<vn-horizontal>
<vn-textfield vn-one label="Código Postal" field="addressData.address.postcode"></vn-textfield>
<vn-textfield vn-one label="Municipio" field="addressData.address.city"></vn-textfield>
<vn-autocomplete vn-one
field="addressData.address.province"
url="/client/api/Provinces"
show-field="name"
value-field="id"
label="Provincia">
</vn-autocomplete>
</vn-horizontal>
<vn-horizontal>
<vn-autocomplete vn-one
field="addressData.address.agency"
url="/client/api/Agencies"
show-field="name"
value-field="id"
label="Agencia">
</vn-autocomplete>
<vn-textfield vn-one label="Teléfono" field="addressData.address.phone"></vn-textfield>
<vn-textfield vn-one label="Móvil" field="addressData.address.mobile"></vn-textfield>
</vn-horizontal>
</vn-vertical>
</vn-card>
<vn-button-bar>
<vn-submit label="Guardar"></vn-submit>
</vn-button-bar>
</form>

View File

@ -0,0 +1,37 @@
import template from './index.html';
import {module} from '../module';
export const NAME = 'vnClientAddressesDataEdit';
export const COMPONENT = {
template: template,
controllerAs: 'addressData',
controller: function($http, $stateParams, copyObject, equalsObject, $window) {
this.address = {};
$http.get(`/client/api/Addresses/${$stateParams.addressId}`).then(
json => {
this.address = json.data;
this.copyAddress();
}
);
this.submit = function() {
if (!equalsObject(this.address, this.addressOld)) {
$http.put('/client/api/Addresses', this.address).then(
json => {
this.address = json.data;
this.copyAddress();
}
);
}
$window.history.back();
};
this.copyAddress = () => {
this.addressOld = {};
copyObject(this.address, this.addressOld);
};
}
};
COMPONENT.controller.$inject = ['$http', '$stateParams', 'copyObject', 'equalsObject', '$window'];
module.component(NAME, COMPONENT);

View File

@ -0,0 +1,40 @@
<vn-vertical pad-medium>
<vn-card>
<vn-vertical pad-large>
<vn-horizontal>
<vn-title vn-one>Consignatario</vn-title>
</vn-horizontal>
<vn-horizontal ng-repeat="i in address.addresses" class="pad-medium-top" style="align-items: center;">
<vn-auto style="border-radius: .5em;" class="pad-small border-solid" ng-class="{'bg-dark-item': i.default,'bg-opacity-item': !i.enabled && !i.default}">
<vn-horizontal style="align-items: center;">
<vn-auto>
<div><b>{{i.consignee}}</b></div>
<div>{{i.street}}</div>
<div>{{i.city}}, {{i.province}}</div>
<div>{{i.phone}}, {{i.mobile}}</div>
</vn-auto>
<a vn-empty ui-sref="clientCard.addressDataEdit({ addressId: {{i.id}} })"><vn-icon-button icon="edit"></vn-icon-button></a>
</vn-horizontal>
</vn-auto>
</vn-horizontal>
</vn-vertical>
<vn-horizontal>
<vn-one style="text-align:center;">
<paging page="address.currentPage"
page-size="address.numPerPage"
total="address.numPages"
show-prev-next="true"
show-first-last="true"
ul-class="pagination"
active-class="active"
ng-click="address.figureOutToDisplay()">
</paging>
</vn-one>
</vn-horizontal>
</vn-card>
<vn-float-button
fixed-bottom-right
ng-click="address.newAddress()"
icon="add">
</vn-float-button>
</vn-vertical>

View File

@ -0,0 +1,63 @@
import template from './index.html';
import {module} from '../module';
export const NAME = 'vnClientAddresses';
export const COMPONENT = {
template: template,
controllerAs: 'address',
bindings: {
client: '<'
},
controller: function($http, $state) {
var self = this;
let numPerPage = 5;
let numRecords = 0;
this.$onChanges = function(changes) {
if (this.client) {
self.client = this.client;
this.getAddresses();
}
};
this.getAddresses = () => {
var json = JSON.stringify({client: self.client.id});
$http.get(`/client/api/Addresses/count?where=${json}`).then(
json => {
numRecords = json.data.count;
self.getNumPages();
self.figureOutToDisplay();
}
);
};
this.getNumPages = () => {
var nPages = numRecords / numPerPage;
self.numPages = Math.ceil(nPages);
};
this.figureOutToDisplay = () => {
var begin = ((self.currentPage - 1) * numPerPage);
self.getAddress(begin);
};
this.getAddress = function(end) {
var json = JSON.stringify({where: {client: self.client.id}, limit: numPerPage, skip: end});
$http.get(`/client/api/Addresses?filter=${json}`).then(
json => {
self.addresses = json.data;
self.filteredTodos = self.addresses;
}
);
};
this.pageChanged = () => {
self.figureOutToDisplay();
};
this.newAddress = () => {
$state.go("clientCard.addressDataCreate", {id: self.client.id});
};
}
};
COMPONENT.controller.$inject = ['$http', '$state'];
module.component(NAME, COMPONENT);

View File

@ -0,0 +1,32 @@
<form name="form" ng-submit="form.$valid && basicData.submit()" pad-medium>
<vn-card >
<vn-vertical pad-large>
<vn-title>Datos básicos</vn-title>
<vn-horizontal>
<vn-textfield vn-one label="Nombre" field="basicData.client.name" focus></vn-textfield>
<vn-textfield vn-one label="NIF/CIF" field="basicData.client.fi"></vn-textfield>
<vn-textfield autofocus vn-one label="Razón social" field="basicData.client.socialName"></vn-textfield>
</vn-horizontal>
<vn-horizontal>
<vn-textfield vn-one label="Teléfono" field="basicData.client.phone"></vn-textfield>
<vn-textfield vn-one label="Móvil" field="basicData.client.mobile"></vn-textfield>
<vn-textfield vn-one label="Fax" field="basicData.client.fax"></vn-textfield>
</vn-horizontal>
<vn-horizontal>
<vn-textfield vn-one label="Email" field="basicData.client.email"></vn-textfield>
<vn-autocomplete vn-one
field="basicData.client.salesPerson"
url="/client/api/SalesPeople"
show-field="name"
value-field="id"
label="Comercial">
</vn-autocomplete>
<vn-one></vn-one>
</vn-horizontal>
</vn-vertical>
</vn-card>
<vn-button-bar>
<vn-submit label="Guardar"></vn-submit>
</vn-button-bar>
</form>
<vn-dialog-confirm object="basicData.client" object-old="basicData.clientOld" state="basicData.state"></vn-dialog-confirm>

View File

@ -0,0 +1,55 @@
import template from './index.html';
import {module} from '../module';
export const NAME = 'vnClientBasicData';
export const COMPONENT = {
template: template,
controllerAs: 'basicData',
bindings: {
client: '<'
},
controller: function($http, copyObject, equalsObject, $transitions, $element, modified) {
var self = this;
var deregister = $transitions.onStart({ }, callback);
this.$onChanges = function(changes) {
if (this.client) {
this.copyClient();
}
};
this.$onDestroy = function() {
deregister();
};
function callback(transition) {
if (!equalsObject(self.client, self.clientOld)) {
self.state = transition.to().name;
var dialog = $element[0].querySelector('dialog');
dialog.showModal();
return false;
}
}
this.submit = function() {
if (!equalsObject(this.client, this.clientOld)) {
var newClient = modified(this.client, this.clientOld);
newClient.modify = "BasicData";
$http.put(`/client/api/Clients/${this.clientOld.id}`, newClient).then(
json => {
copyObject(json.data, this.client);
this.copyClient();
}
);
}
};
this.copyClient = function() {
this.clientOld = {};
copyObject(this.client, this.clientOld);
};
}
};
COMPONENT.controller.$inject = ['$http', 'copyObject', 'equalsObject', '$transitions', '$element', 'getDataModified'];
module.component(NAME, COMPONENT);

View File

@ -0,0 +1,9 @@
<vn-horizontal>
<vn-empty style="min-width: 18em; padding-left: 1em; padding-bottom: 1em;">
<vn-descriptor client="card.client" class="display-block" ></vn-descriptor>
<vn-left-menu items="card.items"></vn-left-menu>
</vn-empty>
<vn-auto>
<vn-vertical style="max-width: 70em; margin: 0 auto;" ui-view></vn-vertical>
</vn-auto>
</vn-horizontal>

View File

@ -0,0 +1,29 @@
import './style.css';
import template from './card.html';
import {module} from '../module';
const _NAME = 'clientClient';
// export const NAME = module.getName(_NAME);
export const NAME = "vnClientCard";
export const COMPONENT = {
template: template,
controllerAs: 'card',
controller: function($http, $stateParams) {
this.client = null;
$http.get(`/client/api/Clients/${$stateParams.id}?filter[include][account]`).then(
json => this.client = json.data
);
this.items = [];
routes.client.routes.forEach(i => {
if (i.description)
this.items.push({
description: i.description,
icon: i.icon,
href: i.state
});
});
}
};
COMPONENT.controller.$inject = ['$http', '$stateParams'];
module.component(NAME, COMPONENT);

View File

@ -0,0 +1,3 @@
vn-descriptor{
font-family: raleway-bold;
}

View File

@ -0,0 +1,9 @@
<form name="form" ng-submit="form.$valid && $ctrl.submit()" pad-large>
<vn-vertical>
<vn-textfield label="New password" model="$ctrl.newPassword" focus></vn-textfield>
<vn-textfield label="Repeat password" model="$ctrl.repeatPassword"></vn-textfield>
</vn-vertical>
<vn-horizontal margin-large-top>
<vn-submit label="Change password"></vn-submit>
</vn-horizontal>
</form>

View File

@ -0,0 +1,36 @@
import {module} from '../module';
const component = {
template: require('./index.html'),
bindings: {
client: '<',
response: '&'
},
controller: controller
};
module.component('vnClientChangePassword', component);
export default component;
controller.$inject = ['$http', 'vnAppLogger', 'vnDialog'];
function controller($http, logger, dialog) {
this.response = function() {};
this.submit = () => {
try {
if(!this.newPassword)
throw new Error(`Passwords can't be empty`);
if(this.newPassword != this.repeatPassword)
throw new Error(`Passwords don't match`);
let account = {
id: 1,
password: this.newPassword
};
$http.put('/client/api/Accounts', account).then(
() => dialog.hide());
}
catch(e) {
logger.showError(e.message);
}
};
}

View File

@ -0,0 +1,34 @@
export * from './module';
export {NAME as CLIENT_CARD,
COMPONENT as CLIENT_CARD_COMPONENT} from './card/card';
export {NAME as CLIENT_BASIC_DATA_INDEX,
COMPONENT as CLIENT_BASIC_DATA_INDEX_COMPONENT} from './basic-data/index';
export {NAME as CLIENT_ADDRESSES,
COMPONENT as CLIENT_ADDRESSES_COMPONENT} from './addresses/index';
export {NAME as CLIENTS,
COMPONENT as CLIENTS_COMPONENT} from './index/index';
export {NAME as CLIENT_FISCAL_DATA_INDEX,
COMPONENT as CLIENT_FISCAL_DATA_INDEX_COMPONENT} from './fiscal-data/index';
export {NAME as CLIENT_WEB_ACCESS,
COMPONENT as CLIENT_WEB_ACCESS_COMPONENT} from './web-access/index';
export {NAME as CLIENT_DESCRIPTOR,
COMPONENT as CLIENT_DESCRIPTOR_COMPONENT} from './descriptor/descriptor';
export {NAME as CLIENT_NOTES,
COMPONENT as CLIENT_NOTES_COMPONENT} from './notes/index';
export {NAME as CLIENT_SEARCH_PANEL,
COMPONENT as CLIENT_SEARCH_PANEL_COMPONENT} from './search-panel/search-panel';
export {NAME as CLIENT_ITEM,
COMPONENT as CLIENT_ITEM_COMPONENT} from './index/item-client';
export {NAME as CLIENT_CREATE,
COMPONENT as CLIENT_CREATE_COMPONENT} from './create/index';
export {NAME as CLIENT_ADDRESSES_DATA_CREATE_INDEX,
COMPONENT as CLIENT_ADDRESSES_DATA_CREATE_INDEX_COMPONENT} from './addresses-data-create/index';
export {NAME as CLIENT_ADDRESSES_DATA_EDIT_INDEX,
COMPONENT as CLIENT_ADDRESSES_DATA_EDIT_INDEX_COMPONENT} from './addresses-data-edit/index';
export {NAME as CLIENT_CONFIRM_INDEX,
COMPONENT as CLIENT_CONFIRM_INDEX_COMPONENT} from './confirm/index';
export {NAME as NEW_NOTE_INDEX,
COMPONENT as NEW_NOTE_INDEX_COMPONENT} from './new-note/index';
import './change-password/index';

View File

@ -0,0 +1,14 @@
<dialog class="mdl-dialog ">
<vn-vertical class="mdl-dialog__content">
<h6 class="dialog-title">
¿Seguro que quieres salir sin guardar?
</h6>
<h6>
Los cambios que no hayas guardado se perderán
</h6>
</vn-vertical>
<vn-horizontal class="mdl-dialog__actions mdl-dialog__actions--full-width">
<button vn-one type="button" class="mdl-button close" ng-click="dialogConfirm.cancel()">Cancelar</button>
<button vn-one type="button" class="mdl-button" ng-click="dialogConfirm.accept()">Aceptar</button>
</vn-horizontal>
</dialog>

View File

@ -0,0 +1,30 @@
import template from './index.html';
import {module} from '../module';
require('./style.css');
export const NAME = 'vnDialogConfirm';
export const COMPONENT = {
template: template,
controllerAs: 'dialogConfirm',
bindings: {
state: '<',
object: '=',
objectOld: "="
},
controller: function($state, $element, copyObject) {
var dialog = $element.find('dialog')[0];
this.accept = function() {
copyObject(this.objectOld, this.object);
$state.go(this.state);
dialog.close();
};
this.cancel = function() {
dialog.close();
};
}
};
COMPONENT.controller.$inject = ['$state', '$element', 'copyObject'];
module.component(NAME, COMPONENT);

View File

@ -0,0 +1,5 @@
.dialog-title{
color:#424242;
font-family: raleway-bold;
}

View File

@ -0,0 +1,21 @@
<div margin-medium>
<form ng-submit="create.submit()" style="max-width: 70em; margin: 0 auto;">
<vn-card>
<vn-vertical pad-large>
<vn-title>Crear Cliente</vn-title>
<vn-horizontal>
<vn-textfield vn-one label="Nombre" field="create.model.name" focus></vn-textfield>
<vn-textfield vn-one label="NIF/CIF" field="create.model.fi"></vn-textfield>
</vn-horizontal>
<vn-horizontal>
<vn-textfield vn-one label="Razón social" field="create.model.socialName"></vn-textfield>
<vn-one></vn-one>
</vn-horizontal>
</vn-vertical>
</vn-card>
<vn-button-bar>
<vn-submit label="Crear y continuar"></vn-submit>
<vn-button label="Crear" ng-click="create.create()"></vn-button>
</vn-button-bar>
</form>
</div>

View File

@ -0,0 +1,30 @@
import template from './index.html';
import {module} from '../module';
export const NAME = "vnClientCreate";
export const COMPONENT = {
template: template,
controllerAs: "create",
controller: function($http, $state, $window) {
this.submit = function() {
this.create('clientCard.basicData');
};
this.create = state => {
this.model.active = true;
$http.post('/client/api/Clients', this.model).then(
json => this.navigate(json.data.id, state)
);
};
this.navigate = (id, state) => {
if (state)
$state.go(state, {id: id});
else
$window.history.back();
};
}
};
COMPONENT.controller.$inject = ['$http', '$state', '$window'];
module.component(NAME, COMPONENT);

View File

@ -0,0 +1,15 @@
<vn-card>
<vn-vertical class="margin-medium" pad-medium-top pad-medium-bottom>
<vn-horizontal>
<vn-one>
<i class="material-icons descriptor-icon">person</i>
</vn-one>
<vn-vertical vn-two>
<div class="margin-none">{{descriptor.client.id}}</div>
<div class="margin-none">{{descriptor.client.name}}</div>
<div class="margin-none">{{descriptor.client.phone}}</div>
<vn-switch label="Activo" field="descriptor.client.active"></vn-switch>
</vn-vertical>
</vn-horizontal>
</vn-vertical>
</vn-card>

View File

@ -0,0 +1,21 @@
import './style.css';
import template from './descriptor.html';
import {module} from '../module';
export const NAME = 'vnDescriptor';
export const COMPONENT = {
template: template,
controllerAs: 'descriptor',
bindings: {
client: '<'
},
controller: function($http, $scope, copyObject) {
var self = this;
$scope.$watch('descriptor.client.active', function(newValue, oldValue) {
if (oldValue !== undefined)
$http.put(`/client/api/Clients/${self.client.id}/activate`, {});
});
}
};
COMPONENT.controller.$inject = ['$http', '$scope', 'copyObject'];
module.component(NAME, COMPONENT);

View File

@ -0,0 +1,3 @@
.descriptor-icon{
font-size:60px;
}

View File

@ -0,0 +1,69 @@
<form name="form" ng-submit="form.$valid && fiscal.submit()" pad-medium>
<vn-card margin-small-bottom>
<vn-vertical pad-large>
<vn-title>Datos fiscales y de facturación</vn-title>
<vn-horizontal>
<vn-check vn-one label="Facturar" field="fiscal.client.hasToInvoice"></vn-check>
<vn-check vn-one label="Factura impresa" field="fiscal.client.invoiceByEmail"></vn-check>
</vn-horizontal>
<vn-horizontal>
<vn-textfield vn-two label="Domicilio fiscal" field="fiscal.client.street" focus></vn-textfield>
<vn-textfield vn-one label="Municipio" field="fiscal.client.city"></vn-textfield>
</vn-horizontal>
<vn-horizontal>
<vn-textfield vn-one label="Código postal" field="fiscal.client.postcode"></vn-textfield>
<vn-autocomplete vn-one
field="fiscal.client.province"
url="/client/api/Provinces"
show-field="name"
value-field="id"
label="Provincia">
</vn-autocomplete>
<vn-autocomplete vn-one
field="fiscal.client.country"
url="/client/api/Countries"
show-field="name"
value-field="id"
label="País">
</vn-autocomplete>
</vn-horizontal>
</vn-vertical>
</vn-card>
<vn-card margin-small-bottom>
<vn-vertical pad-large>
<vn-title>Información de facturación</vn-title>
<vn-horizontal>
<vn-textfield vn-two label="IBAN" field="fiscal.client.iban"></vn-textfield>
<vn-autocomplete vn-two
field="fiscal.client.payMethod"
url="/client/api/PaymentMethods"
show-field="name"
value-field="id"
label="Forma de pago">
</vn-autocomplete>
<vn-textfield vn-one label="Vencimiento" field="fiscal.client.dueDay"></vn-textfield>
</vn-horizontal>
<vn-horizontal>
<vn-textfield vn-one label="Crédito" field="fiscal.client.credit"></vn-textfield>
<vn-textfield vn-one label="CyC" field="fiscal.client.cyc"></vn-textfield>
<vn-textfield vn-one label="IAE" field="fiscal.client.gestdoc"></vn-textfield>
<vn-check vn-two label="Recargo de equivalencia" field="fiscal.client.surcharge"></vn-check>
</vn-horizontal>
</vn-vertical>
</vn-card>
<vn-card margin-small-bottom>
<vn-vertical pad-large>
<vn-title>Documentación</vn-title>
<vn-horizontal>
<vn-check vn-one label="Recibido core VNH" field="fiscal.client.coreVnh"></vn-check>
<vn-check vn-one label="Recibido core VNL" field="fiscal.client.coreVnl"></vn-check>
<vn-check vn-one label="Recibido B2B VNL" field="fiscal.client.sepaVnl"></vn-check>
</vn-horizontal>
</vn-vertical>
</vn-card>
<vn-button-bar>
<vn-submit label="Guardar"></vn-submit>
</vn-button-bar>
</form>
<vn-dialog-confirm object="fiscal.client" object-old="fiscal.clientOld" state="fiscal.state"></vn-dialog-confirm>

View File

@ -0,0 +1,55 @@
import template from './index.html';
import {module} from '../module';
export const NAME = 'vnClientFiscalData';
export const COMPONENT = {
template: template,
controllerAs: 'fiscal',
bindings: {
client: '<'
},
controller: function($http, copyObject, equalsObject, $transitions, $element, modified) {
var self = this;
var deregister = $transitions.onStart({ }, callback);
this.submit = function() {
if (!equalsObject(this.client, this.clientOld)) {
var newClient = modified(this.client, this.clientOld);
newClient.modify = "FiscalData";
$http.put(`/client/api/Clients/${this.clientOld.id}`, newClient).then(
json => {
this.client = json.data;
this.copyClient();
}
);
}
};
this.$onChanges = function(changes) {
if (this.client) {
this.copyClient();
}
};
this.$onDestroy = function() {
deregister();
};
function callback(transition) {
if (!equalsObject(self.client, self.clientOld)) {
self.state = transition.to().name;
var dialog = $element[0].querySelector('dialog');
dialog.showModal();
return false;
}
}
this.copyClient = function() {
this.clientOld = {};
copyObject(this.client, this.clientOld);
};
}
};
COMPONENT.controller.$inject = ['$http', 'copyObject', 'equalsObject', '$transitions', '$element', 'getDataModified'];
module.component(NAME, COMPONENT);

View File

@ -0,0 +1,20 @@
<div margin-medium>
<div style="max-width: 40em; margin: 0 auto;">
<vn-card>
<vn-horizontal pad-medium>
<vn-searchbar
vn-auto model="search.filter"
search="search.find()"
advanced="true"
popover="vn-client-search-panel">
</vn-searchbar>
</vn-horizontal>
</vn-card>
<vn-card margin-medium-top>
<vn-item-client ng-repeat="client in search.clients" title="View client" client="client"></vn-item-client>
</vn-card>
</div>
<a ui-sref="create" fixed-bottom-right>
<vn-float-button icon="person_add"></vn-float-button>
</a>
</div>

View File

@ -0,0 +1,53 @@
import template from './index.html';
import {module} from '../module';
require('./style.css');
export const NAME = 'vnClientIndex';
export const COMPONENT = {
template: template,
controllerAs: 'search',
controller: function($http) {
this.clients = [];
this.find = function() {
var where = null;
var filter = this.filter;
var queryStr = '/client/api/Clients';
var search = filter.search;
if (search)
where = {name: {ilike: search}};
var params = filter.params;
if (params) {
where = {};
let partials = {
alias: true,
name: true,
socialName: true,
city: true,
email: true
};
for (let param in params)
if (params[param]) {
if (partials[param])
where[param] = {ilike: params[param]};
else
where[param] = params[param];
}
filter.params = undefined;
}
if (where) {
let json = JSON.stringify({where: where});
queryStr = `${queryStr}?filter=${json}`;
}
$http.get(queryStr).then(
json => this.clients = json.data
);
};
this.filter = {};
this.find();
}
};
COMPONENT.controller.$inject = ['$http'];
module.component(NAME, COMPONENT);

View File

@ -0,0 +1,7 @@
<a ui-sref="clientCard.basicData({ id: {{itemClient.client.id}} })" pad-medium border-solid-bottom>
<div class="vn-item-client-name">{{itemClient.client.name}}</div>
<div>Id Cliente: <b>{{itemClient.client.id}}</b></div>
<div>Teléfono: <b>{{itemClient.client.phone}}</b></div>
<div>Población: <b>{{itemClient.client.city}}</b></div>
<div>email: <b>{{itemClient.client.email}}</b></div>
</a>

View File

@ -0,0 +1,12 @@
import template from './item-client.html';
import {module} from '../module';
export const NAME = 'vnItemClient';
export const COMPONENT = {
template: template,
controllerAs: 'itemClient',
bindings: {
client: '<'
}
};
module.component(NAME, COMPONENT);

View File

@ -0,0 +1,16 @@
vn-item-client {
display: block;
}
vn-item-client a {
display: block;
text-decoration: none;
color: inherit;
}
vn-item-client a:hover {
color: white;
background-color: #424242;
}
.vn-item-client-name{
font-family: raleway-bold;
}

View File

@ -0,0 +1 @@
{}

View File

@ -0,0 +1 @@
{}

View File

@ -0,0 +1,5 @@
import {ng} from 'vendor';
import * as core from 'core';
export const NAME = 'client';
export const module = ng.module(NAME, []);

View File

@ -0,0 +1,12 @@
<form name="form" ng-submit="form.$valid && newNote.submit()" pad-medium>
<vn-card>
<vn-vertical pad-large>
<vn-title>Nueva nota</vn-title>
<vn-textarea label="Nueva nota" model="newNote.note.text" focus padd-medium-top></vn-textarea>
</vn-vertical>
</vn-card>
<vn-button-bar>
<vn-submit label="Guardar"></vn-submit>
</vn-button-bar>
</form>
<vn-dialog-confirm object="newNote.note" object-old="newNote.noteOld" state="newNote.state"></vn-dialog-confirm>

View File

@ -0,0 +1,54 @@
import template from './index.html';
import {module} from '../module';
export const NAME = 'vnNewNote';
export const COMPONENT = {
template: template,
controllerAs: 'newNote',
controller: function($http, $state, copyObject, equalsObject, $transitions, $element) {
this.client = $state.params.id;
this.note = {text: null};
var self = this;
var deregister = $transitions.onStart({ }, callback);
copyNote();
this.submit = function() {
if (this.note) {
let observation = this.createNote();
$http.post('/client/api/ClientObservations', observation).then(
json => {
this.note = json.data;
copyNote();
$state.go('clientCard.notes');
}
);
}
};
this.$onDestroy = () => {
deregister();
};
this.createNote = () => {
let observation = {client: this.client, text: this.note.text, salesPerson: 'user', modify: 'ClientObservation'};
return observation;
};
function callback(transition) {
if (!equalsObject(self.note, self.noteOld)) {
self.state = transition.to().name;
var dialog = $element[0].querySelector('dialog');
dialog.showModal();
return false;
}
}
function copyNote() {
self.noteOld = {};
copyObject(self.note, self.noteOld);
}
}
};
COMPONENT.controller.$inject = ['$http', '$state', 'copyObject', 'equalsObject', '$transitions', '$element'];
module.component(NAME, COMPONENT);

View File

@ -0,0 +1,17 @@
<vn-card ng-show="observation.observations.length" pad-medium>
<vn-vertical pad-large>
<vn-title>Notas</vn-title>
<vn-horizontal ng-repeat="n in observation.observations" margin-small-bottom style="align-items: center;">
<vn-auto style="border-radius: .3em;" class="pad-small border-solid">
<div class="notes-date">{{n.creationDate | date:'dd/MM/yyyy HH:mm'}}</div>
<div class="notes-date">{{n.salesPerson}}</div>
<div>{{n.text}}</div>
</vn-auto>
</vn-horizontal>
</vn-vertical>
</vn-card>
<vn-float-button
fixed-bottom-right
ng-click="observation.newObservation()"
icon="add">
</vn-float-button>

View File

@ -0,0 +1,34 @@
import './style.css';
import template from './index.html';
import {module} from '../module';
export const NAME = 'vnClientNotes';
export const COMPONENT = {
template: template,
controllerAs: 'observation',
bindings: {
client: '<'
},
controller: function($http, $state) {
this.$onChanges = function(changes) {
if (this.client) {
this.getObservation(this.client.id);
}
};
this.getObservation = function(clientId) {
let json = JSON.stringify({where: {client: this.client.id}, order: 'creationDate DESC'});
$http.get(`/client/api/clientObservations?filter=${json}`).then(
json => {
this.observations = json.data;
}
);
};
this.newObservation = () => {
$state.go("clientCard.newNote", {id: this.client.id});
};
}
};
COMPONENT.controller.$inject = ['$http', '$state'];
module.component(NAME, COMPONENT);

View File

@ -0,0 +1,3 @@
.notes-date{
font-family: raleway-bold;
}

View File

@ -0,0 +1,26 @@
<div pad-large style="min-width: 30em;">
<form name="form" ng-submit="form.$valid && $ctrl.onSubmit()">
<vn-horizontal>
<vn-textfield vn-one label="Id Cliente" model="$ctrl.filter.id"></vn-textfield>
<vn-textfield vn-one label="NIF/CIF" model="$ctrl.filter.fi"></vn-textfield>
</vn-horizontal>
<vn-horizontal>
<vn-textfield vn-one label="Nombre" model="$ctrl.filter.name"></vn-textfield>
</vn-horizontal>
<vn-horizontal>
<vn-textfield vn-one label="Razon Social" model="$ctrl.filter.socialName"></vn-textfield>
</vn-horizontal>
<vn-horizontal>
<vn-textfield vn-one label="Población" model="$ctrl.filter.city"></vn-textfield>
<vn-textfield vn-one label="Código Postal" model="$ctrl.filter.postcode"></vn-textfield>
</vn-horizontal>
<vn-horizontal>
<vn-textfield vn-one label="Email" model="$ctrl.filter.email"></vn-textfield>
<vn-textfield vn-one label="Teléfono" model="$ctrl.filter.phone"></vn-textfield>
</vn-horizontal>
<vn-horizontal margin-large-top>
<vn-submit label="Search"></vn-submit>
</vn-horizontal>
</form>
</div>

View File

@ -0,0 +1,10 @@
import {module} from '../module';
export const NAME = 'vnClientSearchPanel';
export const COMPONENT = {
template: require('./search-panel.html'),
controller: function($scope) {
this.onSubmit = function() {}
}
};
module.component(NAME, COMPONENT);

View File

@ -0,0 +1,14 @@
<form name="form" ng-submit="form.$valid && web.submit()" pad-medium >
<vn-card>
<vn-vertical pad-large>
<vn-title>Web access</vn-title>
<vn-check label="Acceso Web" field="web.account.active"></vn-check>
<vn-textfield label="Usuario" class="margin-medium-top" field="web.account.name" focus></vn-textfield>
</vn-vertical>
</vn-card>
<vn-button-bar>
<vn-submit label="Guardar"></vn-submit>
<vn-button label="Cambiar password" vn-dialog="vn-client-change-password"></vn-button>
</vn-button-bar>
</form>
<vn-dialog-confirm object="web.account" object-old="web.accountOld" state="web.state"></vn-dialog-confirm>

View File

@ -0,0 +1,65 @@
import template from './index.html';
import {module} from '../module';
export const NAME = 'vnClientWebAccess';
export const COMPONENT = {
template: template,
controllerAs: 'web',
bindings: {
client: '<'
},
controller: function($http, copyObject, equalsObject, $transitions, $element, modified) {
var self = this;
var deregister = $transitions.onStart({ }, callback);
this.submit = function() {
if (!equalsObject(this.account, this.accountOld)) {
var newAccount = modified(this.account, this.accountOld);
newAccount.modify = "WebAccess";
if (this.account.id) {
$http.put(`/client/api/Accounts/${this.client.id}`, newAccount).then(
json => {
this.client.account = json.data;
self.copyAccount();
}
);
} else {
newAccount.id = this.client.id;
$http.post('/client/api/Accounts', newAccount).then(
json => {
this.client.account = json.data;
copyObject(this.client.account, this.accountOld);
}
);
}
}
};
this.$onChanges = function(changes) {
if (this.client) {
this.copyAccount();
}
};
this.$onDestroy = function() {
deregister();
};
function callback(transition) {
if (!equalsObject(self.client.account, self.accountOld)) {
self.state = transition.to().name;
var dialog = $element[0].querySelector('dialog');
dialog.showModal();
return false;
}
}
this.copyAccount = function() {
this.account = this.client.account;
this.accountOld = {};
copyObject(this.client.account, this.accountOld);
};
}
};
COMPONENT.controller.$inject = ['$http', 'copyObject', 'equalsObject', '$transitions', '$element', 'getDataModified'];
module.component(NAME, COMPONENT);

2
client/core/index.js Normal file
View File

@ -0,0 +1,2 @@
export * from './src/core'

10
client/core/package.json Normal file
View File

@ -0,0 +1,10 @@
{
"name": "@salix/core",
"version": "0.0.0",
"description": "",
"main": "index.js",
"repository": {
"type": "git",
"url": "http://git.verdnatura.es:/salix"
}
}

1
client/core/src/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
node_modules

View File

@ -0,0 +1,368 @@
import {module} from '../module';
import './index.mdl';
import './style.scss';
export const component = {
transclude: true,
bindings: {
url: '@',
showField: '@',
valueField: '@',
model: '='
},
template: template,
controller: controller
};
module.component('vnAutocomplete', component);
template.$inject = ['$element', '$attrs', 'vnInputAttrsNormalizer', 'vnResolveDefaultComponent'];
function template($element, $attrs, normalizer, resolve) {
normalizer.normalize($attrs);
return resolve.getTemplate('autocomplete', $attrs);
}
controller.$inject = ['$http', '$element', '$attrs', '$scope', '$parse', '$document', 'vnPopover'];
function controller($http, $element, $attrs, $scope, $parse, $document, popoverProvider) {
let locked = false;
$scope.$watch($attrs.model, (newValue) => {
if(!locked) {
locked = true;
this.setValue(newValue);
locked = false;
}
});
componentHandler.upgradeElement($element[0].firstChild);
function mdlUpdate() {
let mdlField = $element[0].firstChild.MaterialTextfield;
if (mdlField)
mdlField.updateClasses_();
}
Object.assign(this, {
init: function() {
this.input = $element[0].querySelector('input');
this.item = null;
this.data = null;
this.popover = null;
this.popoverData = null;
this.timeoutId = null;
this.lastSearch = null;
this.lastRequest = null;
this.currentRequest = null;
this.moreData = false;
this.activeOption = -1;
this.maxRows = 10;
this.requestDelay = 350;
this.requestItem();
},
loadData: function(textFilter) {
textFilter = textFilter ? textFilter : '';
if(this.lastSearch === textFilter) {
this.popoverDataReady();
return;
}
this.lastSearch = textFilter;
let lastRequest = this.lastRequest;
let requestWillSame = lastRequest !== null
&& !this.moreData
&& textFilter.substr(0, lastRequest.length) === lastRequest;
if(requestWillSame)
this.localFilter(textFilter);
else
this.requestData(textFilter, false);
},
getRequestFields: function() {
let fields = {};
fields[this.valueField] = true;
fields[this.showField] = true;
return fields;
},
requestData: function(textFilter, append) {
let where = {};
let skip = 0;
if(textFilter)
where[this.showField] = {ilike: textFilter};
if(append && this.data)
skip = this.data.length;
let filter = {
fields: this.getRequestFields(),
where: where,
order: `${this.showField} ASC`,
skip: skip,
limit: this.maxRows
};
this.lastRequest = textFilter ? textFilter : '';
let json = JSON.stringify(filter);
if(this.currentRequest)
this.currentRequest.resolve();
this.currentRequest = $http.get(`${this.url}?filter=${json}`);
this.currentRequest.then(
json => this.onRequest(json.data, append),
json => this.onRequest([])
);
},
onRequest: function(data, append) {
this.currentRequest = null;
this.moreData = data.length >= this.maxRows;
if(!append || !this.data)
this.data = data;
else
this.data = this.data.concat(data);
this.setPopoverData(this.data);
},
localFilter: function(textFilter) {
let regex = new RegExp(textFilter, 'i');
let data = this.data.filter((item) => {
return regex.test(item[this.showField]);
});
this.setPopoverData(data);
},
setPopoverData: function(data) {
this.popoverData = data;
this.popoverDataReady();
},
popoverDataReady: function() {
if(this.hasFocus)
this.showPopover();
},
showPopover: function() {
if(!this.data) return;
let fragment = $document[0].createDocumentFragment();
let data = this.popoverData;
for(let i = 0; i < data.length; i++) {
let li = $document[0].createElement('li');
li.appendChild($document[0].createTextNode(data[i][this.showField]));
fragment.appendChild(li);
}
if(this.moreData) {
let li = $document[0].createElement('li');
li.appendChild($document[0].createTextNode('Load more'));
li.className = 'load-more';
fragment.appendChild(li);
}
if (!this.popover) {
let popover = $document[0].createElement('ul');
popover.addEventListener('click',
(e) => this.onPopoverClick(e));
popover.addEventListener('mousedown',
(e) => this.onPopoverMousedown(e));
popover.className = 'vn-autocomplete';
popover.appendChild(fragment);
popoverProvider.show(popover, this.input);
this.popover = popover;
}
else {
this.popover.innerHTML = '';
this.popover.appendChild(fragment);
}
},
hidePopover: function() {
if(!this.popover) return;
this.activeOption = -1;
popoverProvider.hide();
this.popover = null;
},
selectPopoverOption: function(index) {
if(!this.popover || index == -1) return;
if(index < this.popoverData.length) {
this.selectOptionByDataIndex(this.popoverData, index);
this.hidePopover();
}
else
this.requestData(this.lastRequest, true);
},
onPopoverClick: function(event) {
let childs = this.popover.childNodes;
for(let i = 0; i < childs.length; i++)
if(childs[i] === event.target) {
this.selectPopoverOption(i);
break;
}
},
onPopoverMousedown: function(event) {
// Prevents input from loosing focus
event.preventDefault();
},
onClick: function(event) {
if(!this.popover)
this.showPopover();
},
onFocus: function() {
this.hasFocus = true;
this.input.select();
if(this.data)
this.showPopover();
else
this.loadData();
},
onBlur: function() {
this.hasFocus = false;
this.restoreShowValue();
this.hidePopover();
},
onKeydown: function(event) {
switch(event.keyCode) {
case 13: // Enter
this.selectPopoverOption(this.activeOption);
break;
case 27: // Escape
this.restoreShowValue();
this.input.select();
break;
case 38: // Arrow up
this.activateOption(this.activeOption-1);
break;
case 40: // Arrow down
this.activateOption(this.activeOption+1);
break;
default:
return;
}
event.preventDefault();
},
onKeyup: function(event) {
if(!this.isKeycodePrintable(event.keyCode)) return;
if(this.timeoutId) clearTimeout(this.timeoutId);
this.timeoutId = setTimeout(() => this.onTimeout(), this.requestDelay);
},
onTimeout: function() {
this.loadData(this.input.value);
this.timeoutId = null;
},
isKeycodePrintable: function(keyCode) {
return keyCode == 32 // Spacebar
|| keyCode == 8 // Backspace
|| (keyCode > 47 && keyCode < 58) // Numbers
|| (keyCode > 64 && keyCode < 91) // Letters
|| (keyCode > 95 && keyCode < 112) // Numpad
|| (keyCode > 185 && keyCode < 193) // ;=,-./`
|| (keyCode > 218 && keyCode < 223); // [\]'
},
restoreShowValue: function() {
this.putItem(this.item);
},
requestItem: function() {
if(!this.model) return;
let where = {};
where[this.valueField] = this.model;
let filter = {
fields: this.getRequestFields(),
where: where,
};
let json = JSON.stringify(filter);
$http.get(`${this.url}?filter=${json}`).then(
json => this.onItemRequest(json.data),
json => this.onItemRequest(null)
);
},
onItemRequest: function(data) {
if(data && data.length > 0)
this.showItem(data[0]);
else
this.showItem(null);
},
activateOption: function(index) {
if(!this.popover)
this.showPopover();
let popover = this.popover;
let childs = popover.childNodes;
let len = this.popoverData.length;
if(this.activeOption >= 0)
childs[this.activeOption].className = '';
if(index >= len)
index = 0;
else if(index < 0)
index = len - 1;
if (index >= 0) {
let opt = childs[index];
let top = popover.scrollTop;
let height = popover.clientHeight;
if(opt.offsetTop + opt.offsetHeight > top + height)
top = opt.offsetTop + opt.offsetHeight - height;
else if(opt.offsetTop < top)
top = opt.offsetTop;
opt.className = 'active';
popover.scrollTop = top;
}
this.activeOption = index;
},
setValue: function(value) {
if(value) {
let data = this.data;
if(data)
for(let i = 0; i < data.length; i++)
if(data[i][this.valueField] == value) {
this.putItem(data[i]);
return;
}
this.requestItem();
}
else
this.putItem(null);
},
selectOptionByIndex: function(index) {
this.selectOptionByDataIndex(this.data, index);
},
selectOptionByDataIndex: function(data, index) {
if(data && index >= 0 && index < data.length)
this.putItem(data[index]);
else
this.putItem(null);
},
putItem: function(item) {
this.showItem(item);
let value = item ? item[this.valueField] : undefined;
if(!locked) {
setTimeout (() => {
$scope.$apply(function () {
locked = true;
$parse($attrs.model).assign($scope, value);
locked = false;
});
});
}
},
showItem: function(item) {
this.input.value = item ? item[this.showField] : '';
this.item = item;
mdlUpdate();
}
});
this.init();
}

View File

@ -0,0 +1,14 @@
<div class="mdl-textfield mdl-js-textfield *[className]*">
<input
class="mdl-textfield__input"
type="text"
rule="*[rule]*"
*[enabled]*
*[focus]*
ng-keydown="$ctrl.onKeydown($event)"
ng-click="$ctrl.onClick($event)"
ng-keyup="$ctrl.onKeyup($event)"
ng-focus="$ctrl.onFocus($event)"
ng-blur="$ctrl.onBlur($event)"/>
<label class="mdl-textfield__label" translate>*[label]*</label>
</div>

View File

@ -0,0 +1,11 @@
import {module} from '../module';
export function factory() {
return {
template: require('./index.mdl.html'),
default: {
className: 'mdl-textfield--floating-label'
}
}
}
module.factory('vnAutocompleteMdlFactory', factory);

View File

@ -0,0 +1,25 @@
ul.vn-autocomplete {
list-style-type: none;
padding: 1em;
margin: 0;
padding: 0;
overflow: auto;
max-height: 300px;
li {
display: block;
padding: .8em;
margin: 0;
cursor: pointer;
&.active,
&:hover {
background-color: rgba(1,1,1,.1);
}
&.load-more {
color: #ffa410;
font-weight: bold;
padding: .4em .8em;
}
}
}

View File

@ -0,0 +1,2 @@
<!-- por definir -->

View File

@ -0,0 +1,24 @@
import {module as _module} from '../module';
import * as util from '../util';
import * as constant from '../constants';
import template from './button.bt.html';
const _NAME = 'button';
const DEFAULT_CLASS = '';
const DEFAULT_TEXT = 'Button';
export const NAME = util.getFactoryName(_NAME + constant.BOOTSTRAP_FRAMEWORK);
export function factory() {
return {
template: template,
default: {
text: DEFAULT_TEXT,
className: DEFAULT_CLASS,
enabled: 'true',
typeName: 'button'
}
}
}
_module.factory(NAME, factory);

View File

@ -0,0 +1,18 @@
import {module as _module} from '../module';
import * as resolveFactory from '../resolveDefaultComponents';
import * as util from '../util';
const _NAME = 'button';
export const NAME = util.getName(_NAME);
directive.$inject = [resolveFactory.NAME];
export function directive(resolve) {
return {
restrict: 'E',
template: function(_, attr) {
return resolve.getTemplate(_NAME, attr);
}
};
}
_module.directive(NAME, directive);

View File

@ -0,0 +1,3 @@
<button type = "*[typeName]*" class="*[className]*" *[enabled]* translate>
*[label]*
</button>

View File

@ -0,0 +1,21 @@
import {module as _module} from '../module';
import * as util from '../util';
import * as constant from '../constants';
import template from './button.mdl.html';
const _NAME = 'button';
export const NAME = util.getFactoryName(_NAME + constant.MATERIAL_DESIGN_FRAMEWORK);
export function factory() {
return {
template: template,
default: {
label: 'Submit',
className: 'mdl-button mdl-js-button mdl-button--raised mdl-button--colored',
enabled: 'true',
typeName: 'button'
}
}
}
_module.factory(NAME, factory);

View File

@ -0,0 +1,21 @@
import {module as _module} from '../module';
import * as resolveFactory from '../resolveDefaultComponents';
import * as util from '../util';
require ('./style.css');
const _NAME = 'card';
export const NAME = util.getName(_NAME);
directive.$inject = [resolveFactory.NAME];
export function directive(resolve) {
return {
restrict: 'E',
transclude: true,
template: function(_, attr) {
return resolve.getTemplate(_NAME, attr);
}
};
}
_module.directive(NAME, directive);

View File

@ -0,0 +1 @@
<div class="demo-card-wide mdl-shadow--2dp bg-panel" *[foo]* ng-transclude></div>

View File

@ -0,0 +1,16 @@
import {module as _module} from '../module';
import * as util from '../util';
import * as constant from '../constants';
import template from './card.mdl.html';
const _NAME = 'card';
export const NAME = util.getFactoryName(_NAME + constant.MATERIAL_DESIGN_FRAMEWORK);
export function factory() {
return {
template: template
}
}
_module.factory(NAME, factory);

View File

@ -0,0 +1,3 @@
vn-card {
display: block;
}

View File

@ -0,0 +1,2 @@
<!-- por definir -->

View File

@ -0,0 +1 @@
// por definir

View File

@ -0,0 +1,28 @@
import {module as _module} from '../module';
import * as resolveFactory from '../resolveDefaultComponents';
import * as normalizerFactory from '../inputAttrsNormalizer';
import * as util from '../util';
const _NAME = 'check';
export const NAME = util.getName(_NAME);
directive.$inject = [resolveFactory.NAME, normalizerFactory.NAME];
export function directive(resolve, normalizer) {
return {
restrict: 'E',
template: function(_, attrs) {
normalizer.normalize(attrs);
return resolve.getTemplate(_NAME, attrs);
},
link: function(scope, element, attrs) {
scope.$watch(attrs.model, () => {
let mdlField = element[0].firstChild.MaterialCheckbox;
if (mdlField)
mdlField.updateClasses_();
});
componentHandler.upgradeElement(element[0].firstChild);
}
};
}
_module.directive(NAME, directive);

View File

@ -0,0 +1,4 @@
<label class="mdl-checkbox mdl-js-checkbox mdl-js-ripple-effect">
<input type="checkbox" name="*[name]*" class="*[className]*" name="*[name]*" ng-model="*[model]*" rule="*[rule]*" *[enabled]* *[focus]*>
<span class="mdl-checkbox__label" translate>*[label]*</span>
</label>

View File

@ -0,0 +1,21 @@
import {module as _module} from '../module';
import * as util from '../util';
import * as constant from '../constants';
import template from './check.mdl.html';
const _NAME = 'check';
const DEFAULT_CLASS = 'mdl-checkbox__input';
export const NAME = util.getFactoryName(_NAME + constant.MATERIAL_DESIGN_FRAMEWORK);
export function factory() {
return {
template: template,
default: {
enabled: 'true',
className: DEFAULT_CLASS
}
};
}
_module.factory(NAME, factory);

View File

@ -0,0 +1,28 @@
import {module as _module} from '../module';
import * as resolveFactory from '../resolveDefaultComponents';
import * as normalizerFactory from '../inputAttrsNormalizer';
import * as util from '../util';
const _NAME = 'combo';
export const NAME = util.getName(_NAME);
directive.$inject = [resolveFactory.NAME, normalizerFactory.NAME];
export function directive(resolve, normalizer) {
return {
restrict: 'E',
transclude: true,
template: function(_, attrs) {
normalizer.normalize(attrs);
return resolve.getTemplate(_NAME, attrs);
},
link: function(scope, element, attrs) {
scope.$watch(attrs.model, () => {
let mdlField = element[0].firstChild.MaterialTextfield;
if (mdlField)
mdlField.updateClasses_();
});
componentHandler.upgradeElement(element[0].firstChild);
}
};
}
_module.directive(NAME, directive);

View File

@ -0,0 +1,5 @@
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
<select class="mdl-textfield__input" class="*[className]*" name="*[name]*" ng-model="*[model]*" rule="*[rule]*" *[enabled]* ng-transclude>
</select>
<label class="mdl-textfield__label" translate>*[label]*</label>
</div>

View File

@ -0,0 +1,14 @@
import {module} from '../module';
import template from './combo.mdl.html';
export const NAME = 'vnComboMdlFactory';
export function factory() {
return {
template: template,
default: {
label: 'Label',
enabled: 'enabled'
}
}
}
module.factory(NAME, factory);

21
client/core/src/config.js Normal file
View File

@ -0,0 +1,21 @@
import {module} from './module';
config.$inject = ['$translateProvider', '$translatePartialLoaderProvider'];
export function config($translateProvider, $translatePartialLoaderProvider) {
$translatePartialLoaderProvider.addPart('core');
let conf = {urlTemplate: '/static/locale/{part}/{lang}.json'};
let langs = ['en', 'es'];
let localLangs = {
'en_US': 'en',
'en_UK': 'en',
'es_ES': 'es',
'es_AR': 'es'
};
$translateProvider
.useSanitizeValueStrategy('escape')
.useLoader('$translatePartialLoader', conf)
.registerAvailableLanguageKeys(langs, localLangs)
.determinePreferredLanguage();
}
module.config(config);

View File

@ -0,0 +1,10 @@
// Proyect prefix name
export const PREFIX ='vn';
// CSS frameworks
export const MATERIAL_DESIGN_FRAMEWORK = 'Mdl';
export const BOOTSTRAP_FRAMEWORK = 'Bt';
// Module dependencies
export const EMPTY_DEPENDECIES = [];

5
client/core/src/copy.js Normal file
View File

@ -0,0 +1,5 @@
import {module} from './module';
export const NAME = 'copyObject';
module.value(NAME, angular.copy);

64
client/core/src/core.js Normal file
View File

@ -0,0 +1,64 @@
import './mdl-override.css';
export * from './module';
export * from './util';
import './config';
import './moduleLoader';
export {default as splitingRegister} from './splitingRegister';
export {NAME as RESOLVEDEFAULTCOMPONENT, ResolveDefaultComponent} from './resolveDefaultComponents';
export {NAME as INTERPOLATE, Interpolate} from './interpolate';
export {NAME as ROUTES_LOADER, RoutesLoader} from './routesLoader';
export {NAME as COPY_OBJECT} from './copy';
export {NAME as EQUALS_OBJECT} from './equals';
export {NAME as GET_DATA_MODIFIED, factory as Modified} from './modified';
export {directive as Focus} from './focus';
export {directive as Validation} from './validation';
export {NAME as BUTTON, directive as ButtonDirective} from './button/button';
export {NAME as BUTTON_MDL, factory as buttonMdl} from './button/button.mdl';
export {NAME as BUTTON_BT, factory as buttonBt} from './button/button.bt';
export {NAME as CHECK, directive as CheckDirective} from './check/check';
export {NAME as CHECK_MDL, factory as checknMdl} from './check/check.mdl';
export {NAME as CHECK_BT, factory as checkBt} from './check/check.bt';
export {NAME as RADIO, directive as RadioDirective} from './radio/radio';
export {NAME as RADIO_MDL, factory as radionMdl} from './radio/radio.mdl';
export {NAME as RADIO_BT, factory as radioBt} from './radio/radio.bt';
export {NAME as TEXTAREA, directive as TextareaDirective} from './textarea/textarea';
export {NAME as TEXTAREA_MDL, factory as textareaMdl} from './textarea/textarea.mdl';
export {NAME as TEXTFIELD, directive as TextfieldDirective} from './textfield/textfield';
export {NAME as TEXTFIELD_MDL, factory as textfieldMdl} from './textfield/textfield.mdl';
export {NAME as TEXTFIELD_BT, factory as textfieldBt} from './textfield/textfield.bt';
export {NAME as LABEL, directive as LabelDirective} from './label/label';
export {NAME as LABEL_MDL, factory as labelMdl} from './label/label.mdl';
export {NAME as LABEL_BT, factory as labelBt} from './label/label.bt';
export {NAME as ICON_BUTTON, directive as IconButtonDirective} from './icon-button/icon-button';
export {NAME as ICON_BUTTON_MDL, factory as iconButtonMdl} from './icon-button/icon-button.mdl';
export {NAME as PASSWORD, directive as PasswordDirective} from './password/password';
export {NAME as PASSWORD_MDL, factory as passwordMdl} from './password/password.mdl';
export {NAME as SUBMIT, directive as SubmitDirective} from './submit/submit';
export {NAME as SUBMIT_MDL, factory as submitMdl} from './submit/submit.mdl';
export {NAME as SNACKBAR, directive as SnackbarDirective} from './snackbar/snackbar';
export {NAME as SNACKBAR_MDL, factory as snackbarMdl} from './snackbar/snackbar.mdl';
export {NAME as SPINNER, directive as SpinnerDirective} from './spinner/spinner';
export {NAME as SPINNER_MDL, factory as spinnerMdl} from './spinner/spinner.mdl';
export {NAME as COMBO, directive as ComboDirective} from './combo/combo';
export {NAME as COMBO_MDL, factory as comboMdl} from './combo/combo.mdl';
export {NAME as DATE_PICKER, directive as DatePickerDirective} from './date-picker/date-picker';
export {NAME as DATE_PICKER_MDL, factory as datePickerMdl} from './date-picker/date-picker.mdl';
export {NAME as CARD, directive as CardDirective} from './card/card';
export {NAME as CARD_MDL, factory as cardMdl} from './card/card.mdl';
export {NAME as SWITCH, directive as SwitchDirective} from './switch/switch';
export {NAME as SWITCH_MDL, factory as switchdMdl} from './switch/switch.mdl';
export {NAME as FLOATBUTTON, directive as FloatButtonDirective} from './floatbutton/floatbutton';
export {NAME as FLOATBUTTON_MDL, factory as floatButtondMdl} from './floatbutton/floatbutton.mdl';
import './icon/index';
import './autocomplete/index';
import './popover/index';
import './dialog/index';
import './title/index';
import './subtitle/index';

View File

@ -0,0 +1,27 @@
import {module as _module} from '../module';
import * as resolveFactory from '../resolveDefaultComponents';
import * as normalizerFactory from '../inputAttrsNormalizer';
import * as util from '../util';
const _NAME = 'datePicker';
export const NAME = util.getName(_NAME);
directive.$inject = [resolveFactory.NAME, normalizerFactory.NAME];
export function directive(resolve, normalizer) {
return {
restrict: 'E',
template: function(_, attrs) {
normalizer.normalize(attrs);
return resolve.getTemplate(_NAME, attrs);
},
link: function(scope, element, attrs) {
scope.$watch(attrs.model, () => {
let mdlField = element[0].firstChild.MaterialTextfield;
if (mdlField)
mdlField.updateClasses_();
});
componentHandler.upgradeElement(element[0].firstChild);
}
};
}
_module.directive(NAME, directive);

View File

@ -0,0 +1,4 @@
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
<input class="mdl-textfield__input *[className]*" type="text" name="*[name]*" ng-model="*[model]*" rule="*[rule]*" *[enabled]*/>
<label class="mdl-textfield__label" translate>*[label]*</label>
</div>

View File

@ -0,0 +1,14 @@
import {module} from '../module';
import template from './date-picker.mdl.html';
export const NAME = 'vnDatePickerMdlFactory';
export function factory() {
return {
template: template,
default: {
label: 'Label',
enabled: 'enabled'
}
}
}
module.factory(NAME, factory);

View File

@ -0,0 +1,75 @@
import {module} from '../module';
require('./style.css');
directive.$inject = ['vnDialog'];
export function directive(dialog) {
return {
restrict: 'A',
link: function($scope, $element, $attrs, $ctrl) {
$element.on('click', function(event) {
dialog.showComponent($attrs.vnDialog, $scope);
event.preventDefault();
});
}
}
}
module.directive('vnDialog', directive);
factory.$inject = ['$document', '$compile'];
export function factory($document, $compile) {
return {
show: function(childElement) {
let background = $document[0].createElement('div');
background.className = 'vn-background';
background.addEventListener('mousedown',
this.onBackgroundMouseDown.bind(this));
this.background = background;
let dialog = $document[0].createElement('div');
dialog.className = 'vn-dialog';
dialog.addEventListener('mousedown',
this.onDialogMouseDown.bind(this));
dialog.appendChild (childElement);
background.appendChild (dialog);
this.dialog = dialog;
let style = this.dialog.style;
let screenMargin = 20;
let width = dialog.offsetWidth;
let height = dialog.offsetHeight;
let innerWidth = window.innerWidth;
let innerHeight = window.innerHeight;
if(width + screenMargin > innerWidth) {
width = innerWidth - dblMargin;
style.width = width +'px';
}
if(height + screenMargin > innerHeight) {
height = innerHeight - dblMargin;
style.height = height +'px';
}
$document[0].body.appendChild (background);
},
showComponent: function(childComponent, $scope) {
let childElement = $document[0].createElement(childComponent);
$compile(childElement)($scope);
this.show(childElement);
},
hide: function() {
$document[0].body.removeChild (this.background);
this.background = null;
this.dialog = null;
this.lastEvent = null;
},
onDialogMouseDown: function(event) {
this.lastEvent = event;
},
onBackgroundMouseDown: function(event) {
if (event != this.lastEvent)
this.hide();
}
};
}
module.factory('vnDialog', factory);

View File

@ -0,0 +1,22 @@
.vn-dialog {
position: relative;
box-shadow: 0 0 .4em rgba(1,1,1,.4);
background-color: white;
border-radius: .2em;
overflow: auto;
top: 50%;
left: 50%;
width: 400px;
margin-top: -150px;
margin-left: -200px;
}
.vn-background {
z-index: 100;
position: fixed;
left: 0;
top: 0;
height: 100%;
width: 100%;
background-color: rgba(1,1,1,.4);
}

View File

@ -0,0 +1,5 @@
import {module} from './module';
export const NAME = 'equalsObject';
module.value(NAME, angular.equals);

View File

@ -0,0 +1,19 @@
import {module as _module} from '../module';
import * as resolveFactory from '../resolveDefaultComponents';
import * as util from '../util';
const _NAME = 'floatButton';
export const NAME = util.getName(_NAME);
directive.$inject = [resolveFactory.NAME];
export function directive(resolve) {
return {
restrict: 'E',
template: function(_, attr) {
return resolve.getTemplate(_NAME, attr);
}
};
}
_module.directive(NAME, directive);

View File

@ -0,0 +1,3 @@
<button class="*[className]*">
<vn-icon icon="*[icon]*"></vn-icon>
</button>

View File

@ -0,0 +1,20 @@
import {module as _module} from '../module';
import * as util from '../util';
import * as constant from '../constants';
import template from './floatbutton.mdl.html';
const _NAME = 'floatButton';
const DEFAULT_CLASS = 'mdl-button mdl-js-button mdl-button--fab mdl-js-ripple-effect mdl-button--colored';
export const NAME = util.getFactoryName(_NAME + constant.MATERIAL_DESIGN_FRAMEWORK);
export function factory() {
return {
template: template,
default: {
className: DEFAULT_CLASS
}
};
}
_module.factory(NAME, factory);

13
client/core/src/focus.js Normal file
View File

@ -0,0 +1,13 @@
import {module} from './module';
export function directive() {
return {
restrict: 'A',
link: function($scope, $element, $attrs) {
var input = $element[0];
input.focus();
input.select();
}
};
}
module.directive('vnFocus', directive);

View File

@ -0,0 +1,17 @@
import {module as _module} from '../module';
import * as resolveFactory from '../resolveDefaultComponents';
import * as util from '../util';
const _NAME = 'iconButton';
export const NAME = util.getName(_NAME);
directive.$inject = [resolveFactory.NAME];
export function directive(resolve) {
return {
restrict: 'E',
template: function(_, attr) {
return resolve.getTemplate(_NAME, attr);
}
};
}
_module.directive(NAME, directive);

View File

@ -0,0 +1,3 @@
<button class="mdl-button mdl-js-button mdl-button--raised mdl-button--colored *[className]*" *[enabled]*>
<vn-icon icon="*[icon]*"></vn-icon>*[label]*
</button>

View File

@ -0,0 +1,15 @@
import {module} from '../module';
import template from './icon-button.mdl.html';
export const NAME = 'vnIconButtonMdlFactory';
export function factory() {
return {
template: template,
default: {
enabled: 'enabled',
icon: '',
label: ''
}
};
}
module.factory(NAME, factory);

View File

@ -0,0 +1,19 @@
import {module} from '../module';
export {factory as mdlFactory} from './index.mdl';
import * as resolveFactory from '../resolveDefaultComponents';
require('./style.css');
const _NAME = 'icon';
export const NAME = 'vnIcon';
export function directive(resolver) {
return {
restrict: 'E',
template: function(_, attrs) {
return resolver.getTemplate(_NAME, attrs);
}
}
}
directive.$inject = [resolveFactory.NAME];
module.directive(NAME, directive);

View File

@ -0,0 +1 @@
<i display-block class="material-icons">*[icon]*</i>

View File

@ -0,0 +1,12 @@
import {module} from '../module';
import template from './index.mdl.html';
export const NAME = 'vnIconMdlFactory';
export function factory() {
return {
template: template,
default: {}
}
}
module.factory(NAME, factory);

View File

@ -0,0 +1,7 @@
vn-icon {
display: inline;
font-size: 18pt;
}
vn-icon > i {
font-size: inherit !important;
}

Some files were not shown because too many files have changed in this diff Show More