Remove angular dependencies

This commit is contained in:
Nicolas Le Goff
2013-06-07 18:36:58 +02:00
parent 1a776a9335
commit d17d14bf46
15 changed files with 22 additions and 693 deletions

View File

@@ -96,8 +96,6 @@ $finder
->name('.svn')
->name('.git')
->name('flash')
->name('angular-mocks')
->name('angular-scenario')
->name('qunit')
->name('features')
->name('chai')

View File

@@ -5,10 +5,6 @@
"bootstrap": "~2.2.2",
"jquery": "~1.8.3",
"font-awesome": "~3.0.2",
"angular": "~1.0.5",
"angular-mocks": "~1.0.5",
"angular-scenario": "~1.0.5",
"angular-ui": "~0.4.0",
"underscore": "~1.4.4",
"modernizr": "~2.6.2",
"normalize-css" : "~2.1.0",

View File

@@ -21,9 +21,7 @@ $groups = array(
'//assets/angular/angular.js',
'//assets/angular-ui/build/angular-ui.js',
'//assets/bootstrap-switch/static/js/bootstrapSwitch.js',
'//assets/underscore/underscore.js',
'//skins/login/js/main.js',
'//skins/login/js/app.js',
'//assets/underscore/underscore.js'
),
'client' => array(
'//include/jslibs/swfobject/swfobject.js'

View File

@@ -13,7 +13,7 @@
{% block form_widget_simple %}
{% spaceless %}
{% set type = type|default('text') %}
<input type="{{ type }}" {{ block('widget_attributes') }} {% if value is not empty %}value="{{ value }}" {% endif %} ng-model="{{ full_name|camelize }}" ng-init="{{ full_name|camelize }}='{{ value }}'"/>
<input type="{{ type }}" {{ block('widget_attributes') }} {% if value is not empty %}value="{{ value }}" {% endif %}/>
{% endspaceless %}
{% endblock form_widget_simple %}

View File

@@ -1,23 +1,14 @@
{% macro fieldInput(field, form_name, icon_name, custom_attributes, validation_messages) %}
{% set input_name = field.vars.name %}
{% set validation_messages = {
"required_message" : "This field is required" |trans,
"is_valid_message" : "This field is not valid"|trans,
"validate_message" : "This field is not valid"|trans
}|merge(validation_messages|default({}))
%}
{% set attributes = custom_attributes|default({})|merge({
'class': app['browser'].getBrowser() == constant('Browser::BROWSER_IE') and app['browser'].getVersion() <= 8 ? '' : 'input-block-level',
'ng-model' : input_name|camelize,
'force-model-update' : ''
})
%}
{{ form_label(field) }}
<table class="input-table" ng-class="getInputClass('{{ input_name }}')">
<table class="input-table">
<tr>
<td class="icon">
<i class="{{ icon_name|default('icon-angle-right') }} icon-white"></i>
@@ -27,23 +18,7 @@
</td>
</tr>
</table>
{% if field.vars.required %}
<div ng-show="!{{ form_name }}.{{ input_name }}.errors.filled">
{{ _self.fieldError(validation_messages.required_message) }}
</div>
{% endif %}
<div ng-show="{{ form_name }}.{{ input_name }}.errors.filled && !{{ form_name }}.{{ input_name }}.errors.valid">
{{ _self.fieldError(validation_messages.is_valid_message) }}
</div>
{% if attributes['ui-validate'] is defined %}
<div ng-show="{{ form_name }}.{{ input_name }}.$error.validator">
{{ _self.fieldError(validation_messages.validate_message) }}
</div>
{% endif %}
<div class="error-view"></div>
{{ form_errors(field) }}
{% endmacro %}

View File

@@ -1,9 +1,3 @@
{#
variable "feed" to get public feeds
variable "recaptcha_display" should be setted Tell whether the recaptch should be displayed
variable "guest_allowed" phrasea::guest_allowed($app)
#}
{% extends "login/layout/sidebar-layout.html.twig" %}
{% import "common/macros.html.twig" as macro %}
@@ -22,6 +16,11 @@
{% endfor %}
{% endblock %}
{% block header_javascript %}
{{ parent() }}
{% include "login/common/templates.html.twig" %}
{% endblock header_javascript %}
{% block sidebar %}
<div class="well-large sidebar-block">
<div class="row-fluid">
@@ -48,13 +47,10 @@
{% endif %}
<form
ng-controller="LoginFormCtrl"
novalidate
name="loginForm"
ng-submit="submit();"
method="POST"
action="{{ path("login_authenticate") }}"
check-form-submission
novalidate
name="loginForm"
method="POST"
action="{{ path("login_authenticate") }}"
>
<div class="row-fluid">
<div class="span12">
@@ -122,14 +118,4 @@
{% block left_content %}
{{ parent() }}
{% set display_layout = app['phraseanet.registry'].get('GV_home_publi') %}
{% if display_layout == 'DISPLAYx1' %}
{% include 'login/include/x1-content.html.twig' %}
{% elseif display_layout == "COOLIRIS" %}
{% include 'login/include/cooliris-content.html.twig' %}
{% elseif display_layout == "SCROLL" %}
{% include 'login/include/scroll-content.html.twig' %}
{% endif %}
{% endblock %}

View File

@@ -1,11 +1,10 @@
{# variable "login" a login object for all template as i is inherited #}
<!DOCTYPE html>
<!--[if lt IE 7]> <html class="no-js lt-ie9 lt-ie8 lt-ie7" xmlns:phraseanet="http://phraseanet.com"> <![endif]-->
<!--[if IE 7]> <html class="no-js lt-ie9 lt-ie8" xmlns:phraseanet="http://phraseanet.com"> <![endif]-->
<!--[if IE 8]> <html class="no-js lt-ie9" xmlns:phraseanet="http://phraseanet.com"> <![endif]-->
<!--[if lt IE 7]> <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
<!--[if IE 7]> <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
<!--[if IE 8]> <html class="no-js lt-ie9"> <![endif]-->
<!--[if gt IE 8]>
<!-->
<html class="no-js" xmlns:phraseanet="http://phraseanet.com">
<html class="no-js">
<!--<![endif]-->
<head>
{% block header %}
@@ -34,23 +33,7 @@
{% endblock header_stylesheet %}
{% block header_javascript %}
<!--[if lte IE 8]>
<script src="/assets/json3/lib/json3.min.js"></script>
<script>
// The ieshiv takes care of our ui.directives, bootstrap module directives and
// AngularJS's ng-view, ng-include, ng-pluralize and ng-switch directives.
// However, IF you have custom directives (yours or someone else's) then
// enumerate the list of tags in window.myCustomTags
window.myCustomTags = ['phraseanetAlert']; // optional
</script>
<script src="/assets/angular-ui/build/angular-ui-ieshiv.min.js"></script>
<![endif]-->
<script type="text/javascript" src="{{ path('minifier', { 'f' : 'skins/build/bootstrap/js/bootstrap.js' }) }}"></script>
<script type="text/javascript" src="{{ path('minifier', { 'g' : 'authentication' }) }}"></script>
<script type="text/javascript" src="{{ path('minifier', {'g' : 'authentication'}) }}"></script>
{% endblock header_javascript %}
{% endblock header %}
</head>
@@ -107,5 +90,9 @@
{% endblock footer_scaffholding %}
</div><!--/.fluid-container-->
{% include 'common/analytics.html.twig' %}
{% block scripts %}
<script type="text/javascript" src="/include/minify/?f=/assets/requirejs/require.js,/scripts/apps/login/home/main.js"></script>
{% endblock %}
</body>
</html>

View File

@@ -1,16 +0,0 @@
basePath = '../../../../';
files = [
JASMINE,
JASMINE_ADAPTER,
'www/assets/angular/angular.js',
'www/assets/angular-ui/build/angular-ui.js',
'www/assets/underscore/underscore.js',
'www/assets/angular-mocks/angular-mocks.js',
'www/skins/login/js/app.js',
'tests/js/login/tests/unit/*.js'
];
autoWatch = true;
browsers = ['PhantomJS'];

View File

@@ -1,312 +0,0 @@
'use strict';
describe('LoginFormController', function(){
var scope;
beforeEach(inject(function($rootScope) {
scope = $rootScope.$new();
scope.isSubmitted = false;
scope.loginForm = {
login : {
errors:{},
$valid : true,
$error : {
required : false
}
},
password : {
errors:{},
$valid : true,
$error : {
required : false
}
}
};
}));
it('should create model errors with 2 validation for each input', inject(function($controller) {
$controller(LoginFormCtrl, {
$scope: scope
});
scope.$digest();
expect(Object.keys(scope.loginForm.login.errors).length).toEqual(2);
expect(Object.keys(scope.loginForm.password.errors).length).toEqual(2);
}));
it('should return input-table-error class when input is not valid', inject(function($controller) {
scope.loginForm.login.errors.valid = false;
scope.loginForm.password.errors.valid = true;
$controller(LoginFormCtrl, {
$scope: scope
});
expect(scope.getInputClass('password')).toBe('');
expect(scope.getInputClass('login')).toEqual('input-table-error');
}));
it('The valid login input validation should be equal to input form validation if form is submited and not valid', inject(function($controller) {
scope.loginForm.$valid = false;
$controller(LoginFormCtrl, {
$scope: scope
});
scope.$digest();
expect(scope.loginForm.login.errors.valid).toBe(scope.loginForm.login.$valid);
}));
it('The filled password and login input validation should be true if input is not required and form is submited and not valid', inject(function($controller) {
scope.loginForm.$valid = false;
$controller(LoginFormCtrl, {
$scope: scope
});
scope.$digest();
expect(scope.loginForm.login.errors.filled).not.toBe(scope.loginForm.login.$error.required);
expect(scope.loginForm.password.errors.filled).not.toBe(scope.loginForm.password.$error.required);
}));
it('Should reset input validation errors when form is submited and valid', inject(function($controller) {
$controller(LoginFormCtrl, {
$scope: scope
});
scope.$digest();
var startLoginState = _.clone(scope.loginForm.login.errors);
var startPasswordState = _.clone(scope.loginForm.password.errors);
scope.loginForm.$valid = true;
scope.loginForm.login.errors.valid = false;
scope.loginForm.password.errors.valid = false;
scope.submit();
expect(scope.loginForm.login.errors).toEqual(startLoginState);
expect(scope.loginForm.password.errors).toEqual(startPasswordState);
}));
it('should not submit form if it is not valid', inject(function($controller) {
scope.loginForm.$valid = false;
$controller(LoginFormCtrl, {
$scope: scope
});
scope.$digest();
expect(scope.submit()).toBe(false);
}));
});
describe('passwordChangeFormController', function(){
var scope;
beforeEach(inject(function($rootScope) {
scope = $rootScope.$new();
scope.isSubmitted = false;
scope.passwordChangeForm = {
passwordConfirm : {
errors:{},
$valid : true,
$error : {
required : false
}
},
password : {
errors:{},
$valid : true,
$error : {
required : false
}
},
oldPassword : {
errors:{},
$valid : true,
$error : {
required : false
}
}
};
}));
it('should create model errors with 2 validation for each input', inject(function($controller) {
$controller(passwordChangeFormCtrl, {
$scope: scope
});
scope.$digest();
expect(Object.keys(scope.passwordChangeForm.passwordConfirm.errors).length).toEqual(2);
expect(Object.keys(scope.passwordChangeForm.password.errors).length).toEqual(2);
}));
it('should return input-table-error class when input is not valid', inject(function($controller) {
scope.passwordChangeForm.passwordConfirm.errors.valid = false;
scope.passwordChangeForm.password.errors.valid = true;
$controller(passwordChangeFormCtrl, {
$scope: scope
});
expect(scope.getInputClass('password')).toBe('');
expect(scope.getInputClass('passwordConfirm')).toEqual('input-table-error');
}));
it('The valid passwordConfirm input validation should be equal to input form validation if form is submited and not valid', inject(function($controller) {
scope.passwordChangeForm.$valid = false;
$controller(passwordChangeFormCtrl, {
$scope: scope
});
scope.$digest();
expect(scope.passwordChangeForm.passwordConfirm.errors.valid).toBe(scope.passwordChangeForm.passwordConfirm.$valid);
}));
it('The filled password and passwordConfirm input validation should be true if input is not required and form is submited and not valid', inject(function($controller) {
scope.passwordChangeForm.$valid = false;
$controller(passwordChangeFormCtrl, {
$scope: scope
});
scope.$digest();
expect(scope.passwordChangeForm.passwordConfirm.errors.filled).not.toBe(scope.passwordChangeForm.passwordConfirm.$error.required);
expect(scope.passwordChangeForm.password.errors.filled).not.toBe(scope.passwordChangeForm.password.$error.required);
}));
it('Should reset input validation errors when form is submited and valid', inject(function($controller) {
$controller(passwordChangeFormCtrl, {
$scope: scope
});
scope.$digest();
var startPasswordCondfirmState = _.clone(scope.passwordChangeForm.passwordConfirm.errors);
var startPasswordState = _.clone(scope.passwordChangeForm.password.errors);
scope.passwordChangeForm.$valid = true;
scope.passwordChangeForm.passwordConfirm.errors.valid = false;
scope.passwordChangeForm.password.errors.valid = false;
scope.submit();
expect(scope.passwordChangeForm.passwordConfirm.errors).toEqual(startPasswordCondfirmState);
expect(scope.passwordChangeForm.password.errors).toEqual(startPasswordState);
}));
it('should not submit form if it is not valid', inject(function($controller) {
scope.passwordChangeForm.$valid = false;
$controller(passwordChangeFormCtrl, {
$scope: scope
});
scope.$digest();
expect(scope.submit()).toBe(false);
}));
});
describe('forgottenPasswordFormCtrl', function(){
var scope;
beforeEach(inject(function($rootScope) {
scope = $rootScope.$new();
scope.isSubmitted = false;
scope.forgottenPasswordForm = {
email : {
errors:{},
$valid : true,
$error : {
required : false
}
}
};
}));
it('should create model errors with 2 validation for email input', inject(function($controller) {
$controller(forgottenPasswordFormCtrl, {
$scope: scope
});
scope.$digest();
expect(Object.keys(scope.forgottenPasswordForm.email.errors).length).toEqual(2);
}));
it('should return input-table-error class when input is not valid', inject(function($controller) {
scope.forgottenPasswordForm.email.errors.valid = true;
$controller(forgottenPasswordFormCtrl, {
$scope: scope
});
expect(scope.getInputClass('email')).toBe('');
}));
it('The valid email input validation should be equal to input form validation if form is submited and not valid', inject(function($controller) {
scope.forgottenPasswordForm.$valid = false;
$controller(forgottenPasswordFormCtrl, {
$scope: scope
});
scope.$digest();
expect(scope.forgottenPasswordForm.email.errors.valid).toBe(scope.forgottenPasswordForm.email.$valid);
}));
it('The filled email input validation should be true if input is not required and form is submited and not valid', inject(function($controller) {
scope.forgottenPasswordForm.$valid = false;
$controller(forgottenPasswordFormCtrl, {
$scope: scope
});
scope.$digest();
expect(scope.forgottenPasswordForm.email.errors.filled).not.toBe(scope.forgottenPasswordForm.email.$error.required);
}));
it('Should reset input validation errors when form is submited and valid', inject(function($controller) {
$controller(forgottenPasswordFormCtrl, {
$scope: scope
});
scope.$digest();
var startEmailState = _.clone(scope.forgottenPasswordForm.email.errors);
scope.forgottenPasswordForm.$valid = true;
scope.forgottenPasswordForm.email.errors.valid = false;
scope.submit();
expect(scope.forgottenPasswordForm.email.errors).toEqual(startEmailState);
}));
it('should not submit form if it is not valid', inject(function($controller) {
scope.forgottenPasswordForm.$valid = false;
$controller(forgottenPasswordFormCtrl, {
$scope: scope
});
scope.$digest();
expect(scope.submit()).toBe(false);
}));
});

View File

@@ -10,6 +10,4 @@ phantomjs "$ROOTDIR/www/assets/qunit/addons/phantomjs/runner.js" "$ROOTDIR/www/i
# run backbone tests
mocha-phantomjs "$ROOTDIR/www/scripts/tests/index.html"
# run angular tests
sh "$BASEDIR/scripts/run.sh"

View File

@@ -1,11 +0,0 @@
@echo off
REM Windows script for running unit tests
REM You have to run server and capture some browser first
REM
REM Requirements:
REM - NodeJS (http://nodejs.org/)
REM - Testacular (npm install -g testacular)
set BASE_DIR=%~dp0
karma start "%BASE_DIR%\..\login\config\testacular.conf.js" %*

View File

@@ -1,9 +0,0 @@
#!/bin/bash
BASE_DIR=`dirname $0`
echo ""
echo "Starting Testacular Server (http://vojtajina.github.com/testacular)"
echo "-------------------------------------------------------------------"
karma start $BASE_DIR/../login/config/testacular.conf.js --single-run $*

View File

@@ -1,19 +0,0 @@
#!/usr/bin/env watchr
# config file for watchr http://github.com/mynyml/watchr
# install: gem install watchr
# run: watch watchr.rb
# note: make sure that you have jstd server running (server.sh) and a browser captured
log_file = File.expand_path(File.dirname(__FILE__) + '/../logs/jstd.log')
`cd ..`
`touch #{log_file}`
puts "String watchr... log file: #{log_file}"
watch( '(app/js|test/unit)' ) do
`echo "\n\ntest run started @ \`date\`" > #{log_file}`
`scripts/test.sh &> #{log_file}`
end

View File

@@ -1,234 +0,0 @@
// controllers
function LoginFormCtrl($scope) {
$scope.isSubmitted = false;
$scope.$watch('loginForm', function() {
$scope.loginForm.login.errors = {'filled' : true, 'valid' : true};
$scope.loginForm.password.errors = {'filled' : true, 'valid' : true};
});
$scope.submit = function() {
$scope.$broadcast('event:force-model-update');
if (true === $scope.loginForm.$valid) {
$scope.isSubmitted = true;
$scope.loginForm.login.errors = {'filled' : true, 'valid' : true};
$scope.loginForm.password.errors = {'filled' : true,'valid' : true};
return true;
}
$scope.loginForm.login.errors.filled = !$scope.loginForm.login.$error.required;
$scope.loginForm.password.errors.filled = !$scope.loginForm.password.$error.required;
return false;
};
$scope.getInputClass = function(name) {
return _.every($scope.loginForm[name].errors, function(value) {
return value === true;
}) ? '' : 'input-table-error';
};
}
function forgottenPasswordFormCtrl($scope) {
$scope.isSubmitted = false;
$scope.$watch('forgottenPasswordForm', function() {
$scope.forgottenPasswordForm.email.errors = {'filled' : true, 'valid' : true};
});
$scope.submit = function() {
$scope.$broadcast('event:force-model-update');
if (true === $scope.forgottenPasswordForm.$valid) {
$scope.forgottenPasswordForm.email.errors = {'filled' : true, 'valid' : true};
$scope.isSubmitted = true;
return true;
}
$scope.forgottenPasswordForm.email.errors.valid = $scope.forgottenPasswordForm.email.$valid;
$scope.forgottenPasswordForm.email.errors.filled = !$scope.forgottenPasswordForm.email.$error.required;
return false;
};
$scope.getInputClass = function(name) {
return _.every($scope.forgottenPasswordForm[name].errors, function(value) {
return value === true;
}) ? '' : 'input-table-error';
};
}
function passwordChangeFormCtrl($scope) {
$scope.isSubmitted = false;
$scope.$watch('passwordChangeForm', function() {
$scope.passwordChangeForm.oldPassword.errors = {'filled' : true, 'valid' : true};
$scope.passwordChangeForm.password.errors = {'filled' : true, 'valid' : true};
$scope.passwordChangeForm.passwordConfirm.errors = {'filled' : true, 'valid' : true};
});
$scope.submit = function() {
$scope.$broadcast('event:force-model-update');
if (true === $scope.passwordChangeForm.$valid) {
$scope.passwordChangeForm.oldPassword.errors = {'filled' : true, 'valid' : true};
$scope.passwordChangeForm.password.errors = {'filled' : true, 'valid' : true};
$scope.passwordChangeForm.passwordConfirm.errors = {'filled' : true, 'valid' : true};
$scope.isSubmitted = true;
return true;
}
$scope.passwordChangeForm.password.errors.filled = !$scope.passwordChangeForm.password.$error.required;
$scope.passwordChangeForm.passwordConfirm.errors.filled = !$scope.passwordChangeForm.passwordConfirm.$error.required;
return false;
};
$scope.getInputClass = function(name) {
return _.every($scope.passwordChangeForm[name].errors, function(value) {
return value === true;
}) ? '' : 'input-table-error';
};
}
//@todo add tests
function registerFormCtrl($scope, $http) {
$scope.isSubmitted = false;
$scope.fields = [];
$scope.$watch('registerForm', function() {
$scope.registerForm.email.errors = {'filled' : true, 'valid' : true};
$scope.registerForm.password.errors = {'filled' : true, 'valid' : true};
$scope.registerForm.passwordConfirm.errors = {'filled' : true, 'valid' : true};
$http.get('/login/registration-fields/').success(function(data, status) {
$scope.fields = data;
_.each($scope.fields, function(field){
$scope.registerForm[camelize(field.name)].errors = {'filled' : true, 'valid' : true};
});
});
});
$scope.submit = function() {
$scope.$broadcast('event:force-model-update');
if (true === $scope.registerForm.$valid) {
$scope.registerForm.email.errors = {'filled' : true, 'valid' : true};
$scope.registerForm.password.errors = {'filled' : true, 'valid' : true};
$scope.registerForm.passwordConfirm.errors = {'filled' : true, 'valid' : true};
_.each($scope.fields, function(field){
$scope.registerForm[camelize(field.name)].errors = {'filled' : true, 'valid' : true};
});
$scope.isSubmitted = true;
return true;
}
$scope.registerForm.password.errors.filled = !$scope.registerForm.password.$error.required;
$scope.registerForm.passwordConfirm.errors.filled = !$scope.registerForm.passwordConfirm.$error.required;
_.each($scope.fields, function(field){
if (field.required) {
$scope.registerForm[camelize(field.name)].errors.filled = !$scope.registerForm[camelize(field.name)].$error.required;
}
});
return false;
};
$scope.getInputClass = function(name) {
return _.every($scope.registerForm[name].errors, function(value) {
return value === true;
}) ? '' : 'input-table-error';
};
}
function camelize(name) {
return name.replace(/\-(\w)/g, function(all, letter, offset){
return (offset === 0 && letter === 'w') ? 'w' : letter.toUpperCase();
});
}
// bootstrap angular
angular.element(document).ready(function() {
angular.bootstrap(document, ['phraseanetAuthentication']);
});
// angular app
angular.module('phraseanetAuthentication', ['ui'])
// force model update for autofill inputs. Yuck.
.directive('forceModelUpdate', function($compile) {
return {
restrict: 'A',
require: 'ngModel',
link: function(scope, element, attrs, ctrl) {
scope.$on('event:force-model-update', function() {
ctrl.$setViewValue(element.val());
});
}
};
}).directive('checkFormSubmission', function () {
// Angular does not prevent form submission if form is not valid and if action attribute is defined.
// This directive change angular's behavior by cancelling form submission
// if form is not valid even if action attribute is defined
return {
link: function (scope, element, attrs, controller) {
scope.$watch('isSubmitted', function(value) {
if(false === value && !!element.attr('action')) {
element.bind('submit', function(event) {
event.preventDefault();
return false;
});
} else {
element.unbind('submit').trigger('submit');
}
});
}
};
}).directive('phraseanetFlash', function () {
return {
restrict:'EA',
template: [
'<div class="alert" ng-class=\'type && "alert-" + type || "warning"\'>',
'<table><tr>',
'<td class="alert-block-logo"><i class="icon-2x icon-white" ng-class=\'icon || "icon-exclamation-sign"\'></i></td>',
'<td class="alert-block-content" ng-transclude></td>',
'<td class="alert-block-close"><a href="#"><b>&times;</b></a></td>',
'</tr></table>',
'</div>'
].join(''),
transclude:true,
replace:true,
scope:{
type: '@'
},
compile: function (element, attrs, transclude) {
return function (scope, element, attr) {
if (true === 'type' in attrs) {
switch (attrs.type) {
case 'error' :
scope.icon = 'icon-warning-sign';
break;
case 'success' :
scope.icon = 'icon-ok-sign';
break;
case 'info' :
scope.icon = 'icon-info-sign';
break;
}
}
};
}
};
});

View File

@@ -1,8 +0,0 @@
// dom ready
$(document).ready(function() {
$(document).on("click", ".alert .alert-block-close a", function(e){
e.preventDefault();
$(this).closest('.alert').alert('close');
return false;
});
});