kss-rails 1.0.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,4 +4,9 @@
4
4
 
5
5
  # 1.0.1
6
6
 
7
- * Added kss/application layout to the KSS::ApplicationController
7
+ * Added kss/application layout to the KSS::ApplicationController
8
+
9
+ # 1.0.2
10
+
11
+ * Highlight source code blocks (jankeesvw)
12
+ * Raise an error suggesting to find missing section if not found (jankeesvw)
data/Gemfile CHANGED
@@ -1,4 +1,3 @@
1
1
  source 'http://rubygems.org'
2
2
 
3
- # Specify your gem's dependencies in kss-server.gemspec
4
3
  gemspec
@@ -1,7 +1,7 @@
1
1
  # This class scans your stylesheets for pseudo classes, then inserts a new CSS
2
2
  # rule with the same properties, but named 'psuedo-class-{{name}}'.
3
3
  #
4
- # Supported pseudo classes: hover, disabled.
4
+ # Supported pseudo classes: hover, disabled, active, visited.
5
5
  #
6
6
  # Example:
7
7
  #
@@ -9,16 +9,16 @@
9
9
  # => a.pseudo-class-hover{ color:blue; }
10
10
  class KssStateGenerator
11
11
  constructor: ->
12
- hover = /:hover/
13
- disabled = /:disabled/
14
- active = /:active/
12
+ pseudos = /(\:hover|\:disabled|\:active|\:visited)/g
15
13
 
16
14
  try
17
15
  for stylesheet in document.styleSheets
18
16
  idxs = []
19
17
  for rule, idx in stylesheet.cssRules
20
- if rule.type is CSSRule.STYLE_RULE and (hover.test(rule.selectorText) or disabled.test(rule.selectorText) or active.test(rule.selectorText))
21
- @insertRule(rule.cssText.replace(':', '.pseudo-class-'))
18
+ if (rule.type == CSSRule.STYLE_RULE) && pseudos.test(rule.selectorText)
19
+ replaceRule = (matched, stuff) ->
20
+ return ".pseudo-class-" + matched.replace(':', '')
21
+ @insertRule(rule.cssText.replace(pseudos, replaceRule))
22
22
 
23
23
  # Takes a given style and attaches it to the current page.
24
24
  #
