Merge pull request #227 from whiteout-io/dev/cleanup

Move directives to seperate files, cleanup app.js
This commit is contained in:
Felix Hammerl 2014-12-11 10:05:02 +01:00
commit 738d2671f7
16 changed files with 409 additions and 436 deletions

View File

@ -31,7 +31,7 @@
<script src="js/app.min.js"></script>
</head>
<body key-shortcuts>
<body wo-key-shortcuts>
<!-- inline icons have to come first, hide immediately with inline styles -->
<div style="width: 0; height: 0; visibility: hidden;">

View File

@ -14,32 +14,11 @@ if (typeof window.applicationCache !== 'undefined') {
};
}
var axe = require('axe-logger'),
AddAccountCtrl = require('./controller/login/add-account'),
CreateAccountCtrl = require('./controller/login/create-account'),
ValidatePhoneCtrl = require('./controller/login/validate-phone'),
LoginCtrl = require('./controller/login/login'),
LoginInitialCtrl = require('./controller/login/login-initial'),
LoginNewDeviceCtrl = require('./controller/login/login-new-device'),
LoginExistingCtrl = require('./controller/login/login-existing'),
LoginPrivateKeyDownloadCtrl = require('./controller/login/login-privatekey-download'),
LoginSetCredentialsCtrl = require('./controller/login/login-set-credentials'),
DialogCtrl = require('./controller/app/dialog'),
AccountCtrl = require('./controller/app/account'),
SetPassphraseCtrl = require('./controller/app/set-passphrase'),
PrivateKeyUploadCtrl = require('./controller/app/privatekey-upload'),
ContactsCtrl = require('./controller/app/contacts'),
AboutCtrl = require('./controller/app/about'),
MailListCtrl = require('./controller/app/mail-list'),
ReadCtrl = require('./controller/app/read'),
WriteCtrl = require('./controller/app/write'),
NavigationCtrl = require('./controller/app/navigation'),
ActionBarCtrl = require('./controller/app/action-bar'),
StatusDisplayCtrl = require('./controller/app/status-display');
var axe = require('axe-logger');
// include angular modules
require('./app-config');
require('./directive/common');
require('./directive');
require('./util');
require('./crypto');
require('./service');
@ -56,12 +35,6 @@ var app = angular.module('mail', [
'woCrypto',
'woServices',
'woEmail',
'navigation',
'mail-list',
'write',
'read',
'contacts',
'login-new-device',
'infinite-scroll'
]);
@ -69,43 +42,43 @@ var app = angular.module('mail', [
app.config(function($routeProvider, $animateProvider) {
$routeProvider.when('/login', {
templateUrl: 'tpl/login.html',
controller: LoginCtrl
controller: require('./controller/login/login')
});
$routeProvider.when('/add-account', {
templateUrl: 'tpl/add-account.html',
controller: AddAccountCtrl
controller: require('./controller/login/add-account')
});
$routeProvider.when('/create-account', {
templateUrl: 'tpl/create-account.html',
controller: CreateAccountCtrl
controller: require('./controller/login/create-account')
});
$routeProvider.when('/validate-phone', {
templateUrl: 'tpl/validate-phone.html',
controller: ValidatePhoneCtrl
controller: require('./controller/login/validate-phone')
});
$routeProvider.when('/login-set-credentials', {
templateUrl: 'tpl/login-set-credentials.html',
controller: LoginSetCredentialsCtrl
controller: require('./controller/login/login-set-credentials')
});
$routeProvider.when('/login-existing', {
templateUrl: 'tpl/login-existing.html',
controller: LoginExistingCtrl
controller: require('./controller/login/login-existing')
});
$routeProvider.when('/login-initial', {
templateUrl: 'tpl/login-initial.html',
controller: LoginInitialCtrl
controller: require('./controller/login/login-initial')
});
$routeProvider.when('/login-new-device', {
templateUrl: 'tpl/login-new-device.html',
controller: LoginNewDeviceCtrl
controller: require('./controller/login/login-new-device')
});
$routeProvider.when('/login-privatekey-download', {
templateUrl: 'tpl/login-privatekey-download.html',
controller: LoginPrivateKeyDownloadCtrl
controller: require('./controller/login/login-privatekey-download')
});
$routeProvider.when('/account', {
templateUrl: 'tpl/desktop.html',
controller: NavigationCtrl,
controller: require('./controller/app/navigation'),
reloadOnSearch: false // don't reload controllers in main app when query params change
});
$routeProvider.otherwise({
@ -124,17 +97,17 @@ app.run(function($rootScope) {
});
// inject controllers from ng-included view templates
app.controller('ReadCtrl', ReadCtrl);
app.controller('WriteCtrl', WriteCtrl);
app.controller('MailListCtrl', MailListCtrl);
app.controller('AccountCtrl', AccountCtrl);
app.controller('SetPassphraseCtrl', SetPassphraseCtrl);
app.controller('PrivateKeyUploadCtrl', PrivateKeyUploadCtrl);
app.controller('ContactsCtrl', ContactsCtrl);
app.controller('AboutCtrl', AboutCtrl);
app.controller('DialogCtrl', DialogCtrl);
app.controller('ActionBarCtrl', ActionBarCtrl);
app.controller('StatusDisplayCtrl', StatusDisplayCtrl);
app.controller('ReadCtrl', require('./controller/app/read'));
app.controller('WriteCtrl', require('./controller/app/write'));
app.controller('MailListCtrl', require('./controller/app/mail-list'));
app.controller('AccountCtrl', require('./controller/app/account'));
app.controller('SetPassphraseCtrl', require('./controller/app/set-passphrase'));
app.controller('PrivateKeyUploadCtrl', require('./controller/app/privatekey-upload'));
app.controller('ContactsCtrl', require('./controller/app/contacts'));
app.controller('AboutCtrl', require('./controller/app/about'));
app.controller('DialogCtrl', require('./controller/app/dialog'));
app.controller('ActionBarCtrl', require('./controller/app/action-bar'));
app.controller('StatusDisplayCtrl', require('./controller/app/status-display'));
//
// Manual angular bootstraping
@ -155,4 +128,4 @@ function bootstrap() {
angular.element(document).ready(function() {
angular.bootstrap(document, ['mail']);
});
}
}

View File

@ -99,28 +99,4 @@ var ContactsCtrl = function($scope, keychain, pgp, dialog) {
};
//
// Directives
//
var ngModule = angular.module('contacts', []);
ngModule.directive('keyfileInput', function() {
return function(scope, elm) {
elm.on('change', function(e) {
for (var i = 0; i < e.target.files.length; i++) {
importKey(e.target.files.item(i));
}
});
function importKey(file) {
var reader = new FileReader();
reader.onload = function(e) {
scope.importKey(e.target.result);
};
reader.readAsText(file);
}
};
});
module.exports = ContactsCtrl;

View File

@ -329,83 +329,9 @@ var MailListCtrl = function($scope, $timeout, $location, $filter, status, notifi
};
//
// Directives
// helper functions
//
var ngModule = angular.module('mail-list', []);
ngModule.directive('listScroll', function() {
return {
link: function(scope, elm, attrs) {
var model = attrs.listScroll,
listEl = elm[0],
scrollTimeout;
/*
* iterates over the mails in the mail list and loads their bodies if they are visible in the viewport
*/
scope.loadVisibleBodies = function() {
var listBorder = listEl.getBoundingClientRect(),
top = listBorder.top,
bottom = listBorder.bottom,
listItems = listEl.children[0].children,
inViewport = false,
listItem, message,
isPartiallyVisibleTop, isPartiallyVisibleBottom, isVisible,
displayMessages = scope[model];
if (!top && !bottom) {
// list not visible
return;
}
for (var i = 0, len = listItems.length; i < len; i++) {
// the n-th list item (the dom representation of an message) corresponds to
// the n-th message model in the filteredMessages array
listItem = listItems.item(i).getBoundingClientRect();
if (!displayMessages || displayMessages.length <= i) {
// stop if i get larger than the size of filtered messages
break;
}
message = displayMessages[i];
isPartiallyVisibleTop = listItem.top < top && listItem.bottom > top; // a portion of the list item is visible on the top
isPartiallyVisibleBottom = listItem.top < bottom && listItem.bottom > bottom; // a portion of the list item is visible on the bottom
isVisible = (listItem.top || listItem.bottom) && listItem.top >= top && listItem.bottom <= bottom; // the list item is visible as a whole
if (isPartiallyVisibleTop || isVisible || isPartiallyVisibleBottom) {
// we are now iterating over visible elements
inViewport = true;
// load mail body of visible
scope.getBody(message);
} else if (inViewport) {
// we are leaving the viewport, so stop iterating over the items
break;
}
}
};
// load body when scrolling
listEl.onscroll = function() {
if (scrollTimeout) {
// remove timeout so that only scroll end
clearTimeout(scrollTimeout);
}
scrollTimeout = setTimeout(function() {
scope.loadVisibleBodies();
}, 300);
};
// load the visible message bodies, when the list is re-initialized and when scrolling stopped
scope.$watchCollection(model, function() {
scope.loadVisibleBodies();
});
}
};
});
function byUidDescending(a, b) {
if (a.uid < b.uid) {
return 1;

View File

@ -169,57 +169,4 @@ var NavigationCtrl = function($scope, $location, account, email, outbox, notific
}
};
//
// Directives
//
var ngModule = angular.module('navigation', []);
ngModule.directive('keyShortcuts', function($timeout) {
return function(scope, elm) {
elm.bind('keydown', function(e) {
// global state is not yet set, ignore keybaord shortcuts
if (!scope.state) {
return;
}
var modifier = e.ctrlKey || e.metaKey;
if (modifier && e.keyCode === 78 && scope.state.lightbox !== 'write') {
// n -> new mail
e.preventDefault();
scope.state.writer.write();
scope.$apply();
} else if (modifier && e.keyCode === 70 && scope.state.lightbox !== 'write') {
// f -> find
e.preventDefault();
scope.state.mailList.searching = true;
$timeout(function() {
scope.state.mailList.searching = false;
}, 200);
scope.$apply();
} else if (modifier && e.keyCode === 82 && scope.state.lightbox !== 'write' && scope.state.mailList.selected) {
// r -> reply
e.preventDefault();
scope.state.writer.write(scope.state.mailList.selected);
scope.$apply();
} else if (e.keyCode === 27 && scope.state.lightbox !== undefined) {
// escape -> close current lightbox
e.preventDefault();
scope.state.lightbox = undefined;
scope.$apply();
} else if (e.keyCode === 27 && scope.state.nav.open) {
// escape -> close nav view
e.preventDefault();
scope.state.nav.toggle(false);
scope.$apply();
}
});
};
});
module.exports = NavigationCtrl;

View File

@ -168,140 +168,4 @@ var ReadCtrl = function($scope, $location, email, invitation, outbox, pgp, keych
};
};
//
// Directives
//
var ngModule = angular.module('read', []);
ngModule.directive('replySelection', function() {
return function(scope, elm) {
var popover, visible;
popover = angular.element(document.querySelector('.reply-selection'));
visible = false;
elm.on('touchstart click', appear);
elm.parent().parent().on('touchstart click', disappear);
popover.on('touchstart click', disappear);
function appear(e) {
e.preventDefault();
e.stopPropagation();
visible = true;
// set popover position
var top = elm[0].offsetTop;
var left = elm[0].offsetLeft;
var width = elm[0].offsetWidth;
var height = elm[0].offsetHeight;
popover[0].style.transition = 'opacity 0.1s linear';
popover[0].style.top = (top + height) + 'px';
popover[0].style.left = (left + width / 2 - popover[0].offsetWidth / 2) + 'px';
popover[0].style.opacity = '1';
}
function disappear() {
if (!visible) {
return;
}
popover[0].style.transition = 'opacity 0.25s linear, top 0.25s step-end, left 0.25s step-end';
popover[0].style.opacity = '0';
popover[0].style.top = '-9999px';
popover[0].style.left = '-9999px';
visible = false;
}
};
});
ngModule.directive('frameLoad', function($timeout, $window) {
return function(scope, elm) {
var iframe = elm[0];
scope.$watch('state.read.open', function(open) {
if (open) {
// trigger rendering of iframe
// otherwise scale to fit would not compute correct dimensions on mobile
displayText(scope.state.mailList.selected ? scope.state.mailList.selected.body : undefined);
displayHtml(scope.state.mailList.selected ? scope.state.mailList.selected.html : undefined);
}
});
$window.addEventListener('resize', scaleToFit);
iframe.onload = function() {
// set listeners
scope.$watch('state.mailList.selected.body', displayText);
scope.$watch('state.mailList.selected.html', displayHtml);
// display initial message body
scope.$apply();
};
function displayText(body) {
var mail = scope.state.mailList.selected;
if ((mail && mail.html) || (mail && mail.encrypted && !mail.decrypted)) {
return;
}
// send text body for rendering in iframe
iframe.contentWindow.postMessage({
text: body
}, '*');
$timeout(scaleToFit, 0);
}
function displayHtml(html) {
if (!html) {
return;
}
// if there are image tags in the html?
var hasImages = /<img[^>]+\bsrc=['"][^'">]+['"]/ig.test(html);
scope.showImageButton = hasImages;
iframe.contentWindow.postMessage({
html: html,
removeImages: hasImages // avoids doing unnecessary work on the html
}, '*');
// only add a scope function to reload the html if there are images
if (hasImages) {
// reload WITH images
scope.displayImages = function() {
scope.showImageButton = false;
iframe.contentWindow.postMessage({
html: html,
removeImages: false
}, '*');
};
}
$timeout(scaleToFit, 0);
}
// transform scale iframe (necessary on iOS) to fit container width
function scaleToFit() {
var parentWidth = elm.parent().width();
var w = elm.width();
var scale = '';
if (w > parentWidth) {
scale = parentWidth / w;
scale = 'scale(' + scale + ',' + scale + ')';
}
elm.css({
'-webkit-transform-origin': '0 0',
'transform-origin': '0 0',
'-webkit-transform': scale,
'transform': scale
});
}
};
});
module.exports = ReadCtrl;

View File

@ -438,61 +438,4 @@ var WriteCtrl = function($scope, $window, $filter, $q, appConfig, auth, keychain
}
};
//
// Directives
//
var ngModule = angular.module('write', []);
ngModule.directive('focusInput', function($timeout, $parse) {
return {
//scope: true, // optionally create a child scope
link: function(scope, element, attrs) {
var model = $parse(attrs.focusInput);
scope.$watch(model, function(value) {
if (value === true) {
$timeout(function() {
element.find('input').first().focus();
}, 100);
}
});
}
};
});
ngModule.directive('focusInputOnClick', function() {
return {
//scope: true, // optionally create a child scope
link: function(scope, element) {
element.on('click', function() {
element.find('input').first().focus();
});
}
};
});
ngModule.directive('attachmentInput', function() {
return function(scope, elm) {
elm.on('change', function(e) {
for (var i = 0; i < e.target.files.length; i++) {
addAttachment(e.target.files.item(i));
}
});
function addAttachment(file) {
var reader = new FileReader();
reader.onload = function(e) {
scope.attachments.push({
filename: file.name,
mimeType: file.type,
content: new Uint8Array(e.target.result)
});
scope.$digest();
};
reader.readAsArrayBuffer(file);
}
};
});
module.exports = WriteCtrl;

View File

@ -107,39 +107,4 @@ var LoginExistingCtrl = function($scope, $location, $routeParams, email, auth, p
};
};
var ngModule = angular.module('login-new-device', []);
ngModule.directive('fileReader', function() {
return function(scope, elm) {
elm.bind('change', function(e) {
var files = e.target.files,
reader = new FileReader();
if (files.length === 0) {
return;
}
reader.onload = function(e) {
var rawKeys = e.target.result,
index = rawKeys.indexOf('-----BEGIN PGP PRIVATE KEY BLOCK-----'),
keyParts;
if (index === -1) {
scope.displayError(new Error('Error parsing private PGP key block!'));
return;
}
keyParts = {
publicKeyArmored: rawKeys.substring(0, index).trim(),
privateKeyArmored: rawKeys.substring(index, rawKeys.length).trim()
};
scope.$apply(function() {
scope.key = keyParts;
});
};
reader.readAsText(files[0]);
});
};
});
module.exports = LoginExistingCtrl;

View File

@ -1,6 +1,6 @@
'use strict';
var ngModule = angular.module('woDirectives', []);
var ngModule = angular.module('woDirectives');
ngModule.directive('woTouch', function($parse) {
var className = 'wo-touch-active';
@ -330,6 +330,4 @@ ngModule.directive('woInputCode', function() {
});
}
};
});
module.exports = ngModule;
});

