Skip to content

Commit 02dadb5

Browse files
committed
add proper testing setup and browserify
1 parent 1805c42 commit 02dadb5

27 files changed

+10450
-4078
lines changed

app/main.js

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
var $ = require('jquery');
2+
var Arrow = require('./models/arrow');
3+
var ArrowConfigurationView = require('./views/arrow_configuration_view');
4+
var ArrowPreviewView = require('./views/arrow_preview_view');
5+
var ArrowCSSView = require('./views/arrow_css_view');
6+
7+
/**
8+
@class App
9+
@constructor
10+
@description
11+
Main application object.
12+
Acts as view dispatcher
13+
**/
14+
var App = function () {
15+
this.init.apply(this, arguments);
16+
};
17+
18+
App.prototype = {
19+
20+
init: function () {
21+
this.model = new Arrow();
22+
this._initViews();
23+
},
24+
25+
/**
26+
@method _initViews
27+
@description initializes views
28+
@protected
29+
**/
30+
_initViews: function () {
31+
var model = this.model;
32+
33+
this.views = [
34+
new ArrowConfigurationView({ model: model, container: $('.configuration') }),
35+
new ArrowPreviewView({ model: model, container: $('<style type="text/css"></style>').appendTo('body') }),
36+
new ArrowCSSView({ model: model, container: $('.css_result') }),
37+
];
38+
},
39+
40+
render: function () {
41+
$.each(this.views, function (i, view) {
42+
view.render();
43+
});
44+
}
45+
46+
};
47+
48+
new App().render();
49+

app/models/arrow.js