@@ -0,0 +1,858 @@
1
+ /**
2
+ * Copyright 2012 Craig Campbell
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ *
16
+ * Rainbow is a simple code syntax highlighter
17
+ *
18
+ * @preserve @version 1.1.8
19
+ * @url rainbowco.de
20
+ */
21
+ window['Rainbow'] = (function() {
22
+
23
+ /**
24
+ * array of replacements to process at the end
25
+ *
26
+ * @type {Object}
27
+ */
28
+ var replacements = {},
29
+
30
+ /**
31
+ * an array of start and end positions of blocks to be replaced
32
+ *
33
+ * @type {Object}
34
+ */
35
+ replacement_positions = {},
36
+
37
+ /**
38
+ * an array of the language patterns specified for each language
39
+ *
40
+ * @type {Object}
41
+ */
42
+ language_patterns = {},
43
+
44
+ /**
45
+ * an array of languages and whether they should bypass the default patterns
46
+ *
47
+ * @type {Object}
48
+ */
49
+ bypass_defaults = {},
50
+
51
+ /**
52
+ * processing level
53
+ *
54
+ * replacements are stored at this level so if there is a sub block of code
55
+ * (for example php inside of html) it runs at a different level
56
+ *
57
+ * @type {number}
58
+ */
59
+ CURRENT_LEVEL = 0,
60
+
61
+ /**
62
+ * constant used to refer to the default language
63
+ *
64
+ * @type {number}
65
+ */
66
+ DEFAULT_LANGUAGE = 0,
67
+
68
+ /**
69
+ * used as counters so we can selectively call setTimeout
70
+ * after processing a certain number of matches/replacements
71
+ *
72
+ * @type {number}
73
+ */
74
+ match_counter = 0,
75
+
76
+ /**
77
+ * @type {number}
78
+ */
79
+ replacement_counter = 0,
80
+
81
+ /**
82
+ * @type {null|string}
83
+ */
84
+ global_class,
85
+
86
+ /**
87
+ * @type {null|Function}
88
+ */
89
+ onHighlight;
90
+
91
+ /**
92
+ * cross browser get attribute for an element
93
+ *
94
+ * @see http://stackoverflow.com/questions/3755227/cross-browser-javascript-getattribute-method
95
+ *
96
+ * @param {Node} el
97
+ * @param {string} attr attribute you are trying to get
98
+ * @returns {string|number}
99
+ */
100
+ function _attr(el, attr, attrs, i) {
101
+ var result = (el.getAttribute && el.getAttribute(attr)) || 0;
102
+
103
+ if (!result) {
104
+ attrs = el.attributes;
105
+
106
+ for (i = 0; i < attrs.length; ++i) {
107
+ if (attrs[i].nodeName === attr) {
108
+ return attrs[i].nodeValue;
109
+ }
110
+ }
111
+ }
112
+
113
+ return result;
114
+ }
115
+
116
+ /**
117
+ * adds a class to a given code block
118
+ *
119
+ * @param {Element} el
120
+ * @param {string} class_name class name to add
121
+ * @returns void
122
+ */
123
+ function _addClass(el, class_name) {
124
+ el.className += el.className ? ' ' + class_name : class_name;
125
+ }
126
+
127
+ /**
128
+ * checks if a block has a given class
129
+ *
130
+ * @param {Element} el
131
+ * @param {string} class_name class name to check for
132
+ * @returns {boolean}
133
+ */
134
+ function _hasClass(el, class_name) {
135
+ return (' ' + el.className + ' ').indexOf(' ' + class_name + ' ') > -1;
136
+ }
137
+
138
+ /**
139
+ * gets the language for this block of code
140
+ *
141
+ * @param {Element} block
142
+ * @returns {string|null}
143
+ */
144
+ function _getLanguageForBlock(block) {
145
+
146
+ // if this doesn't have a language but the parent does then use that
147
+ // this means if for example you have: <pre data-language="php">
148
+ // with a bunch of <code> blocks inside then you do not have
149
+ // to specify the language for each block
150
+ var language = _attr(block, 'data-language') || _attr(block.parentNode, 'data-language');
151
+
152
+ // this adds support for specifying language via a css class
153
+ // you can use the Google Code Prettify style: <pre class="lang-php">
154
+ // or the HTML5 style: <pre><code class="language-php">
155
+ if (!language) {
156
+ var pattern = /\blang(?:uage)?-(\w+)/,
157
+ match = block.className.match(pattern) || block.parentNode.className.match(pattern);
158
+
159
+ if (match) {
160
+ language = match[1];
161
+ }
162
+ }
163
+
164
+ return language;
165
+ }
166
+
167
+ /**
168
+ * makes sure html entities are always used for tags
169
+ *
170
+ * @param {string} code
171
+ * @returns {string}
172
+ */
173
+ function _htmlEntities(code) {
174
+ return code.replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/&(?![\w\#]+;)/g, '&amp;');
175
+ }
176
+
177
+ /**
178
+ * determines if a new match intersects with an existing one
179
+ *
180
+ * @param {number} start1 start position of existing match
181
+ * @param {number} end1 end position of existing match
182
+ * @param {number} start2 start position of new match
183
+ * @param {number} end2 end position of new match
184
+ * @returns {boolean}
185
+ */
186
+ function _intersects(start1, end1, start2, end2) {
187
+ if (start2 >= start1 && start2 < end1) {
188
+ return true;
189
+ }
190
+
191
+ return end2 > start1 && end2 < end1;
192
+ }
193
+
194
+ /**
195
+ * determines if two different matches have complete overlap with each other
196
+ *
197
+ * @param {number} start1 start position of existing match
198
+ * @param {number} end1 end position of existing match
199
+ * @param {number} start2 start position of new match
200
+ * @param {number} end2 end position of new match
201
+ * @returns {boolean}
202
+ */
203
+ function _hasCompleteOverlap(start1, end1, start2, end2) {
204
+
205
+ // if the starting and end positions are exactly the same
206
+ // then the first one should stay and this one should be ignored
207
+ if (start2 == start1 && end2 == end1) {
208
+ return false;
209
+ }
210
+
211
+ return start2 <= start1 && end2 >= end1;
212
+ }
213
+
214
+ /**
215
+ * determines if the match passed in falls inside of an existing match
216
+ * this prevents a regex pattern from matching inside of a bigger pattern
217
+ *
218
+ * @param {number} start - start position of new match
219
+ * @param {number} end - end position of new match
220
+ * @returns {boolean}
221
+ */
222
+ function _matchIsInsideOtherMatch(start, end) {
223
+ for (var key in replacement_positions[CURRENT_LEVEL]) {
224
+ key = parseInt(key, 10);
225
+
226
+ // if this block completely overlaps with another block
227
+ // then we should remove the other block and return false
228
+ if (_hasCompleteOverlap(key, replacement_positions[CURRENT_LEVEL][key], start, end)) {
229
+ delete replacement_positions[CURRENT_LEVEL][key];
230
+ delete replacements[CURRENT_LEVEL][key];
231
+ }
232
+
233
+ if (_intersects(key, replacement_positions[CURRENT_LEVEL][key], start, end)) {
234
+ return true;
235
+ }
236
+ }
237
+
238
+ return false;
239
+ }
240
+
241
+ /**
242
+ * takes a string of code and wraps it in a span tag based on the name
243
+ *
244
+ * @param {string} name name of the pattern (ie keyword.regex)
245
+ * @param {string} code block of code to wrap
246
+ * @returns {string}
247
+ */
248
+ function _wrapCodeInSpan(name, code) {
249
+ return '<span class="' + name.replace(/\./g, ' ') + (global_class ? ' ' + global_class : '') + '">' + code + '</span>';
250
+ }
251
+
252
+ /**
253
+ * finds out the position of group match for a regular expression
254
+ *
255
+ * @see http://stackoverflow.com/questions/1985594/how-to-find-index-of-groups-in-match
256
+ *
257
+ * @param {Object} match
258
+ * @param {number} group_number
259
+ * @returns {number}
260
+ */
261
+ function _indexOfGroup(match, group_number) {
262
+ var index = 0,
263
+ i;
264
+
265
+ for (i = 1; i < group_number; ++i) {
266
+ if (match[i]) {
267
+ index += match[i].length;
268
+ }
269
+ }
270
+
271
+ return index;
272
+ }
273
+
274
+ /**
275
+ * matches a regex pattern against a block of code
276
+ * finds all matches that should be processed and stores the positions
277
+ * of where they should be replaced within the string
278
+ *
279
+ * this is where pretty much all the work is done but it should not
280
+ * be called directly
281
+ *
282
+ * @param {RegExp} pattern
283
+ * @param {string} code
284
+ * @returns void
285
+ */
286
+ function _processPattern(regex, pattern, code, callback)
287
+ {
288
+ var match = regex.exec(code);
289
+
290
+ if (!match) {
291
+ return callback();
292
+ }
293
+
294
+ ++match_counter;
295
+
296
+ // treat match 0 the same way as name
297
+ if (!pattern['name'] && typeof pattern['matches'][0] == 'string') {
298
+ pattern['name'] = pattern['matches'][0];
299
+ delete pattern['matches'][0];
300
+ }
301
+
302
+ var replacement = match[0],
303
+ start_pos = match.index,
304
+ end_pos = match[0].length + start_pos,
305
+
306
+ /**
307
+ * callback to process the next match of this pattern
308
+ */
309
+ processNext = function() {
310
+ var nextCall = function() {
311
+ _processPattern(regex, pattern, code, callback);
312
+ };
313
+
314
+ // every 100 items we process let's call set timeout
315
+ // to let the ui breathe a little
316
+ return match_counter % 100 > 0 ? nextCall() : setTimeout(nextCall, 0);
317
+ };
318
+
319
+ // if this is not a child match and it falls inside of another
320
+ // match that already happened we should skip it and continue processing
321
+ if (_matchIsInsideOtherMatch(start_pos, end_pos)) {
322
+ return processNext();
323
+ }
324
+
325
+ /**
326
+ * callback for when a match was successfully processed
327
+ *
328
+ * @param {string} replacement
329
+ * @returns void
330
+ */
331
+ var onMatchSuccess = function(replacement) {
332
+ // if this match has a name then wrap it in a span tag
333
+ if (pattern['name']) {
334
+ replacement = _wrapCodeInSpan(pattern['name'], replacement);
335
+ }
336
+
337
+ // console.log('LEVEL', CURRENT_LEVEL, 'replace', match[0], 'with', replacement, 'at position', start_pos, 'to', end_pos);
338
+
339
+ // store what needs to be replaced with what at this position
340
+ if (!replacements[CURRENT_LEVEL]) {
341
+ replacements[CURRENT_LEVEL] = {};
342
+ replacement_positions[CURRENT_LEVEL] = {};
343
+ }
344
+
345
+ replacements[CURRENT_LEVEL][start_pos] = {
346
+ 'replace': match[0],
347
+ 'with': replacement
348
+ };
349
+
350
+ // store the range of this match so we can use it for comparisons
351
+ // with other matches later
352
+ replacement_positions[CURRENT_LEVEL][start_pos] = end_pos;
353
+
354
+ // process the next match
355
+ processNext();
356
+ },
357
+
358
+ // if this pattern has sub matches for different groups in the regex
359
+ // then we should process them one at a time by rerunning them through
360
+ // this function to generate the new replacement
361
+ //
362
+ // we run through them backwards because the match position of earlier
363
+ // matches will not change depending on what gets replaced in later
364
+ // matches
365
+ group_keys = keys(pattern['matches']),
366
+
367
+ /**
368
+ * callback for processing a sub group
369
+ *
370
+ * @param {number} i
371
+ * @param {Array} group_keys
372
+ * @param {Function} callback
373
+ */
374
+ processGroup = function(i, group_keys, callback) {
375
+ if (i >= group_keys.length) {
376
+ return callback(replacement);
377
+ }
378
+
379
+ var processNextGroup = function() {
380
+ processGroup(++i, group_keys, callback);
381
+ },
382
+ block = match[group_keys[i]];
383
+
384
+ // if there is no match here then move on
385
+ if (!block) {
386
+ return processNextGroup();
387
+ }
388
+
389
+ var group = pattern['matches'][group_keys[i]],
390
+ language = group['language'],
391
+
392
+ /**
393
+ * process group is what group we should use to actually process
394
+ * this match group
395
+ *
396
+ * for example if the subgroup pattern looks like this
397
+ * 2: {
398
+ * 'name': 'keyword',
399
+ * 'pattern': /true/g
400
+ * }
401
+ *
402
+ * then we use that as is, but if it looks like this
403
+ *
404
+ * 2: {
405
+ * 'name': 'keyword',
406
+ * 'matches': {
407
+ * 'name': 'special',
408
+ * 'pattern': /whatever/g
409
+ * }
410
+ * }
411
+ *
412
+ * we treat the 'matches' part as the pattern and keep
413
+ * the name around to wrap it with later
414
+ */
415
+ process_group = group['name'] && group['matches'] ? group['matches'] : group,
416
+
417
+ /**
418
+ * takes the code block matched at this group, replaces it
419
+ * with the highlighted block, and optionally wraps it with
420
+ * a span with a name
421
+ *
422
+ * @param {string} block
423
+ * @param {string} replace_block
424
+ * @param {string|null} match_name
425
+ */
426
+ _replaceAndContinue = function(block, replace_block, match_name) {
427
+ replacement = _replaceAtPosition(_indexOfGroup(match, group_keys[i]), block, match_name ? _wrapCodeInSpan(match_name, replace_block) : replace_block, replacement);
428
+ processNextGroup();
429
+ };
430
+
431
+ // if this is a sublanguage go and process the block using that language
432
+ if (language) {
433
+ return _highlightBlockForLanguage(block, language, function(code) {
434
+ _replaceAndContinue(block, code);
435
+ });
436
+ }
437
+
438
+ // if this is a string then this match is directly mapped to selector
439
+ // so all we have to do is wrap it in a span and continue
440
+ if (typeof group === 'string') {
441
+ return _replaceAndContinue(block, block, group);
442
+ }
443
+
444
+ // the process group can be a single pattern or an array of patterns
445
+ // _processCodeWithPatterns always expects an array so we convert it here
446
+ _processCodeWithPatterns(block, process_group.length ? process_group : [process_group], function(code) {
447
+ _replaceAndContinue(block, code, group['matches'] ? group['name'] : 0);
448
+ });
449
+ };
450
+
451
+ processGroup(0, group_keys, onMatchSuccess);
452
+ }
453
+
454
+ /**
455
+ * should a language bypass the default patterns?
456
+ *
457
+ * if you call Rainbow.extend() and pass true as the third argument
458
+ * it will bypass the defaults
459
+ */
460
+ function _bypassDefaultPatterns(language)
461
+ {
462
+ return bypass_defaults[language];
463
+ }
464
+
465
+ /**
466
+ * returns a list of regex patterns for this language
467
+ *
468
+ * @param {string} language
469
+ * @returns {Array}
470
+ */
471
+ function _getPatternsForLanguage(language) {
472
+ var patterns = language_patterns[language] || [],
473
+ default_patterns = language_patterns[DEFAULT_LANGUAGE] || [];
474
+
475
+ return _bypassDefaultPatterns(language) ? patterns : patterns.concat(default_patterns);
476
+ }
477
+
478
+ /**
479
+ * substring replace call to replace part of a string at a certain position
480
+ *
481
+ * @param {number} position the position where the replacement should happen
482
+ * @param {string} replace the text we want to replace
483
+ * @param {string} replace_with the text we want to replace it with
484
+ * @param {string} code the code we are doing the replacing in
485
+ * @returns {string}
486
+ */
487
+ function _replaceAtPosition(position, replace, replace_with, code) {
488
+ var sub_string = code.substr(position);
489
+ return code.substr(0, position) + sub_string.replace(replace, replace_with);
490
+ }
491
+
492
+ /**
493
+ * sorts an object by index descending
494
+ *
495
+ * @param {Object} object
496
+ * @return {Array}
497
+ */
498
+ function keys(object) {
499
+ var locations = [],
500
+ replacement,
501
+ pos;
502
+
503
+ for(var location in object) {
504
+ if (object.hasOwnProperty(location)) {
505
+ locations.push(location);
506
+ }
507
+ }
508
+
509
+ // numeric descending
510
+ return locations.sort(function(a, b) {
511
+ return b - a;
512
+ });
513
+ }
514
+
515
+ /**
516
+ * processes a block of code using specified patterns
517
+ *
518
+ * @param {string} code
519
+ * @param {Array} patterns
520
+ * @returns void
521
+ */
522
+ function _processCodeWithPatterns(code, patterns, callback)
523
+ {
524
+ // we have to increase the level here so that the
525
+ // replacements will not conflict with each other when
526
+ // processing sub blocks of code
527
+ ++CURRENT_LEVEL;
528
+
529
+ // patterns are processed one at a time through this function
530
+ function _workOnPatterns(patterns, i)
531
+ {
532
+ // still have patterns to process, keep going
533
+ if (i < patterns.length) {
534
+ return _processPattern(patterns[i]['pattern'], patterns[i], code, function() {
535
+ _workOnPatterns(patterns, ++i);
536
+ });
537
+ }
538
+
539
+ // we are done processing the patterns
540
+ // process the replacements and update the DOM
541
+ _processReplacements(code, function(code) {
542
+
543
+ // when we are done processing replacements
544
+ // we are done at this level so we can go back down
545
+ delete replacements[CURRENT_LEVEL];
546
+ delete replacement_positions[CURRENT_LEVEL];
547
+ --CURRENT_LEVEL;
548
+ callback(code);
549
+ });
550
+ }
551
+
552
+ _workOnPatterns(patterns, 0);
553
+ }
554
+
555
+ /**
556
+ * process replacements in the string of code to actually update the markup
557
+ *
558
+ * @param {string} code the code to process replacements in
559
+ * @param {Function} onComplete what to do when we are done processing
560
+ * @returns void
561
+ */
562
+ function _processReplacements(code, onComplete) {
563
+
564
+ /**
565
+ * processes a single replacement
566
+ *
567
+ * @param {string} code
568
+ * @param {Array} positions
569
+ * @param {number} i
570
+ * @param {Function} onComplete
571
+ * @returns void
572
+ */
573
+ function _processReplacement(code, positions, i, onComplete) {
574
+ if (i < positions.length) {
575
+ ++replacement_counter;
576
+ var pos = positions[i],
577
+ replacement = replacements[CURRENT_LEVEL][pos];
578
+ code = _replaceAtPosition(pos, replacement['replace'], replacement['with'], code);
579
+
580
+ // process next function
581
+ var next = function() {
582
+ _processReplacement(code, positions, ++i, onComplete);
583
+ };
584
+
585
+ // use a timeout every 250 to not freeze up the UI
586
+ return replacement_counter % 250 > 0 ? next() : setTimeout(next, 0);
587
+ }
588
+
589
+ onComplete(code);
590
+ }
591
+
592
+ var string_positions = keys(replacements[CURRENT_LEVEL]);
593
+ _processReplacement(code, string_positions, 0, onComplete);
594
+ }
595
+
596
+ /**
597
+ * takes a string of code and highlights it according to the language specified
598
+ *
599
+ * @param {string} code
600
+ * @param {string} language
601
+ * @param {Function} onComplete
602
+ * @returns void
603
+ */
604
+ function _highlightBlockForLanguage(code, language, onComplete) {
605
+ var patterns = _getPatternsForLanguage(language);
606
+ _processCodeWithPatterns(_htmlEntities(code), patterns, onComplete);
607
+ }
608
+
609
+ /**
610
+ * highlight an individual code block
611
+ *
612
+ * @param {Array} code_blocks
613
+ * @param {number} i
614
+ * @returns void
615
+ */
616
+ function _highlightCodeBlock(code_blocks, i, onComplete) {
617
+ if (i < code_blocks.length) {
618
+ var block = code_blocks[i],
619
+ language = _getLanguageForBlock(block);
620
+
621
+ if (!_hasClass(block, 'rainbow') && language) {
622
+ language = language.toLowerCase();
623
+
624
+ _addClass(block, 'rainbow');
625
+
626
+ return _highlightBlockForLanguage(block.innerHTML, language, function(code) {
627
+ block.innerHTML = code;
628
+
629
+ // reset the replacement arrays
630
+ replacements = {};
631
+ replacement_positions = {};
632
+
633
+ // if you have a listener attached tell it that this block is now highlighted
634
+ if (onHighlight) {
635
+ onHighlight(block, language);
636
+ }
637
+
638
+ // process the next block
639
+ setTimeout(function() {
640
+ _highlightCodeBlock(code_blocks, ++i, onComplete);
641
+ }, 0);
642
+ });
643
+ }
644
+ return _highlightCodeBlock(code_blocks, ++i, onComplete);
645
+ }
646
+
647
+ if (onComplete) {
648
+ onComplete();
649
+ }
650
+ }
651
+
652
+ /**
653
+ * start highlighting all the code blocks
654
+ *
655
+ * @returns void
656
+ */
657
+ function _highlight(node, onComplete) {
658
+
659
+ // the first argument can be an Event or a DOM Element
660
+ // I was originally checking instanceof Event but that makes it break
661
+ // when using mootools
662
+ //
663
+ // @see https://github.com/ccampbell/rainbow/issues/32
664
+ //
665
+ node = node && typeof node.getElementsByTagName == 'function' ? node : document;
666
+
667
+ var pre_blocks = node.getElementsByTagName('pre'),
668
+ code_blocks = node.getElementsByTagName('code'),
669
+ i,
670
+ final_blocks = [];
671
+
672
+ // @see http://stackoverflow.com/questions/2735067/how-to-convert-a-dom-node-list-to-an-array-in-javascript
673
+ // we are going to process all <code> blocks
674
+ for (i = 0; i < code_blocks.length; ++i) {
675
+ final_blocks.push(code_blocks[i]);
676
+ }
677
+
678
+ // loop through the pre blocks to see which ones we should add
679
+ for (i = 0; i < pre_blocks.length; ++i) {
680
+
681
+ // if the pre block has no code blocks then process it directly
682
+ if (!pre_blocks[i].getElementsByTagName('code').length) {
683
+ final_blocks.push(pre_blocks[i]);
684
+ }
685
+ }
686
+
687
+ _highlightCodeBlock(final_blocks, 0, onComplete);
688
+ }
689
+
690
+ /**
691
+ * public methods
692
+ */
693
+ return {
694
+
695
+ /**
696
+ * extends the language pattern matches
697
+ *
698
+ * @param {*} language name of language
699
+ * @param {*} patterns array of patterns to add on
700
+ * @param {boolean|null} bypass if true this will bypass the default language patterns
701
+ */
702
+ extend: function(language, patterns, bypass) {
703
+
704
+ // if there is only one argument then we assume that we want to
705
+ // extend the default language rules
706
+ if (arguments.length == 1) {
707
+ patterns = language;
708
+ language = DEFAULT_LANGUAGE;
709
+ }
710
+
711
+ bypass_defaults[language] = bypass;
712
+ language_patterns[language] = patterns.concat(language_patterns[language] || []);
713
+ },
714
+
715
+ /**
716
+ * call back to let you do stuff in your app after a piece of code has been highlighted
717
+ *
718
+ * @param {Function} callback
719
+ */
720
+ onHighlight: function(callback) {
721
+ onHighlight = callback;
722
+ },
723
+
724
+ /**
725
+ * method to set a global class that will be applied to all spans
726
+ *
727
+ * @param {string} class_name
728
+ */
729
+ addClass: function(class_name) {
730
+ global_class = class_name;
731
+ },
732
+
733
+ /**
734
+ * starts the magic rainbow
735
+ *
736
+ * @returns void
737
+ */
738
+ color: function() {
739
+
740
+ // if you want to straight up highlight a string you can pass the string of code,
741
+ // the language, and a callback function
742
+ if (typeof arguments[0] == 'string') {
743
+ return _highlightBlockForLanguage(arguments[0], arguments[1], arguments[2]);
744
+ }
745
+
746
+ // if you pass a callback function then we rerun the color function
747
+ // on all the code and call the callback function on complete
748
+ if (typeof arguments[0] == 'function') {
749
+ return _highlight(0, arguments[0]);
750
+ }
751
+
752
+ // otherwise we use whatever node you passed in with an optional
753
+ // callback function as the second parameter
754
+ _highlight(arguments[0], arguments[1]);
755
+ }
756
+ };
757
+ }) ();
758
+
759
+ /**
760
+ * adds event listener to start highlighting
761
+ */
762
+ (function() {
763
+ if (window.addEventListener) {
764
+ return window.addEventListener('load', Rainbow.color, false);
765
+ }
766
+ window.attachEvent('onload', Rainbow.color);
767
+ }) ();
768
+
769
+ // When using Google closure compiler in advanced mode some methods
770
+ // get renamed. This keeps a public reference to these methods so they can
771
+ // still be referenced from outside this library.
772
+ Rainbow["onHighlight"] = Rainbow.onHighlight;
773
+ Rainbow["addClass"] = Rainbow.addClass;
774
+
775
+ /**
776
+ * HTML patterns
777
+ *
778
+ * @author Craig Campbell
779
+ * @version 1.0.7
780
+ */
781
+ Rainbow.extend('html', [
782
+ {
783
+ 'name': 'source.php.embedded',
784
+ 'matches': {
785
+ 2: {
786
+ 'language': 'php'
787
+ }
788
+ },
789
+ 'pattern': /&lt;\?=?(?!xml)(php)?([\s\S]*?)(\?&gt;)/gm
790
+ },
791
+ {
792
+ 'name': 'source.css.embedded',
793
+ 'matches': {
794
+ 0: {
795
+ 'language': 'css'
796
+ }
797
+ },
798
+ 'pattern': /&lt;style(.*?)&gt;([\s\S]*?)&lt;\/style&gt;/gm
799
+ },
800
+ {
801
+ 'name': 'source.js.embedded',
802
+ 'matches': {
803
+ 0: {
804
+ 'language': 'javascript'
805
+ }
806
+ },
807
+ 'pattern': /&lt;script(?! src)(.*?)&gt;([\s\S]*?)&lt;\/script&gt;/gm
808
+ },
809
+ {
810
+ 'name': 'comment.html',
811
+ 'pattern': /&lt;\!--[\S\s]*?--&gt;/g
812
+ },
813
+ {
814
+ 'matches': {
815
+ 1: 'support.tag.open',
816
+ 2: 'support.tag.close'
817
+ },
818
+ 'pattern': /(&lt;)|(\/?\??&gt;)/g
819
+ },
820
+ {
821
+ 'name': 'support.tag',
822
+ 'matches': {
823
+ 1: 'support.tag',
824
+ 2: 'support.tag.special',
825
+ 3: 'support.tag-name'
826
+ },
827
+ 'pattern': /(&lt;\??)(\/|\!?)(\w+)/g
828
+ },
829
+ {
830
+ 'matches': {
831
+ 1: 'support.attribute'
832
+ },
833
+ 'pattern': /([a-z-]+)(?=\=)/gi
834
+ },
835
+ {
836
+ 'matches': {
837
+ 1: 'support.operator',
838
+ 2: 'string.quote',
839
+ 3: 'string.value',
840
+ 4: 'string.quote'
841
+ },
842
+ 'pattern': /(=)('|")(.*?)(\2)/g
843
+ },
844
+ {
845
+ 'matches': {
846
+ 1: 'support.operator',
847
+ 2: 'support.value'
848
+ },
849
+ 'pattern': /(=)([a-zA-Z\-0-9]*)\b/g
850
+ },
851
+ {
852
+ 'matches': {
853
+ 1: 'support.attribute'
854
+ },
855
+ 'pattern': /\s(\w+)(?=\s|&gt;)(?![\s\S]*&lt;)/g
856
+ }
857
+ ], true);
858
+
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Blackboard theme
3
+ *
4
+ * Adapted from Domenico Carbotta's TextMate theme of the same name
5
+ *
6
+ * @author Domenico Carbotta
7
+ * @author Craig Campbell
8
+ * @version 1.0.2
9
+ */
10
+ pre {
11
+ background: #0B1022;
12
+ word-wrap: break-word;
13
+ margin: 0px;
14
+ padding: 0px;
15
+ padding: 10px;
16
+ color: #fff;
17
+ font-size: 14px;
18
+ margin-bottom: 20px;
19
+ }
20
+
21
+ pre, code {
22
+ font-family: 'Monaco', courier, monospace;
23
+ }
24
+
25
+ pre .comment {
26
+ color: #727272;
27
+ }
28
+
29
+ pre .constant {
30
+ color: #D8FA3C;
31
+ }
32
+
33
+ pre .storage {
34
+ color: #FBDE2D;
35
+ }
36
+
37
+ pre .string, pre .comment.docstring {
38
+ color: #61CE3C;
39
+ }
40
+
41
+ pre .string.regexp, pre .support.tag.script, pre .support.tag.style {
42
+ color: #fff;
43
+ }
44
+
45
+ pre .keyword, pre .selector {
46
+ color: #FBDE2D;
47
+ }
48
+
49
+ pre .inherited-class {
50
+ font-style: italic;
51
+ }
52
+
53
+ pre .entity {
54
+ color: #FF6400;
55
+ }
56
+
57
+ pre .support, *[data-language="c"] .function.call {
58
+ color: #8DA6CE;
59
+ }
60
+
61
+ pre .variable.global, pre .variable.class, pre .variable.instance {
62
+ color: #FF6400;
63
+ }
@@ -1,39 +1,8 @@
1
- /*----------------------------------------------------------------------------
2
- @group Global Reset
3
- ----------------------------------------------------------------------------*/
4
- * {
5
- padding:0;
6
- margin:0;
7
- }
8
- h1, h2, h3, h4, h5, h6, p, pre, blockquote, label, ul, ol, dl, fieldset, address { margin:1em 0; }
9
- li, dd { margin-left:5%; }
10
- fieldset { padding: .5em; }
11
- select option{ padding:0 5px; }
12
-
13
- .access{ display:none; } /* For accessibility related elements */
14
- .clear{ clear:both; height:0px; font-size:0px; line-height:0px; overflow:hidden; }
15
- a{ outline:none; }
16
- a img{ border:none; }
17
-
18
- .clearfix:after {
19
- content: ".";
20
- display: block;
21
- height: 0;
22
- clear: both;
23
- visibility: hidden;
1
+ .kss-body {
2
+ margin: 0;
24
3
  }
25
- * html .clearfix {height: 1%;}
26
- .clearfix {display:inline-block;}
27
- .clearfix {display: block;}
28
-
29
- /* @end */
30
4
 
31
- body{
32
- font-family:Helvetica, Arial, sans-serif;
33
- font-size:14px;
34
- }
35
-
36
- header{
5
+ .kss-header{
37
6
  padding:10px;
38
7
 
39
8
  font-size:16px;
@@ -43,24 +12,24 @@ header{
43
12
  border-bottom:1px solid #ddd;
44
13
  }
45
14
 
46
- #wrapper{
15
+ #kss_wrapper{
47
16
  padding-left:200px;
48
17
  padding-right: 25px;
49
18
  }
50
19
 
51
- nav[role=main]{
20
+ nav.kss-nav{
52
21
  float:left;
53
22
  margin-left:-200px;
54
23
  width:160px;
55
24
  }
56
- nav ul{
25
+ nav.kss-nav>ul{
57
26
  margin-left:10px;
58
27
  }
59
- nav li{
28
+ nav.kss-nav>ul>li{
60
29
  list-style-type:none;
61
30
  margin:10px 0;
62
31
  }
63
- nav li a{
32
+ nav.kss-nav>ul>li>a{
64
33
  text-decoration:none;
65
34
  color:#666;
66
35
  }
@@ -137,6 +106,4 @@ h1.styleguide {
137
106
  font-weight: normal;
138
107
  color: #222; }
139
108
 
140
- /* @end */
141
-
142
- //= require application
109
+ /* @end */
@@ -7,6 +7,11 @@ module Kss
7
7
  raise ArgumentError, "Missing block" unless block_given?
8
8
 
9
9
  @section = styleguide.section(section)
10
+
11
+ if !@section.raw
12
+ raise "KSS styleguide section is nil, is section '#{section}' defined in your css?"
13
+ end
14
+
10
15
  content = capture(&block)
11
16
  render 'kss/shared/styleguide_block', :section => @section, :example_html => content
12
17
  end
@@ -1,2 +1,2 @@
1
1
  <h1>Welcome!</h1>
2
- <p>This is an example <a href="/styleguide">styleguide</a>. To customize this page, create a file at <code>app/views/kss/home/index.html.erb</code>.</p>
2
+ <p>This is an example <a href="./styleguide">styleguide</a>. To customize this page, create a file at <code>app/views/kss/home/index.html.erb</code>.</p>
@@ -13,10 +13,12 @@
13
13
  <div class="styleguide-element">
14
14
  <%= example_html.html_safe %>
15
15
  </div>
16
+ <pre><code data-language="html"><%= example_html.strip %></code></pre>
16
17
  <% section.modifiers.each do |modifier| %>
17
18
  <div class="styleguide-element styleguide-modifier">
18
19
  <span class="styleguide-modifier-name"><%= modifier.name %></span>
19
20
  <%= example_html.gsub('$modifier_class', modifier.class_name).html_safe %>
20
21
  </div>
22
+ <pre><code data-language="html"><%= example_html.gsub('$modifier_class', modifier.class_name).strip %></code></pre>
21
23
  <% end %>
22
24
  </div>
@@ -1,17 +1,17 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
  Gem::Specification.new do |gem|
3
- gem.authors = ["Garrett Bjerkhoel"]
4
- gem.email = ["me@garrettbjerkhoel.com"]
3
+ gem.authors = ['Garrett Bjerkhoel']
4
+ gem.email = ['me@garrettbjerkhoel.com']
5
5
  gem.description = %q{Rails 3 engine to provide a living styleguide from Kyle Neath's KSS.}
6
6
  gem.summary = %q{Rails 3 engine to provide a living styleguide from Kyle Neath's KSS.}
7
- gem.homepage = "https://github.com/dewski/kss-rails"
7
+ gem.homepage = 'https://github.com/dewski/kss-rails'
8
8
 
9
9
  gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
10
10
  gem.files = `git ls-files`.split("\n")
11
11
  gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
12
- gem.name = "kss-rails"
13
- gem.require_paths = ["lib"]
14
- gem.version = '1.0.1'
12
+ gem.name = 'kss-rails'
13
+ gem.require_paths = ['lib']
14
+ gem.version = '1.0.2'
15
15
 
16
16
  gem.add_dependency 'kss'
17
17
  gem.add_dependency 'rails', '>= 3.0.0'
@@ -5,15 +5,16 @@
5
5
  <title>KSS Styleguide</title>
6
6
  <%= stylesheet_link_tag 'kss' %>
7
7
  <%= stylesheet_link_tag 'application' %>
8
+ <%= stylesheet_link_tag 'blackboard' %>
8
9
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
9
10
  </head>
10
- <body>
11
- <header>
11
+ <body class="kss-body">
12
+ <header class="kss-header">
12
13
  KSS Styleguide Example
13
14
  </header>
14
15
 
15
- <div id="wrapper">
16
- <nav role="main">
16
+ <div id="kss_wrapper">
17
+ <nav role="main" class="kss-nav">
17
18
  <ul>
18
19
  <li><%= link_to 'Home', kss.root_path %></li>
19
20
  <li><%= link_to 'Styleguide', kss.styleguide_path %></li>
@@ -24,5 +25,6 @@
24
25
  </div><!-- /#wrapper -->
25
26
 
26
27
  <%= javascript_include_tag 'kss' %>
28
+ <%= javascript_include_tag 'rainbow' %>
27
29
  </body>
28
30
  </html>
@@ -1,12 +1,3 @@
1
1
  <%= styleguide_block '1.1' do -%>
2
2
  <button class="$modifier_class">Example Button</button>
3
- <% end -%>
4
- <p>This block above was created with a simple template call:</p>
5
- <pre><code>&lt;%= styleguide_block &#x27;1.1&#x27; do %&gt;
6
- &lt;button class=&quot;$modifier_class&quot;&gt;Example Button&lt;/button&gt;
7
- &lt;% end %&gt;</code></pre>
8
- <p>
9
- Take a look at the source code of this Rails engine for more details. The goal
10
- is to remove the pain from creating a styleguide — document your CSS, have
11
- example HTML in your templates and automate as much as possible.
12
- </p>
3
+ <% end -%>
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kss-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-01-18 00:00:00.000000000Z
12
+ date: 2013-02-14 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: kss
16
- requirement: &70160073644480 !ruby/object:Gem::Requirement
16
+ requirement: !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,15 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70160073644480
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
25
30
  - !ruby/object:Gem::Dependency
26
31
  name: rails
27
- requirement: &70160073643780 !ruby/object:Gem::Requirement
32
+ requirement: !ruby/object:Gem::Requirement
28
33
  none: false
29
34
  requirements:
30
35
  - - ! '>='
@@ -32,7 +37,12 @@ dependencies:
32
37
  version: 3.0.0
33
38
  type: :runtime
34
39
  prerelease: false
35
- version_requirements: *70160073643780
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: 3.0.0
36
46
  description: Rails 3 engine to provide a living styleguide from Kyle Neath's KSS.
37
47
  email:
38
48
  - me@garrettbjerkhoel.com
@@ -47,6 +57,8 @@ files:
47
57
  - README.md
48
58
  - Rakefile
49
59
  - app/assets/javascripts/kss.coffee
60
+ - app/assets/javascripts/rainbow.js
61
+ - app/assets/stylesheets/blackboard.css
50
62
  - app/assets/stylesheets/kss.css.scss
51
63
  - app/controllers/kss/application_controller.rb
52
64
  - app/controllers/kss/home_controller.rb
@@ -81,7 +93,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
81
93
  version: '0'
82
94
  requirements: []
83
95
  rubyforge_project:
84
- rubygems_version: 1.8.10
96
+ rubygems_version: 1.8.23
85
97
  signing_key:
86
98
  specification_version: 3
87
99
  summary: Rails 3 engine to provide a living styleguide from Kyle Neath's KSS.