Skip to content

Commit

Permalink
Further progress on the localizations-input directive. Finished most …
Browse files Browse the repository at this point in the history
…of the directive implementation
  • Loading branch information
zakhenry committed Oct 30, 2015
1 parent da70f8c commit 729a242
Show file tree
Hide file tree
Showing 7 changed files with 125 additions and 130 deletions.
9 changes: 7 additions & 2 deletions app/src/app/admin/articles/article/post/post.tpl.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ <h2 ng-if="!ArticleController.$stateParams.newArticle">Edit</h2>
<md-input-container>
<label for="articleFormTitle">Title</label>

<input id="articleFormTitle" ng-model="ArticleController.article.title" name="title" type="text" ng-required="true">
<input id="articleFormTitle" ng-model="ArticleController.article.title" localizable-input="ArticleController.article._localizations" name="title" type="text" ng-required="true">
<ng-messages for="articleFormTitle.title.$error">
<ng-message when="required">This is required.</ng-message>
</ng-messages>
Expand All @@ -20,7 +20,12 @@ <h2 ng-if="!ArticleController.$stateParams.newArticle">Edit</h2>
<md-input-container flex>
<label for="articleFormExcerpt">Excerpt</label>

<textarea id="articleFormExcerpt" ng-model="ArticleController.article.excerpt" columns="1" md-maxlength="140"></textarea>
<textarea
id="articleFormExcerpt"
ng-model="ArticleController.article.excerpt"
localizable-input="ArticleController.article._localizations"
columns="1" md-maxlength="140"
></textarea>
<ng-messages for="articleFormTitle.excerpt.$error">
<ng-message when="maxlength">Maximum length is 140 chars (Like a tweet!)</ng-message>
</ng-messages>
Expand Down
3 changes: 2 additions & 1 deletion app/src/common/directives/directives.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@ namespace common.directives {
export const namespace = 'common.directives';

angular.module(namespace, [
namespace + '.avatar',
namespace + '.menuToggle',
namespace + '.uploadImage',
namespace + '.markdownEditor',
namespace + '.localizableInput',
namespace + '.selectMediaImage',
namespace + '.contentSectionsInput',
namespace + '.avatar'
])
;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,84 +1,33 @@
<md-dialog flex="80" id="localizableInputDialog">
<md-dialog flex="50" id="localizableInputDialog">
<md-toolbar>
<div class="md-toolbar-tools">
<h2>Select Media</h2>
<h2>Translate</h2>
<span flex></span>
<md-button class="md-icon-button" ng-click="LocalizableInputDialogController.cancelDialog()">
<md-icon aria-label="Close dialog">close</md-icon>
</md-button>
</div>
</md-toolbar>
<md-dialog-content>
<p ng-bind-html="LocalizableInputDialogController.originalValue"></p>

<md-tabs md-selected="LocalizableInputDialogController.selectedIndex" md-dynamic-height md-border-bottom md-autoselect>
<md-tab label="Upload new">
<md-tab label="{{region.name}}"ng-repeat="region in LocalizableInputDialogController.regionService.supportedRegions">

<upload-image ng-if="!LocalizableInputDialogController.selectedImage" ng-model="LocalizableInputDialogController.selectedImage"></upload-image>

<dl ng-if="LocalizableInputDialogController.selectedImage">
<dt>Image</dt>
<dd>
<cl-image public-id="{{LocalizableInputDialogController.selectedImage.imageId}}" format="{{LocalizableInputDialogController.selectedImage.format}}">
<cl-transformation height="300" width="300" crop="fill" gravity="north"/>
</cl-image>
</dd>
<dt>Alt</dt>
<dd>{{LocalizableInputDialogController.selectedImage.alt}}</dd>
<dt>Title</dt>
<dd>{{LocalizableInputDialogController.selectedImage.title}}</dd>
</dl>
<md-input-container flex ng-switch="LocalizableInputDialogController.inputNodeName">
<textarea ng-switch-when="textarea" ng-model="LocalizableInputDialogController.localizationMap[region.code]"></textarea>
<input ng-switch-when="input" ng-model="LocalizableInputDialogController.localizationMap[region.code]">
<markdown-editor ng-switch-when="markdown-editor" ng-model="testModel"></markdown-editor>
</md-input-container>

</md-tab>
<md-tab label="Select From Library">

<md-grid-list
md-cols-sm="1"
md-cols-md="2"
md-cols-gt-md="4"
md-row-height="1:1"
md-gutter="12px"
md-gutter-gt-sm="8px">

<md-grid-tile
ng-repeat="image in LocalizableInputDialogController.library"
ng-click="LocalizableInputDialogController.toggleImageSelection(image)"
md-ink-ripple style="cursor:pointer"
ng-class="{'selected':LocalizableInputDialogController.selectedImage == image}"
>

<md-grid-tile-header>
<h3>{{image.alt | uppercase}}</h3>
</md-grid-tile-header>

<cl-image width="100%" public-id="{{image.imageId}}" format="{{image.format}}">
<cl-transformation height="300" width="300" crop="fill" gravity="north"/>
</cl-image>

<md-grid-tile-footer ng-if="!!image.title">
<h3>{{image.title}}</h3>
</md-grid-tile-footer>
</md-grid-tile>

</md-grid-list>

<md-toolbar>
<md-tabs md-dynamic-height md-selected="LocalizableInputDialogController.currentPageIndex">

<md-tab ng-repeat="pageNumber in LocalizableInputDialogController.pages"
ng-click="LocalizableInputDialogController.goToPage(pageNumber)"
label="{{pageNumber}}">
</md-tab>

</md-tabs>
</md-toolbar>

</md-tab>
</md-tabs>

</md-dialog-content>

<div class="md-actions">
<md-button ng-disabled="!LocalizableInputDialogController.selectedImage" ng-click="LocalizableInputDialogController.selectImage()" class="md-primary">Select Image</md-button>
<md-button ng-click="LocalizableInputDialogController.saveLocalizations()" class="md-primary">Save</md-button>
<md-button ng-click="LocalizableInputDialogController.cancelDialog()" class="md-warn">Cancel</md-button>
</div>
</md-dialog>
Original file line number Diff line number Diff line change
Expand Up @@ -2,65 +2,72 @@ namespace common.directives.localizableInput.dialog {

export const namespace = 'common.directives.localizableInput.dialog';

export interface ILocalizationMap {
[regionCode:string] : string;
}

export class LocalizableInputDialogController {

public selectedIndex:number;
public selectedImage:common.models.Image;
public library:common.models.Image[];
private imagesPaginator:common.services.pagination.Paginator;
private perPage:number = 12;
public pages:number[];
public currentPage:number = 1;
private currentPageIndex:number;
static $inject = ['localizations', 'attributeKey', 'inputNodeName', 'originalValue', 'regionService', '$mdDialog', 'ngRestAdapter'];

public selectedIndex:number = 0;
public localizationMap:ILocalizationMap;

static $inject = ['$mdDialog', 'imageService'];
constructor(public localizations:common.models.Localization<any>[],
public attributeKey:string,
public inputNodeName:string,
public originalValue:string,
public regionService:common.services.region.RegionService,
private $mdDialog:ng.material.IDialogService,
private ngRestAdapter:NgRestAdapter.NgRestAdapterService
) {

constructor(private $mdDialog:ng.material.IDialogService,
private imageService:common.services.image.ImageService) {
this.localizationMap = _.reduce(regionService.supportedRegions, (localizationMap, region:global.ISupportedRegion) => {
localizationMap[region.code] = this.getLocalizationValueForRegion(region.code);
return localizationMap;
}, {});

this.init();
}

private init() {
this.imagesPaginator = this.imageService.getPaginator().setCount(this.perPage);
private getLocalizationValueForRegion(regionCode:string):string {
let localization = _.find(this.localizations, {regionCode: regionCode});

this.imagesPaginator.getPage(this.currentPage)
.then((images:common.models.Image[]) => {
this.library = images;
this.pages = this.imagesPaginator.getPages();
});
if (!localization){
return null;
}

this.currentPageIndex = this.currentPage - 1;
return localization.localizations[this.attributeKey];
}

public toggleImageSelection(selectedImage:common.models.Image) {
public saveLocalizations(){

if (this.selectedImage == selectedImage){
this.selectedImage = null;
}else{
this.selectedImage = selectedImage;
}
}
let updatedLocalizations = _.reduce(this.localizationMap, (updatedLocalizations:common.models.Localization<any>[], translation:string, regionCode:string) => {
if(!translation){
return updatedLocalizations;
}

public selectImage() {
let existing = _.find(this.localizations, {regionCode: regionCode});

if (!this.selectedImage) {
this.$mdDialog.cancel('closed');
}
if(existing){
existing.localizations[this.attributeKey] = translation;
updatedLocalizations.push(existing);
return updatedLocalizations;
}

this.$mdDialog.hide(this.selectedImage);
}
updatedLocalizations.push(new common.models.Localization<any>({
localizableId: this.ngRestAdapter.uuid(),
localizableType: null, //this is determined by the api
localizations: {
[this.attributeKey]: translation
},
regionCode: regionCode,
}));

public goToPage(page:number):ng.IPromise<common.models.Image[]> {
return updatedLocalizations;

this.currentPage = page;
}, []);

return this.imagesPaginator.getPage(this.currentPage)
.then((images:common.models.Image[]) => {
this.library = images;
return this.library;
});
this.$mdDialog.hide(updatedLocalizations);
}

/**
Expand Down

This file was deleted.

76 changes: 54 additions & 22 deletions app/src/common/directives/localizableInput/localizableInput.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,53 +3,81 @@ namespace common.directives.localizableInput {
export const namespace = 'common.directives.localizableInput';

export interface ILocalizationChangeHandler {
(localizations:common.models.Localization[]):void;
(localizations:common.models.Localization<any>[]):void;
}

export interface IInputElementAttributes extends ng.IAttributes{
ngModel: string;
}

export class LocalizableInputController {

public localizableInput:common.models.Localization[];
public localizableInput:common.models.Localization<any>[];
private changeHandler:ILocalizationChangeHandler;
public localizationObject:common.models.Localization;
private attributeKey:string;
private inputNodeName:string;
public originalValue:string;

static $inject = ['$mdDialog'];
constructor(private $mdDialog) {
static $inject = ['$mdDialog', '$compile'];
constructor(private $mdDialog:ng.material.IDialogService, private $compile:ng.ICompileService) {
}

public registerChangeHandler(handler:ILocalizationChangeHandler){
this.changeHandler = handler;
}

public promptAddLocalization($event:MouseEvent):ng.IPromise<string> {
public getButtonElement($scope:ng.IScope):ng.IAugmentedJQuery{

return this.$compile(`<md-icon ng-click="LocalizableInputController.promptAddLocalization($event)">translate</md-icon>`)($scope);
}

/**
* Get the attribute name by parsing the ng-model="path.to.attribute" attribute.
* @todo consider alternative method as this relies on the attribute being at the top level of the localisation
* @param $element
* @param $attrs
*/
public setInputAttributes($element:ng.IAugmentedJQuery, $attrs:IInputElementAttributes):void {
this.attributeKey = _.last($attrs.ngModel.split('.'));
this.inputNodeName = $element.prop('nodeName').toLowerCase();
}

/**
* Prompt the localisation dialog to pop up
* @param $event
* @returns {IPromise<common.models.Localization<any>[]>}
*/
public promptAddLocalization($event:MouseEvent):ng.IPromise<common.models.Localization<any>[]> {

let dialogConfig:ng.material.IDialogOptions = {
templateUrl: 'templates/common/directives/LocalizableInput/dialog/localizableInputDialog.tpl.html',
targetEvent: $event,
templateUrl: 'templates/common/directives/localizableInput/dialog/localizableInputDialog.tpl.html',
controller: namespace+'.dialog.controller',
controllerAs: 'LocalizableInputDialogController',
clickOutsideToClose: true,
locals: {}
locals: {
localizations: this.localizableInput,
attributeKey: this.attributeKey,
inputNodeName: this.inputNodeName,
originalValue: this.originalValue,
}
};

return this.$mdDialog.show(dialogConfig)
.then((localization:string) => {
.then((updatedLocalizations:common.models.Localization<any>[]) => {

//this.localizationObject = localization;
//
//if (this.changeHandler){
// this.changeHandler(localization);
//}
this.changeHandler(updatedLocalizations);

return localization;
return updatedLocalizations;
});

}
}

class LocalizableInputDirective implements ng.IDirective {

public restrict = 'E';
public restrict = 'A';
public require = ['ngModel','localizableInput'];
public templateUrl = 'templates/common/directives/localizableInput/localizableInput.tpl.html';
public replace = false;
public scope = {
localizableInput: '='
Expand All @@ -62,19 +90,23 @@ namespace common.directives.localizableInput {
constructor() {
}

public link = ($scope: ng.IScope, $element: ng.IAugmentedJQuery, $attrs: ng.IAttributes, $controllers: [ng.INgModelController, LocalizableInputController]) => {
public link = ($scope: ng.IScope, $element: ng.IAugmentedJQuery, $attrs: IInputElementAttributes, $controllers: [ng.INgModelController, LocalizableInputController]) => {

let $ngModelController = $controllers[0];
let directiveController = $controllers[1];

directiveController.registerChangeHandler((localizations:common.models.Localization[]) => {
directiveController.setInputAttributes($element, $attrs);

$element.after(directiveController.getButtonElement($scope));

directiveController.registerChangeHandler((localizations:common.models.Localization<any>[]) => {
$ngModelController.$setDirty();
});

$ngModelController.$render = () => {
//do something when the primary input changes?
};
//@todo resolve how to get the following to run the first time, consider $render, but that causes the ngmodel to be blank for some reason
$ngModelController.$viewChangeListeners.push(() => {
directiveController.originalValue = $ngModelController.$modelValue;
});

};

Expand Down
Loading

0 comments on commit 729a242

Please sign in to comment.