PluginProbe ʕ •ᴥ•ʔ
SiteOrigin CSS / 1.0
SiteOrigin CSS v1.0
1.2.1 1.2.10 1.2.11 1.2.12 1.2.13 1.2.14 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 1.3.0 1.3.1 1.3.2 1.4.0 1.4.1 1.4.2 1.4.3 1.5.0 1.5.1 1.5.10 1.5.11 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.5.9 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 trunk 1.0 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.1 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.2.0
so-css / js / inspector.js
so-css / js Last commit date
css.js 11 years ago css.min.js 11 years ago csslint.js 11 years ago csslint.min.js 11 years ago editor.js 11 years ago editor.min.js 11 years ago inspector.js 11 years ago inspector.min.js 11 years ago jquery.sizes.js 11 years ago jquery.sizes.min.js 11 years ago specificity.js 11 years ago specificity.min.js 11 years ago
inspector.js
432 lines
1
2 /* globals jQuery, Backbone, _, socssOptions, SPECIFICITY, console */
3
4 ( function( $, _, socssOptions ){
5
6 var socss = {
7 model : { },
8 collection : { },
9 view : { },
10 fn : {}
11 };
12
13 /**
14 * This is the main view for the app
15 */
16 socss.view.inspector = Backbone.View.extend( {
17
18 active: false,
19 hl: false,
20 hoverEl: false,
21 pageSelectors: [],
22
23 selectorTemplate: _.template('<div class="socss-selector"><%= selector %></div>'),
24
25 initialize: function(){
26 var thisView = this;
27
28 this.hl = new socss.view.highlighter();
29 this.hl.initialize();
30
31 this.pageSelectors = socss.fn.pageSelectors();
32
33 // Setup hovering
34 $('body').on('mouseover', '*', function(e){
35 if( !thisView.active ) {
36 return true;
37 }
38
39 var $$ = $(this);
40 if( $$.closest('.socss-element').length === 0 ) {
41 e.stopPropagation();
42 thisView.setHoverEl( $(this) );
43 }
44 });
45
46 // Setup the click event
47 $('body *').click(function( e ){
48 if( !thisView.active || thisView.$el.is(':hover') ) {
49 return true;
50 }
51
52 e.preventDefault();
53 e.stopPropagation();
54
55 var $$ = $(this);
56 $$.blur();
57 thisView.setActiveEl( thisView.hoverEl );
58 });
59
60 this.$('.socss-enable-inspector').click( function(){
61 thisView.toggleActive();
62 } );
63
64 this.$el.mouseenter( function(){
65 thisView.hl.clear();
66 } );
67
68 // Try register this inspector with the parent editor
69 try {
70 parent.socss.mainEditor.setInspector( this );
71 }
72 catch( err ){
73 console.log( 'No editor to register this inspector with' );
74 }
75
76 },
77
78 /**
79 * Set the element that's currently being hovered
80 *
81 * @param hoverEl
82 */
83 setHoverEl: function( hoverEl ){
84 this.hoverEl = hoverEl;
85 this.hl.highlight( hoverEl );
86 },
87
88 activate: function(){
89 this.active = true;
90 $('body').addClass('socss-active');
91 $('body').removeClass('socss-inactive');
92 },
93
94 deactivate: function(){
95 this.active = false;
96 $('body').addClass('socss-inactive');
97 $('body').removeClass('socss-active');
98 this.hl.clear();
99 this.$('.socss-hierarchy').empty();
100 },
101
102 /**
103 * Toggle the active status
104 */
105 toggleActive: function(){
106 if( this.active ) {
107 this.deactivate();
108 }
109 else {
110 this.activate();
111 }
112 },
113
114 /**
115 * Set the element that we're busy inspecting
116 * @param el
117 */
118 setActiveEl: function( el ) {
119 var thisView = this;
120
121 var $h = this.$('.socss-hierarchy');
122 $h.empty();
123
124 if (el.prop('tagName').toLowerCase() !== 'body') {
125 var cel = $(el);
126 do {
127 $(this.selectorTemplate({selector: socss.fn.elSelector(cel)}))
128 .prependTo($h)
129 .data('el', cel);
130 cel = cel.parent();
131 } while (cel.prop('tagName').toLowerCase() !== 'body');
132
133 $(this.selectorTemplate({selector: 'body'}))
134 .prependTo($h)
135 .data('el', $('body'));
136
137 this.$('.socss-hierarchy .socss-selector')
138 .hover(function () {
139 thisView.hl.highlight($(this).data('el'));
140 })
141 .click(function (e) {
142 e.preventDefault();
143 e.stopPropagation();
144 thisView.setActiveEl($(this).data('el'));
145 });
146 }
147
148 // Scroll all the way left...
149 $h.scrollLeft( 99999 );
150
151 // Now lets add all the CSS selectors
152 var selectors = this.pageSelectors.filter( function(a){
153 // Use try to catch any malformed selectors
154 try {
155 return el.is( a.selector );
156 }
157 catch(err) {
158 return false;
159 }
160 } );
161
162 var container = this.$('.socss-selectors-window').empty();
163
164 _.each( selectors, function(selector){
165 container.append(
166 $( thisView.selectorTemplate(selector) )
167 .data( selector )
168 );
169 } );
170 container.find('> div')
171 .mouseenter( function(){
172 thisView.hl.highlight( $(this).data('selector') );
173 } )
174 .click( function(e){
175 e.preventDefault();
176 e.stopPropagation();
177
178 thisView.trigger( 'click_selector', $(this).data('selector') );
179 } );
180
181 // And the CSS attributes
182 var attributes = socss.fn.elementAttributes(el);
183 container = this.$('.socss-properties-window').empty();
184
185 _.each( attributes, function(v, k){
186 container.append(
187 $( thisView.selectorTemplate( { selector: '<strong>' + k + '</strong>: ' + v } ) )
188 .data( 'property', k + ': ' + v )
189 );
190 } );
191
192 container.find('> div')
193 .click( function(e){
194 e.preventDefault();
195 e.stopPropagation();
196
197 thisView.trigger( 'click_property', $(this).data('property') );
198 });
199
200 this.trigger('set_active_element', el, selectors);
201 }
202
203 } );
204
205 socss.view.highlighter = Backbone.View.extend( {
206 template: _.template( $('#socss-template-hover').html().trim() ),
207 highlighted: [ ],
208
209 highlight: function( els ){
210 this.clear();
211 var thisView = this;
212
213 $(els).each(function(i, el){
214 el = $(el);
215
216 if( !el.is(':visible') ) {
217 // Skip over invisible elements
218 return true;
219 }
220
221 var hl = $( thisView.template() );
222 hl.css({
223 'top' : el.offset().top,
224 'left' : el.offset().left,
225 'width' : el.outerWidth(),
226 'height' : el.outerHeight()
227 }).appendTo( 'body' );
228
229 var g;
230
231 var padding = el.padding();
232 for( var k in padding ) {
233 if( parseInt( padding[k] ) > 0 ) {
234 g = hl.find( '.socss-guide-padding.socss-guide-' + k ).show();
235 if( k === 'top' || k === 'bottom' ) {
236 g.css('height', padding[k]);
237 }
238 else {
239 g.css('width', padding[k]);
240 g.css({
241 'width': padding[k],
242 'top' : padding.top,
243 'bottom' : padding.bottom
244 });
245 }
246 }
247 }
248
249 var margin = el.margin();
250 for( var k in margin ) {
251 if( parseInt( margin[k] ) > 0 ) {
252 g = hl.find( '.socss-guide-margin.socss-guide-' + k ).show();
253 if( k === 'top' || k === 'bottom' ) {
254 g.css('height', margin[k]);
255 }
256 else {
257 g.css('width', margin[k]);
258 }
259 }
260 }
261
262 thisView.highlighted.push( hl );
263 } );
264 },
265
266 clear: function(){
267 while( this.highlighted.length ) {
268 this.highlighted.pop().remove();
269 }
270 }
271 } );
272
273 socss.parsedCss = {};
274 socss.fn.getParsedCss = function(){
275 // Load all the parsed CSS
276 if( Object.keys(socss.parsedCss).length === 0 ) {
277 var parser = new cssjs();
278 $('.socss-theme-styles').each(function(){
279 var $$ = $(this);
280 var p = parser.parseCSS( $$.html() );
281 socss.parsedCss[ $$.attr('id') ] = p;
282 });
283 }
284 return socss.parsedCss;
285 };
286
287 /**
288 * Function to get all the available page selectors
289 */
290 socss.fn.pageSelectors = function(){
291 var selectors = [];
292 var parsedCss = socss.fn.getParsedCss();
293
294 for( var k in parsedCss ) {
295 for( var i = 0; i < parsedCss[k].length; i++ ) {
296 if (typeof parsedCss[k][i].selector === 'undefined') {
297 continue;
298 }
299
300 var ruleSpecificity = SPECIFICITY.calculate( parsedCss[k][i].selector );
301 for (var j = 0; j < ruleSpecificity.length; j++) {
302 selectors.push({
303 'selector': ruleSpecificity[j].selector.trim(),
304 'specificity': parseInt(ruleSpecificity[j].specificity.replace(/,/g, ''))
305 });
306 }
307
308 }
309 }
310
311 // Also add selectors for all the elements in the
312 $('body *').each(function(){
313 var $$ = $(this);
314 var elName = socss.fn.elSelector( $$ );
315 var ruleSpecificity = SPECIFICITY.calculate( elName );
316 for (var k = 0; k < ruleSpecificity.length; k++) {
317 selectors.push({
318 'selector': ruleSpecificity[k].selector.trim(),
319 'specificity': parseInt(ruleSpecificity[k].specificity.replace(/,/g, ''))
320 });
321 }
322 });
323
324 selectors = _.uniq( selectors, false, function( a ){
325 return a.selector;
326 } );
327
328 selectors.sort(function(a, b){
329 return a.specificity > b.specificity ? -1 : 1;
330 });
331
332 return selectors;
333 };
334
335 socss.fn.elementAttributes = function( el ) {
336 if( !document.styleSheets ) {
337 return [];
338 }
339
340 var elProperties = [];
341
342 var trimFunc = function(e) {
343 return e.trim();
344 };
345
346 var filterFunc = function(e){
347 return e !== '';
348 };
349
350 var splitFunc = function(e) {
351 return e.split(':').map( trimFunc );
352 };
353
354
355 var parsedCss = socss.fn.getParsedCss();
356
357 for( var k in parsedCss ) {
358 for( var i = 0; i < parsedCss[k].length; i++ ) {
359 if (
360 typeof parsedCss[k][i].selector === 'undefined' ||
361 typeof parsedCss[k][i].type !== 'undefined' ||
362 parsedCss[k][i].selector[0] === '@'
363 ) {
364 continue;
365 }
366
367 var ruleSpecificity = SPECIFICITY.calculate( parsedCss[k][i].selector );
368 for (var j = 0; j < ruleSpecificity.length; j++) {
369 try {
370 if( el.is( ruleSpecificity[j].selector ) ) {
371 for( var l = 0; l < parsedCss[k][i].rules.length; l++ ) {
372 elProperties.push({
373 'name' : parsedCss[k][i].rules[l].directive,
374 'value' : parsedCss[k][i].rules[l].value,
375 'specificity' : parseInt(ruleSpecificity[j].specificity.replace(/,/g, ''))
376 });
377 }
378 }
379 }
380 catch( e ) {
381 // For now, we're just going to ignore rules that trigger jQuery errors
382 }
383 }
384
385 }
386 }
387
388 elProperties.sort( function(a,b) {
389 return a.specificity > b.specificity ? 1 : -1;
390 }).reverse();
391
392 var returnProperties = {};
393 for( var pi = 0; pi < elProperties.length; pi++ ) {
394 if( typeof returnProperties[elProperties[pi].name] === 'undefined' ) {
395 returnProperties[elProperties[pi].name] = elProperties[pi].value;
396 }
397 }
398
399 return returnProperties;
400 };
401
402 socss.fn.elSelector = function( el ){
403 var elName = '';
404 if( el.attr('id') !== undefined ) {
405 elName += '#' + el.attr('id');
406 }
407 if( el.attr('class') !== undefined ) {
408 elName += '.' + el.attr('class').replace(/\s+/, '.');
409 }
410
411 if( elName === '' ) {
412 elName = el.prop('tagName').toLowerCase();
413 }
414
415 return elName;
416 };
417
418 window.socssInspector = socss;
419
420 } ) ( jQuery, _, socssOptions );
421
422 jQuery( function($){
423 var socss = window.socssInspector;
424
425 // Setup the editor
426 var inspector = new socss.view.inspector( {
427 el : $('#socss-inspector-interface').get(0)
428 } );
429 inspector.activate();
430
431 window.socssInspector.mainInspector = inspector;
432 } );