View File

@ -0,0 +1,21 @@
'use strict';
var ngModule = angular.module('woDirectives');
ngModule.directive('keyfileInput', function() {
return function(scope, elm) {
elm.on('change', function(e) {
for (var i = 0; i < e.target.files.length; i++) {
importKey(e.target.files.item(i));
}
});
function importKey(file) {
var reader = new FileReader();
reader.onload = function(e) {
scope.importKey(e.target.result);
};
reader.readAsText(file);
}
};
});

11
src/js/directive/index.js Normal file
View File

@ -0,0 +1,11 @@
'use strict';
angular.module('woDirectives', []);
require('./common');
require('./key-shortcuts');
require('./mail-list');
require('./write');
require('./read');
require('./contacts');
require('./login-new-device');

View File

@ -0,0 +1,51 @@
'use strict';
var ngModule = angular.module('woDirectives');
ngModule.directive('woKeyShortcuts', function($timeout) {
return function(scope, elm) {
elm.bind('keydown', function(e) {
// global state is not yet set, ignore keybaord shortcuts
if (!scope.state) {
return;
}
var modifier = e.ctrlKey || e.metaKey;
if (modifier && e.keyCode === 78 && scope.state.lightbox !== 'write') {
// n -> new mail
e.preventDefault();
scope.state.writer.write();
scope.$apply();
} else if (modifier && e.keyCode === 70 && scope.state.lightbox !== 'write') {
// f -> find
e.preventDefault();
scope.state.mailList.searching = true;
$timeout(function() {
scope.state.mailList.searching = false;
}, 200);
scope.$apply();
} else if (modifier && e.keyCode === 82 && scope.state.lightbox !== 'write' && scope.state.mailList.selected) {
// r -> reply
e.preventDefault();
scope.state.writer.write(scope.state.mailList.selected);
scope.$apply();
} else if (e.keyCode === 27 && scope.state.lightbox !== undefined) {
// escape -> close current lightbox
e.preventDefault();
scope.state.lightbox = undefined;
scope.$apply();
} else if (e.keyCode === 27 && scope.state.nav.open) {
// escape -> close nav view
e.preventDefault();
scope.state.nav.toggle(false);
scope.$apply();
}
});
};
});

