fix some zero-width space weirdness
[fnpeditor.git] / src / editor / modules / documentToolbar / actionView.js
1 define(function(require) {
2     
3 'use strict';
4 /* globals gettext */
5
6 var $ = require('libs/jquery'),
7     Backbone = require('libs/backbone'),
8     _ = require('libs/underscore'),
9     viewTemplate = require('libs/text!modules/documentToolbar/templates/actionView.html'),
10     buttonTemplate = require('libs/text!modules/documentToolbar/templates/actionViewButton.html'),
11     selectionTemplate = require('libs/text!modules/documentToolbar/templates/actionViewSelection.html');
12
13
14 viewTemplate = _.template(viewTemplate);
15 buttonTemplate = _.template(buttonTemplate);
16 selectionTemplate = _.template(selectionTemplate);
17
18 var iconExists = function(iconName) {
19     /* globals window */
20     var el = $('<i>').addClass('icon-' + iconName);
21     $('body').append(el);
22     var style = window.getComputedStyle(el[0]);
23     var toret = /glyphicons/.test(style.backgroundImage) && !/14px 14px/.test(style.backgroundPosition);
24     el.remove();
25     return toret;
26 };
27
28 var ActionView = Backbone.View.extend({
29     events: {
30         'mousedown .btn': 'onMouseDown',
31         'click .btn': 'onExecute',
32         'change select': 'onSelectionChange',
33         'mouseenter': 'onMouseEnter',
34         'mouseleave': 'onMouseLeave'
35     },
36     initialize: function() {
37         this.action = this.options.action;
38         this.action.on('paramsChanged', function() {
39             this.render();
40         }, this);
41         this.setElement(viewTemplate());
42     },
43     render: function() {
44         /* globals document */
45
46         var actionState = this.action.getState();
47
48         if(!actionState) {
49             this.$el.html(buttonTemplate({label: gettext('error :('), iconName:''}));
50             this._button().attr('disabled', true);
51             return;
52         }
53
54         var templateContext = {
55             label: actionState.label || '?',
56             iconName: (iconExists(actionState.icon)) ? actionState.icon : null,
57             iconStyle: actionState.iconStyle
58         },
59             hovered = document.querySelectorAll(':hover'),
60             hovers = false,
61             button = this._button();
62            
63         if(hovered.length && _.last(hovered) === button[0]) {
64             hovers = true;
65         }
66
67         this.$el.empty();
68         _.pairs(this.action.definition.params).forEach(function(pair) {
69             var paramName = pair[0],
70                 paramDesc = pair[1],
71                 widget;
72             if(paramDesc.type === 'select') {
73                 widget = $(selectionTemplate({
74                     paramName: paramName,
75                     options: paramDesc.options
76                 }));
77                 if(this.action.params[paramName]) {
78                     widget.find('option[value=' + this.action.params[paramName].id + ']').attr('selected', true);
79                 }
80                 this.$el.append(widget);
81             }
82         }.bind(this));
83
84         this.$el.append(buttonTemplate(templateContext));
85         button = this._button();
86         
87         if(!actionState.allowed) {
88             button.attr('disabled', true);
89             button.wrap('<div style="position: relative;">');
90             button.after('<div style="position: absolute; top:0; bottom:0; left:0; right: 0"></div>');
91         }
92         
93         if(actionState.toggled !== undefined) {
94             button.toggleClass('active', actionState.toggled);
95         }
96
97         if(hovers) {
98             this.trigger('hover');
99         }
100     },
101     onMouseEnter: function() {
102         this.trigger('hover');
103     },
104     onMouseLeave: function() {
105         this.trigger('leave');
106     },
107     onMouseDown: function() {
108         this.trigger('mousedown');
109     },
110     onExecute: function() {
111         this.action.execute();
112     },
113     onSelectionChange: function(e) {
114         var select = $(e.target),
115             paramName = select.attr('param');
116
117         this.action.definition.params[paramName].options.some(function(option) {
118             if(option.id.toString() === select.val()) {
119                 this.action.updateWidgetParam(paramName, option);
120                 return true; // break
121             }
122         }.bind(this));
123     },
124     _button: function() {
125         return this.$el.find('button');
126     }
127 });
128
129 var create = function(action) {
130     var view = new ActionView({action:action});
131     view.render();
132
133     return {
134         on: function() {
135             view.on.apply(view, Array.prototype.slice.call(arguments, 0));
136         },
137         dom: view.$el,
138     };
139 };
140
141 return {
142     create: create
143 };
144
145 });