Lines changed: 291 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,291 @@
1+
var $ = require('jquery');
2+
3+
/**
4+
@class Arrow
5+
@constructor
6+
**/
7+
var Arrow = function () {
8+
this.init.apply(this, arguments);
9+
};
10+
11+
Arrow.prototype = {
12+
13+
init: function () {
14+
// jquerify 'this'
15+
this._$self = $(this);
16+
17+
this._createAttrs();
18+
},
19+
20+
/**
21+
@method invertedPosition
22+
@description
23+
returns the opposite of the position
24+
so 'top' becomes 'bottom' and 'left' becomes 'right'
25+
@returns {String}
26+
**/
27+
invertedPosition: function () {
28+
var pos = this.get('position');
29+
30+
if ( pos === 'top' ) return 'bottom';
31+
else if ( pos === 'bottom') return 'top';
32+
else if ( pos === 'left' ) return 'right';
33+
else if ( pos === 'right' ) return 'left';
34+
},
35+
36+
/**
37+
@method hexToRGB
38+
@description
39+
returns an rgb color from an hex color
40+
@returns {Array}
41+
**/
42+
hexToRGB: function (h) {
43+
if ( typeof h !== 'string' || !h.match(/^#([0-9A-F]{3}$)|([0-9A-F]{6}$)/i) ) return [0, 0, 0];
44+
else if ( h.match(/^(#[0-9a-f]{3})$/i) ) h = '#' + h[1] + h[1] + h[2] + h[2] + h[3] + h[3];
45+
var rgb = [],
46+
i = 1;
47+
48+
for(; i < 6; i+=2) {
49+
rgb.push(parseInt(h.substring(i, i + 2), 16));
50+
}
51+
return rgb;
52+
},
53+
54+
/**
55+
@method _baseCSS
56+
@description generates the base css
57+
@returns {String} css
58+
@protected
59+
**/
60+
_baseCSS: function () {
61+
var pos = this.get('position'),
62+
iPos = this.invertedPosition(),
63+
color = this.get('color'),
64+
borderWidth = this.get('borderWidth'),
65+
borderColor = this.get('borderColor'),
66+
hasBorder = borderWidth > 0,
67+
css = '.arrow_box {\n';
68+
69+
color = this._sanitizeHexColors(color);
70+
71+
css += '\tposition: relative;\n';
72+
css += '\tbackground: ' + color + ';\n';
73+
74+
if (hasBorder) {
75+
borderColor = this._sanitizeHexColors(borderColor);
76+
css += '\tborder: ' + borderWidth + 'px solid ' + borderColor + ';\n';
77+
}
78+
79+
css += '}\n';
80+
css += '.arrow_box:after';
81+
82+
if (hasBorder) css += ', .arrow_box:before {\n';
83+
else css += ' {\n';
84+
85+
css += '\t' + iPos +': 100%;\n';
86+
87+
if (pos === 'top' || pos === 'bottom') {
88+
css += '\tleft: 50%;\n';
89+
}
90+
else {
91+
css += '\ttop: 50%;\n';
92+
}
93+
94+
css += '\tborder: solid transparent;\n';
95+
css += '\tcontent: " ";\n';
96+
css += '\theight: 0;\n';
97+
css += '\twidth: 0;\n';
98+
css += '\tposition: absolute;\n';
99+
css += '\tpointer-events: none;\n';
100+
101+
if (hasBorder) css += '}\n';
102+
103+
return css;
104+
},
105+
106+
/**
107+
@method _arrowCSS
108+
@description generates arrow css
109+
@param {String} color the color of the arrow
110+
@param {Integer} size the size of the arrow
111+
@param {String} layer :after or :before (defaults to :after)
112+
@returns {String} css
113+
@protected
114+
**/
115+
_arrowCSS: function (color, size, layer) {
116+
color = this._sanitizeHexColors(color);
117+
var pos = this.get('position'),
118+
iPos = this.invertedPosition(),
119+
rgbColor = this.hexToRGB(color),
120+
borderWidth = this.get('borderWidth'),
121+
css = "";
122+
123+
layer = layer || 'after';
124+
125+
if(borderWidth > 0) css += '.arrow_box:' + layer + ' {\n';
126+
127+
css += '\tborder-color: rgba(' + rgbColor.join(', ') + ', 0);\n';
128+
css += '\tborder-' + iPos + '-color: ' + color + ';\n';
129+
css += '\tborder-width: ' + size + 'px;\n';
130+
131+
if (pos === 'top' || pos === 'bottom') {
132+
css += '\tmargin-left: -' + size + 'px;\n';
133+
}
134+
else {
135+
css += '\tmargin-top: -' + size + 'px;\n';
136+
}
137+
138+
css += '}';
139+
140+
return css;
141+
},
142+
143+
/**
144+
@method _baseArrowCSS
145+
@description generates the base arrow
146+
@returns {String} css
147+
@protected
148+
**/
149+
_baseArrowCSS: function () {
150+
return this._arrowCSS(
151+
this.get('color'),
152+
this.get('size'),
153+
'after'
154+
);
155+
},
156+
157+
/**
158+
@method _arrowBorderCSS
159+
@description generates the border arrow
160+
@returns {String} css
161+
@protected
162+
**/
163+
_arrowBorderCSS: function () {
164+
var css = '',
165+
borderWidth = this.get('borderWidth');
166+
167+
if (borderWidth > 0) {
168+
css = this._arrowCSS(
169+
this.get('borderColor'),
170+
this.get('size') + Math.round(borderWidth * 1.41421356), // cos(PI/4) * 2
171+
'before'
172+
);
173+
}
174+
175+
return css;
176+
},
177+
178+
/**
179+
@method toCSS
180+
@description returns a CSS representation of the arrow
181+
@returns {String} css
182+
**/
183+
toCSS: function () {
184+
185+
var css = [
186+
this._baseCSS(),
187+
this._baseArrowCSS(),
188+
this._arrowBorderCSS()
189+
];
190+
191+
return css.join(css[2] ? '\n':'');
192+
},
193+
194+
/**
195+
@method _createAttrs
196+
@description creates attributes from the ATTR constant
197+
@protected
198+
**/
199+
_createAttrs: function () {
200+
var ATTRS = Arrow.ATTRS,
201+
attributes = {};
202+
203+
$.each(ATTRS, function (attr, value) {
204+
attributes[attr] = value;
205+
});
206+
207+
this._attributes = attributes;
208+
},
209+
210+
/**
211+
@method _sanitizeHexColors
212+
@description prefix hexcolors with # if necessary
213+
@returns {String} h
214+
@protected
215+
**/
216+
_sanitizeHexColors: function(h) {
217+
return (h.charAt(0)==='#')?h:'#' + h;
218+
},
219+
220+
/**
221+
@method getAttrs
222+
@description returns all the attributes
223+
@returns {Object} all the model attributes
224+
**/
225+
getAttrs: function () {
226+
return this._attributes;
227+
},
228+
229+
/**
230+
@method get
231+
@description returns the provided attribute
232+
@param {String} attr the attribute to return
233+
@returns {?} the attribute
234+
**/
235+
get: function (attr) {
236+
return this._attributes[attr];
237+
},
238+
239+
/**
240+
@method set
241+
@description updates the provided attribute
242+
@param {String} attr the attribute to update
243+
@param {?} val the value to update with
244+
**/
245+
set: function (attr, val) {
246+
if (!(attr in this._attributes)) return;
247+
248+
this._attributes[attr] = val;
249+
this.fire('change');
250+
},
251+
252+
/**
253+
@method on
254+
@description adds event listeners
255+
@note uses jQuery custom events under the hood
256+
@param {String} evType the event type
257+
@param {Function} callback the event handler
258+
@param {Object} context the 'this' for the callback
259+
**/
260+
on: function (evType, callback, context) {
261+
var $self = this._$self;
262+
263+
$self.on(
264+
evType,
265+
$.proxy(callback, context || this)
266+
);
267+
},
268+
269+
/**
270+
@method fire
271+
@description trigger event
272+
@note uses jQuery custom events under the hood
273+
@param {String} evType the event type
274+
**/
275+
fire: function (evType) {
276+
var $self = this._$self;
277+
278+
$self.trigger(evType);
279+
}
280+
281+
};
282+
283+
Arrow.ATTRS = {
284+
position: 'top',
285+
size: 30,
286+
color: '#88b7d5',
287+
borderWidth: 4,
288+
borderColor: '#c2e1f5'
289+
};
290+
291+
module.exports = Arrow;

0 commit comments

Comments
 (0)