View File

@ -0,0 +1,37 @@
'use strict';
var ngModule = angular.module('woDirectives');
ngModule.directive('fileReader', function() {
return function(scope, elm) {
elm.bind('change', function(e) {
var files = e.target.files,
reader = new FileReader();
if (files.length === 0) {
return;
}
reader.onload = function(e) {
var rawKeys = e.target.result,
index = rawKeys.indexOf('-----BEGIN PGP PRIVATE KEY BLOCK-----'),
keyParts;
if (index === -1) {
scope.displayError(new Error('Error parsing private PGP key block!'));
return;
}
keyParts = {
publicKeyArmored: rawKeys.substring(0, index).trim(),
privateKeyArmored: rawKeys.substring(index, rawKeys.length).trim()
};
scope.$apply(function() {
scope.key = keyParts;
});
};
reader.readAsText(files[0]);
});
};
});

View File

@ -0,0 +1,75 @@
'use strict';
var ngModule = angular.module('woDirectives');
ngModule.directive('listScroll', function() {
return {
link: function(scope, elm, attrs) {
var model = attrs.listScroll,
listEl = elm[0],
scrollTimeout;
/*
* iterates over the mails in the mail list and loads their bodies if they are visible in the viewport
*/
scope.loadVisibleBodies = function() {
var listBorder = listEl.getBoundingClientRect(),
top = listBorder.top,
bottom = listBorder.bottom,
listItems = listEl.children[0].children,
inViewport = false,
listItem, message,
isPartiallyVisibleTop, isPartiallyVisibleBottom, isVisible,
displayMessages = scope[model];
if (!top && !bottom) {
// list not visible
return;
}
for (var i = 0, len = listItems.length; i < len; i++) {
// the n-th list item (the dom representation of an message) corresponds to
// the n-th message model in the filteredMessages array
listItem = listItems.item(i).getBoundingClientRect();
if (!displayMessages || displayMessages.length <= i) {
// stop if i get larger than the size of filtered messages
break;
}
message = displayMessages[i];
isPartiallyVisibleTop = listItem.top < top && listItem.bottom > top; // a portion of the list item is visible on the top
isPartiallyVisibleBottom = listItem.top < bottom && listItem.bottom > bottom; // a portion of the list item is visible on the bottom
isVisible = (listItem.top || listItem.bottom) && listItem.top >= top && listItem.bottom <= bottom; // the list item is visible as a whole
if (isPartiallyVisibleTop || isVisible || isPartiallyVisibleBottom) {
// we are now iterating over visible elements
inViewport = true;
// load mail body of visible
scope.getBody(message);
} else if (inViewport) {
// we are leaving the viewport, so stop iterating over the items
break;
}
}
};
// load body when scrolling
listEl.onscroll = function() {
if (scrollTimeout) {
// remove timeout so that only scroll end
clearTimeout(scrollTimeout);
}
scrollTimeout = setTimeout(function() {
scope.loadVisibleBodies();
}, 300);
};
// load the visible message bodies, when the list is re-initialized and when scrolling stopped
scope.$watchCollection(model, function() {
scope.loadVisibleBodies();
});
}
};
});

