PluginProbe ʕ •ᴥ•ʔ
SiteOrigin CSS / 1.0.1
SiteOrigin CSS v1.0.1
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
444 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 // Display the link
201 var link = el.closest('a[href]');
202 var linkContainer = this.$('.socss-link');
203 if( link.length ) {
204 linkContainer.show().find('a')
205 .html( link.attr('href').replace(/[\?&]*so_css_preview=1/, '') )
206 .attr('href', link.attr('href') );
207 }
208 else {
209 linkContainer.hide();
210 }
211
212 this.trigger('set_active_element', el, selectors);
213 }
214
215 } );
216
217 socss.view.highlighter = Backbone.View.extend( {
218 template: _.template( $('#socss-template-hover').html().trim() ),
219 highlighted: [ ],
220
221 highlight: function( els ){
222 this.clear();
223 var thisView = this;
224
225 $(els).each(function(i, el){
226 el = $(el);
227
228 if( !el.is(':visible') ) {
229 // Skip over invisible elements
230 return true;
231 }
232
233 var hl = $( thisView.template() );
234 hl.css({
235 'top' : el.offset().top,
236 'left' : el.offset().left,
237 'width' : el.outerWidth(),
238 'height' : el.outerHeight()
239 }).appendTo( 'body' );
240
241 var g;
242
243 var padding = el.padding();
244 for( var k in padding ) {
245 if( parseInt( padding[k] ) > 0 ) {
246 g = hl.find( '.socss-guide-padding.socss-guide-' + k ).show();
247 if( k === 'top' || k === 'bottom' ) {
248 g.css('height', padding[k]);
249 }
250 else {
251 g.css('width', padding[k]);
252 g.css({
253 'width': padding[k],
254 'top' : padding.top,
255 'bottom' : padding.bottom
256 });
257 }
258 }
259 }
260
261 var margin = el.margin();
262 for( var k in margin ) {
263 if( parseInt( margin[k] ) > 0 ) {
264 g = hl.find( '.socss-guide-margin.socss-guide-' + k ).show();
265 if( k === 'top' || k === 'bottom' ) {
266 g.css('height', margin[k]);
267 }
268 else {
269 g.css('width', margin[k]);
270 }
271 }
272 }
273
274 thisView.highlighted.push( hl );
275 } );
276 },
277
278 clear: function(){
279 while( this.highlighted.length ) {
280 this.highlighted.pop().remove();
281 }
282 }
283 } );
284
285 socss.parsedCss = {};
286 socss.fn.getParsedCss = function(){
287 // Load all the parsed CSS
288 if( Object.keys(socss.parsedCss).length === 0 ) {
289 var parser = new cssjs();
290 $('.socss-theme-styles').each(function(){
291 var $$ = $(this);
292 var p = parser.parseCSS( $$.html() );
293 socss.parsedCss[ $$.attr('id') ] = p;
294 });
295 }
296 return socss.parsedCss;
297 };
298
299 /**
300 * Function to get all the available page selectors
301 */
302 socss.fn.pageSelectors = function(){
303 var selectors = [];
304 var parsedCss = socss.fn.getParsedCss();
305
306 for( var k in parsedCss ) {
307 for( var i = 0; i < parsedCss[k].length; i++ ) {
308 if (typeof parsedCss[k][i].selector === 'undefined') {
309 continue;
310 }
311
312 var ruleSpecificity = SPECIFICITY.calculate( parsedCss[k][i].selector );
313 for (var j = 0; j < ruleSpecificity.length; j++) {
314 selectors.push({
315 'selector': ruleSpecificity[j].selector.trim(),
316 'specificity': parseInt(ruleSpecificity[j].specificity.replace(/,/g, ''))
317 });
318 }
319
320 }
321 }
322
323 // Also add selectors for all the elements in the
324 $('body *').each(function(){
325 var $$ = $(this);
326 var elName = socss.fn.elSelector( $$ );
327 var ruleSpecificity = SPECIFICITY.calculate( elName );
328 for (var k = 0; k < ruleSpecificity.length; k++) {
329 selectors.push({
330 'selector': ruleSpecificity[k].selector.trim(),
331 'specificity': parseInt(ruleSpecificity[k].specificity.replace(/,/g, ''))
332 });
333 }
334 });
335
336 selectors = _.uniq( selectors, false, function( a ){
337 return a.selector;
338 } );
339
340 selectors.sort(function(a, b){
341 return a.specificity > b.specificity ? -1 : 1;
342 });
343
344 return selectors;
345 };
346
347 socss.fn.elementAttributes = function( el ) {
348 if( !document.styleSheets ) {
349 return [];
350 }
351
352 var elProperties = [];
353
354 var trimFunc = function(e) {
355 return e.trim();
356 };
357
358 var filterFunc = function(e){
359 return e !== '';
360 };
361
362 var splitFunc = function(e) {
363 return e.split(':').map( trimFunc );
364 };
365
366
367 var parsedCss = socss.fn.getParsedCss();
368
369 for( var k in parsedCss ) {
370 for( var i = 0; i < parsedCss[k].length; i++ ) {
371 if (
372 typeof parsedCss[k][i].selector === 'undefined' ||
373 typeof parsedCss[k][i].type !== 'undefined' ||
374 parsedCss[k][i].selector[0] === '@'
375 ) {
376 continue;
377 }
378
379 var ruleSpecificity = SPECIFICITY.calculate( parsedCss[k][i].selector );
380 for (var j = 0; j < ruleSpecificity.length; j++) {
381 try {
382 if( el.is( ruleSpecificity[j].selector ) ) {
383 for( var l = 0; l < parsedCss[k][i].rules.length; l++ ) {
384 elProperties.push({
385 'name' : parsedCss[k][i].rules[l].directive,
386 'value' : parsedCss[k][i].rules[l].value,
387 'specificity' : parseInt(ruleSpecificity[j].specificity.replace(/,/g, ''))
388 });
389 }
390 }
391 }
392 catch( e ) {
393 // For now, we're just going to ignore rules that trigger jQuery errors
394 }
395 }
396
397 }
398 }
399
400 elProperties.sort( function(a,b) {
401 return a.specificity > b.specificity ? 1 : -1;
402 }).reverse();
403
404 var returnProperties = {};
405 for( var pi = 0; pi < elProperties.length; pi++ ) {
406 if( typeof returnProperties[elProperties[pi].name] === 'undefined' ) {
407 returnProperties[elProperties[pi].name] = elProperties[pi].value;
408 }
409 }
410
411 return returnProperties;
412 };
413
414 socss.fn.elSelector = function( el ){
415 var elName = '';
416 if( el.attr('id') !== undefined ) {
417 elName += '#' + el.attr('id');
418 }
419 if( el.attr('class') !== undefined ) {
420 elName += '.' + el.attr('class').replace(/\s+/, '.');
421 }
422
423 if( elName === '' ) {
424 elName = el.prop('tagName').toLowerCase();
425 }
426
427 return elName;
428 };
429
430 window.socssInspector = socss;
431
432 } ) ( jQuery, _, socssOptions );
433
434 jQuery( function($){
435 var socss = window.socssInspector;
436
437 // Setup the editor
438 var inspector = new socss.view.inspector( {
439 el : $('#socss-inspector-interface').get(0)
440 } );
441 inspector.activate();
442
443 window.socssInspector.mainInspector = inspector;
444 } );