133
src/js/directive/read.js Normal file
View File

@ -0,0 +1,133 @@
'use strict';
var ngModule = angular.module('woDirectives');
ngModule.directive('replySelection', function() {
return function(scope, elm) {
var popover, visible;
popover = angular.element(document.querySelector('.reply-selection'));
visible = false;
elm.on('touchstart click', appear);
elm.parent().parent().on('touchstart click', disappear);
popover.on('touchstart click', disappear);
function appear(e) {
e.preventDefault();
e.stopPropagation();
visible = true;
// set popover position
var top = elm[0].offsetTop;
var left = elm[0].offsetLeft;
var width = elm[0].offsetWidth;
var height = elm[0].offsetHeight;
popover[0].style.transition = 'opacity 0.1s linear';
popover[0].style.top = (top + height) + 'px';
popover[0].style.left = (left + width / 2 - popover[0].offsetWidth / 2) + 'px';
popover[0].style.opacity = '1';
}
function disappear() {
if (!visible) {
return;
}
popover[0].style.transition = 'opacity 0.25s linear, top 0.25s step-end, left 0.25s step-end';
popover[0].style.opacity = '0';
popover[0].style.top = '-9999px';
popover[0].style.left = '-9999px';
visible = false;
}
};
});
ngModule.directive('frameLoad', function($timeout, $window) {
return function(scope, elm) {
var iframe = elm[0];
scope.$watch('state.read.open', function(open) {
if (open) {
// trigger rendering of iframe
// otherwise scale to fit would not compute correct dimensions on mobile
displayText(scope.state.mailList.selected ? scope.state.mailList.selected.body : undefined);
displayHtml(scope.state.mailList.selected ? scope.state.mailList.selected.html : undefined);
}
});
$window.addEventListener('resize', scaleToFit);
iframe.onload = function() {
// set listeners
scope.$watch('state.mailList.selected.body', displayText);
scope.$watch('state.mailList.selected.html', displayHtml);
// display initial message body
scope.$apply();
};
function displayText(body) {
var mail = scope.state.mailList.selected;
if ((mail && mail.html) || (mail && mail.encrypted && !mail.decrypted)) {
return;
}
// send text body for rendering in iframe
iframe.contentWindow.postMessage({
text: body
}, '*');
$timeout(scaleToFit, 0);
}
function displayHtml(html) {
if (!html) {
return;
}
// if there are image tags in the html?
var hasImages = /<img[^>]+\bsrc=['"][^'">]+['"]/ig.test(html);
scope.showImageButton = hasImages;
iframe.contentWindow.postMessage({
html: html,
removeImages: hasImages // avoids doing unnecessary work on the html
}, '*');
// only add a scope function to reload the html if there are images
if (hasImages) {
// reload WITH images
scope.displayImages = function() {
scope.showImageButton = false;
iframe.contentWindow.postMessage({
html: html,
removeImages: false
}, '*');
};
}
$timeout(scaleToFit, 0);
}
// transform scale iframe (necessary on iOS) to fit container width
function scaleToFit() {
var parentWidth = elm.parent().width();
var w = elm.width();
var scale = '';
if (w > parentWidth) {
scale = parentWidth / w;
scale = 'scale(' + scale + ',' + scale + ')';
}
elm.css({
'-webkit-transform-origin': '0 0',
'transform-origin': '0 0',
'-webkit-transform': scale,
'transform': scale
});
}
};
});

53
src/js/directive/write.js Normal file
View File

@ -0,0 +1,53 @@
'use strict';
var ngModule = angular.module('woDirectives');
ngModule.directive('focusInput', function($timeout, $parse) {
return {
//scope: true, // optionally create a child scope
link: function(scope, element, attrs) {
var model = $parse(attrs.focusInput);
scope.$watch(model, function(value) {
if (value === true) {
$timeout(function() {
element.find('input').first().focus();
}, 100);
}
});
}
};
});
ngModule.directive('focusInputOnClick', function() {
return {
//scope: true, // optionally create a child scope
link: function(scope, element) {
element.on('click', function() {
element.find('input').first().focus();
});
}
};
});
ngModule.directive('attachmentInput', function() {
return function(scope, elm) {
elm.on('change', function(e) {
for (var i = 0; i < e.target.files.length; i++) {
addAttachment(e.target.files.item(i));
}
});
function addAttachment(file) {
var reader = new FileReader();
reader.onload = function(e) {
scope.attachments.push({
filename: file.name,
mimeType: file.type,
content: new Uint8Array(e.target.result)
});
scope.$digest();
};
reader.readAsArrayBuffer(file);
}
};
});