You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

880 lines
22 KiB

11 years ago
  1. // namespace
  2. window.semantic = {
  3. handler: {}
  4. };
  5. // Allow for console.log to not break IE
  6. if (typeof window.console == "undefined" || typeof window.console.log == "undefined") {
  7. window.console = {
  8. log : function() {},
  9. info : function(){},
  10. warn : function(){}
  11. };
  12. }
  13. if(typeof window.console.group == 'undefined' || typeof window.console.groupEnd == 'undefined' || typeof window.console.groupCollapsed == 'undefined') {
  14. window.console.group = function(){};
  15. window.console.groupEnd = function(){};
  16. window.console.groupCollapsed = function(){};
  17. }
  18. if(typeof window.console.markTimeline == 'undefined') {
  19. window.console.markTimeline = function(){};
  20. }
  21. window.console.clear = function(){};
  22. // ready event
  23. semantic.ready = function() {
  24. // selector cache
  25. var
  26. $peek = $('.peek'),
  27. $peekItem = $peek.children('.menu').children('a.item'),
  28. $peekSubItem = $peek.find('.item .menu .item'),
  29. $sortableTables = $('.sortable.table'),
  30. $stuckColumn = $('.fixed.column > .image, .fixed.column > .content'),
  31. $themeDropdown = $('.theme.dropdown'),
  32. $ui = $('.ui').not('.hover, .down'),
  33. $swap = $('.theme.menu .item'),
  34. $menu = $('#menu'),
  35. $hideMenu = $('#menu .hide.item'),
  36. $sortTable = $('.sortable.table'),
  37. $demo = $('.demo'),
  38. $waypoints = $peek.closest('.tab, .container').find('h2').first().siblings('h2').addBack(),
  39. $menuPopup = $('.ui.main.menu .popup.item'),
  40. $menuDropdown = $('.ui.main.menu .dropdown'),
  41. $pageTabMenu = $('body > .tab.segment .tabular.menu'),
  42. $pageTabs = $('body > .tab.segment .menu .item'),
  43. $downloadDropdown = $('.download.buttons .dropdown'),
  44. $helpPopup = $('.header .help.icon'),
  45. $example = $('.example'),
  46. $shownExample = $example.filter('.shown'),
  47. $developer = $('.developer.item'),
  48. $overview = $('.overview.item, .overview.button'),
  49. $designer = $('.designer.item'),
  50. $sidebarButton = $('.attached.launch.button'),
  51. $increaseFont = $('.font .increase'),
  52. $decreaseFont = $('.font .decrease'),
  53. $code = $('div.code').not('.existing'),
  54. $existingCode = $('.existing.code'),
  55. // alias
  56. handler
  57. ;
  58. // event handlers
  59. handler = {
  60. createIcon: function() {
  61. $example
  62. .each(function(){
  63. $('<i/>')
  64. .addClass('icon code')
  65. .prependTo( $(this) )
  66. ;
  67. })
  68. ;
  69. },
  70. getSpecification: function(callback) {
  71. var
  72. url = $(this).data('url') || false
  73. ;
  74. callback = callback || function(){};
  75. if(url) {
  76. $.ajax({
  77. method: 'get',
  78. url: url,
  79. type: 'json',
  80. complete: callback
  81. });
  82. }
  83. },
  84. less: {
  85. parseFile: function(content) {
  86. var
  87. variables = {},
  88. lines = content.match(/^(@[\s|\S]+?;)/gm),
  89. name,
  90. value
  91. ;
  92. $.each(lines, function(index, line) {
  93. // clear whitespace
  94. line = $.trim(line);
  95. // match variables only
  96. if(line[0] == '@') {
  97. name = line.match(/^@(.+):/);
  98. value = line.match(/:\s*([\s|\S]+?;)/);
  99. if( ($.isArray(name) && name.length >= 2) && ($.isArray(value) && value.length >= 2) ) {
  100. name = name[1];
  101. value = value[1];
  102. variables[name] = value;
  103. }
  104. }
  105. });
  106. console.log(variables);
  107. return variables;
  108. },
  109. changeTheme: function(theme) {
  110. var
  111. variableURL = '/build/less/themes/packages/{$theme}/{$type}s/{$element}.variables',
  112. overrideURL = '/build/less/themes/packages/{$theme}/{$type}s/{$element}.overrides',
  113. urlData = {
  114. theme : typeof(theme === 'string')
  115. ? theme.toLowerCase()
  116. : theme,
  117. type : $themeDropdown.data('type'),
  118. element : $themeDropdown.data('element')
  119. }
  120. ;
  121. $themeDropdown
  122. .api({
  123. on : 'now',
  124. url : variableURL,
  125. dataType : 'text',
  126. urlData : urlData,
  127. success: function(content) {
  128. less.modifyVars( handler.less.parseFile(content) );
  129. $themeDropdown
  130. .api({
  131. on : 'now',
  132. url : overrideURL,
  133. dataType : 'text',
  134. urlData : urlData,
  135. success: function(content) {
  136. if( $('style.override').size() > 0 ) {
  137. $('style.override').remove();
  138. }
  139. $('<style>' + content + '</style>')
  140. .addClass('override')
  141. .appendTo('body')
  142. ;
  143. }
  144. })
  145. ;
  146. }
  147. })
  148. ;
  149. }
  150. },
  151. create: {
  152. examples: function(json) {
  153. var
  154. types = json['Types'],
  155. text = json['Text'],
  156. states = json['States'],
  157. variations = json['Variations'],
  158. $element,
  159. html
  160. ;
  161. $.each(types, function(name, type){
  162. html += '<h2 class="ui dividing header">' + name + '</h2';
  163. if($.isPlainObject(type)) {
  164. $.each(type, function(name, subType) {
  165. $element = $.zc(subType);
  166. $element = handler.create.text($element, text);
  167. html += '<h3 class="ui header">' + name + '</h3';
  168. html += handler.create.variations($element, variations);
  169. });
  170. }
  171. else {
  172. $element = $.zc(type);
  173. $element = handler.create.text($element);
  174. html += handler.create.variations($element, variations);
  175. }
  176. });
  177. // Each TYPE
  178. // show type name
  179. // html = koan (html)
  180. // each text
  181. // find label
  182. // if(obj)
  183. // replace random text
  184. // else
  185. // replace text
  186. // end
  187. // Each variation
  188. // (if obj)
  189. // each
  190. // add class
  191. // (else)
  192. // add class
  193. // label = property
  194. // class = class
  195. // show html
  196. // end
  197. // end
  198. },
  199. element: function(koan, type, text, variation) {
  200. },
  201. variations: function($element, variations) {
  202. $.each(variations, function(name, variation){
  203. });
  204. },
  205. text: function($element, text) {
  206. $.each(text, function(selector, text) {
  207. $element.find(selector).text(text);
  208. });
  209. return $element;
  210. }
  211. },
  212. font: {
  213. increase: function() {
  214. var
  215. $container = $(this).parent().prev('.ui.segment'),
  216. fontSize = parseInt( $container.css('font-size'), 10)
  217. ;
  218. $container
  219. .css('font-size', fontSize + 1)
  220. ;
  221. },
  222. decrease: function() {
  223. var
  224. $container = $(this).parent().prev('.ui.segment'),
  225. fontSize = parseInt( $container.css('font-size'), 10)
  226. ;
  227. $container
  228. .css('font-size', fontSize - 1)
  229. ;
  230. }
  231. },
  232. overviewMode: function() {
  233. var
  234. $button = $(this),
  235. $body = $('body'),
  236. $example = $('.example')
  237. ;
  238. $body.toggleClass('overview');
  239. $button.toggleClass('active');
  240. if($body.hasClass('overview')) {
  241. $developer.addClass('disabled').popup('destroy');
  242. $designer.addClass('disabled').popup('destroy');
  243. $example.each(function() {
  244. $(this).children().not('.ui.header:eq(0), .example p:eq(0), .annotation').hide();
  245. });
  246. $example.filter('.another').hide();
  247. }
  248. else {
  249. $developer.removeClass('disabled').popup();
  250. $designer.removeClass('disabled').popup();
  251. $example.each(function() {
  252. $(this).children().not('.ui.header:eq(0), .example p:eq(0), .annotation').show();
  253. });
  254. $example.filter('.another').show();
  255. }
  256. },
  257. developerMode: function() {
  258. var
  259. $example = $('.example').not('.no')
  260. ;
  261. $developer.addClass('active');
  262. $designer.removeClass('active');
  263. $example
  264. .each(function() {
  265. $.proxy(handler.createCode, $(this))('developer');
  266. })
  267. ;
  268. },
  269. designerMode: function() {
  270. var
  271. $example = $('.example').not('.no')
  272. ;
  273. $designer.addClass('active');
  274. $developer.removeClass('active');
  275. $example
  276. .each(function() {
  277. $.proxy(handler.createCode, $(this))('designer');
  278. })
  279. ;
  280. },
  281. getIndent: function(text) {
  282. var
  283. lines = text.split("\n"),
  284. firstLine = (lines[0] === '')
  285. ? lines[1]
  286. : lines[0],
  287. spacesPerIndent = 2,
  288. leadingSpaces = firstLine.length - firstLine.replace(/^\s*/g, '').length,
  289. indent
  290. ;
  291. if(leadingSpaces !== 0) {
  292. indent = leadingSpaces;
  293. }
  294. else {
  295. // string has already been trimmed, get first indented line and subtract 2
  296. $.each(lines, function(index, line) {
  297. leadingSpaces = line.length - line.replace(/^\s*/g, '').length;
  298. if(leadingSpaces !== 0) {
  299. indent = leadingSpaces - spacesPerIndent;
  300. return false;
  301. }
  302. });
  303. }
  304. return indent || 4;
  305. },
  306. generateCode: function() {
  307. var
  308. $example = $(this).closest('.example'),
  309. $annotation = $example.find('.annotation'),
  310. $code = $annotation.find('.code'),
  311. $header = $example.not('.another').children('.ui.header:first-of-type').eq(0).add('p:first-of-type'),
  312. $demo = $example.children().not($header).not('i.code:first-child, .code, .instructive, .language.label, .annotation, br, .ignore, .ignored'),
  313. code = ''
  314. ;
  315. if( $code.size() === 0) {
  316. $demo
  317. .each(function(){
  318. var $this = $(this).clone(false);
  319. if($this.not('br')) {
  320. code += $this.removeAttr('style').get(0).outerHTML + "\n";
  321. }
  322. })
  323. ;
  324. }
  325. $example.data('code', code);
  326. return code;
  327. },
  328. createCode: function(type) {
  329. var
  330. $example = $(this).closest('.example'),
  331. $header = $example.children('.ui.header:first-of-type').eq(0).add('p:first-of-type'),
  332. $annotation = $example.find('.annotation'),
  333. $code = $annotation.find('.code'),
  334. $demo = $example.children().not($header).not('i.code:first-child, .code, .instructive, .language.label, .annotation, br, .ignore, .ignored'),
  335. code = $example.data('code') || $.proxy(handler.generateCode, this)()
  336. ;
  337. if( $code.hasClass('existing') ) {
  338. $annotation.show();
  339. $code.removeClass('existing');
  340. $.proxy(handler.initializeCode, $code)();
  341. }
  342. if($annotation.size() === 0) {
  343. $annotation = $('<div/>')
  344. .addClass('annotation')
  345. .appendTo($example)
  346. ;
  347. }
  348. if( $example.find('.ace_editor').size() === 0) {
  349. $code = $('<div/>')
  350. .data('type', 'html')
  351. .addClass('code')
  352. .html(code)
  353. .hide()
  354. .appendTo($annotation)
  355. ;
  356. $.proxy(handler.initializeCode, $code)();
  357. }
  358. if( ($demo.first().is(':visible') || type == 'developer') && type != 'designer' ) {
  359. $demo.hide();
  360. $header.show();
  361. $annotation.fadeIn(500);
  362. }
  363. else {
  364. $annotation.hide();
  365. if($demo.size() > 1) {
  366. $demo.show();
  367. }
  368. else {
  369. $demo.fadeIn(500);
  370. }
  371. }
  372. },
  373. createAnnotation: function() {
  374. if(!$(this).data('type')) {
  375. $(this).data('type', 'html');
  376. }
  377. $(this)
  378. .wrap('<div class="annotation">')
  379. .parent()
  380. .hide()
  381. ;
  382. },
  383. resizeCode: function() {
  384. $('.ace_editor')
  385. .each(function() {
  386. var
  387. $code = $(this),
  388. padding = 20,
  389. editor,
  390. editorSession,
  391. codeHeight
  392. ;
  393. $code.css('height', 'auto');
  394. editor = ace.edit($code[0]);
  395. editorSession = editor.getSession();
  396. codeHeight = editorSession.getScreenLength() * editor.renderer.lineHeight + padding;
  397. $code.css('height', codeHeight);
  398. editor.resize();
  399. })
  400. ;
  401. },
  402. makeCode: function() {
  403. if(window.ace !== undefined) {
  404. $code
  405. .filter(':visible')
  406. .each(handler.initializeCode)
  407. ;
  408. $existingCode
  409. .each(handler.createAnnotation)
  410. ;
  411. }
  412. },
  413. makeStickyColumns: function() {
  414. var
  415. $visibleStuck = $(this).find('.fixed.column > .image, .fixed.column > .content'),
  416. isInitialized = ($visibleStuck.parent('.sticky-wrapper').size() !== 0)
  417. ;
  418. if(!isInitialized) {
  419. $visibleStuck
  420. .waypoint('sticky', {
  421. offset : 65,
  422. stuckClass : 'fixed'
  423. })
  424. ;
  425. }
  426. // apparently this doesnt refresh on first hit
  427. $.waypoints('refresh');
  428. $.waypoints('refresh');
  429. },
  430. initializeCode: function() {
  431. var
  432. $code = $(this).show(),
  433. code = $code.html(),
  434. existingCode = $code.hasClass('existing'),
  435. contentType = $code.data('type') || 'javascript',
  436. title = $code.data('title') || false,
  437. demo = $code.data('demo') || false,
  438. preview = $code.data('preview') || false,
  439. label = $code.data('label') || false,
  440. displayType = {
  441. html : 'HTML',
  442. javascript : 'Javascript',
  443. css : 'CSS',
  444. text : 'Command Line',
  445. sh : 'Command Line'
  446. },
  447. indent = handler.getIndent(code) || 4,
  448. padding = 20,
  449. whiteSpace,
  450. $label,
  451. editor,
  452. editorSession,
  453. codeHeight
  454. ;
  455. // trim whitespace
  456. whiteSpace = new RegExp('\\n\\s{' + indent + '}', 'g');
  457. code = $.trim(code).replace(whiteSpace, '\n');
  458. if(contentType == 'html') {
  459. $code.text(code);
  460. }
  461. else {
  462. $code.html(code);
  463. }
  464. // evaluate if specified
  465. if($code.hasClass('evaluated')) {
  466. eval(code);
  467. }
  468. // initialize
  469. editor = ace.edit($code[0]);
  470. editorSession = editor.getSession();
  471. editor.setTheme('ace/theme/github');
  472. editor.setShowPrintMargin(false);
  473. editor.setReadOnly(true);
  474. editor.renderer.setShowGutter(false);
  475. editor.setHighlightActiveLine(false);
  476. editorSession.setMode('ace/mode/'+ contentType);
  477. editorSession.setUseWrapMode(true);
  478. editorSession.setTabSize(2);
  479. editorSession.setUseSoftTabs(true);
  480. codeHeight = editorSession.getScreenLength() * editor.renderer.lineHeight + padding;
  481. $(this)
  482. .height(codeHeight + 'px')
  483. .wrap('<div class="ui instructive segment">')
  484. ;
  485. // add label
  486. if(title) {
  487. $('<div>')
  488. .addClass('ui attached top label')
  489. .html('<span class="title">' + title + '</span>' + '<em>' + (displayType[contentType] || contentType) + '</em>')
  490. .prependTo( $(this).parent() )
  491. ;
  492. }
  493. if(label) {
  494. $('<div>')
  495. .addClass('ui pointing below label')
  496. .html(displayType[contentType] || contentType)
  497. .insertBefore ( $(this).parent() )
  498. ;
  499. }
  500. // add run code button
  501. if(demo) {
  502. $('<a>')
  503. .addClass('ui pointing below black label')
  504. .html('Run Code')
  505. .on('click', function() {
  506. eval(code);
  507. })
  508. .insertBefore ( $(this).parent() )
  509. ;
  510. }
  511. // add preview if specified
  512. if(preview) {
  513. $(code)
  514. .insertAfter( $(this).parent() )
  515. ;
  516. }
  517. editor.resize();
  518. },
  519. movePeek: function() {
  520. if( $('.stuck .peek').size() > 0 ) {
  521. $('.peek')
  522. .toggleClass('pushed')
  523. ;
  524. }
  525. else {
  526. $('.peek')
  527. .removeClass('pushed')
  528. ;
  529. }
  530. },
  531. menu: {
  532. mouseenter: function() {
  533. $(this)
  534. .stop()
  535. .animate({
  536. width: '155px'
  537. }, 300, function() {
  538. $(this).find('.text').show();
  539. })
  540. ;
  541. },
  542. mouseleave: function(event) {
  543. $(this).find('.text').hide();
  544. $(this)
  545. .stop()
  546. .animate({
  547. width: '70px'
  548. }, 300)
  549. ;
  550. }
  551. },
  552. peek: function() {
  553. var
  554. $body = $('html, body'),
  555. $header = $(this),
  556. $menu = $header.parent(),
  557. $group = $menu.children(),
  558. $headers = $group.add( $group.find('.menu .item') ),
  559. $waypoint = $waypoints.eq( $group.index( $header ) ),
  560. offset
  561. ;
  562. offset = $waypoint.offset().top - 70;
  563. if(!$header.hasClass('active') ) {
  564. $menu
  565. .addClass('animating')
  566. ;
  567. $headers
  568. .removeClass('active')
  569. ;
  570. $body
  571. .stop()
  572. .one('scroll', function() {
  573. $body.stop();
  574. })
  575. .animate({
  576. scrollTop: offset
  577. }, 500)
  578. .promise()
  579. .done(function() {
  580. $menu
  581. .removeClass('animating')
  582. ;
  583. $headers
  584. .removeClass('active')
  585. ;
  586. $header
  587. .addClass('active')
  588. ;
  589. $waypoint
  590. .css('color', $header.css('border-right-color'))
  591. ;
  592. $waypoints
  593. .removeAttr('style')
  594. ;
  595. })
  596. ;
  597. }
  598. },
  599. peekSub: function() {
  600. var
  601. $body = $('html, body'),
  602. $subHeader = $(this),
  603. $header = $subHeader.parents('.item'),
  604. $menu = $header.parent(),
  605. $subHeaderGroup = $header.find('.item'),
  606. $headerGroup = $menu.children(),
  607. $waypoint = $('h2').eq( $headerGroup.index( $header ) ),
  608. $subWaypoint = $waypoint.nextAll('h3').eq( $subHeaderGroup.index($subHeader) ),
  609. offset = $subWaypoint.offset().top - 80
  610. ;
  611. $menu
  612. .addClass('animating')
  613. ;
  614. $headerGroup
  615. .removeClass('active')
  616. ;
  617. $subHeaderGroup
  618. .removeClass('active')
  619. ;
  620. $body
  621. .stop()
  622. .animate({
  623. scrollTop: offset
  624. }, 500, function() {
  625. $menu
  626. .removeClass('animating')
  627. ;
  628. $subHeader
  629. .addClass('active')
  630. ;
  631. })
  632. .one('scroll', function() {
  633. $body.stop();
  634. })
  635. ;
  636. },
  637. swapStyle: function() {
  638. var
  639. theme = $(this).data('theme')
  640. ;
  641. $(this)
  642. .addClass('active')
  643. .siblings()
  644. .removeClass('active')
  645. ;
  646. $('head link.ui')
  647. .each(function() {
  648. var
  649. href = $(this).attr('href'),
  650. subDirectory = href.split('/')[3],
  651. newLink = href.replace(subDirectory, theme)
  652. ;
  653. $(this)
  654. .attr('href', newLink)
  655. ;
  656. })
  657. ;
  658. }
  659. };
  660. $(window)
  661. .on('resize', function() {
  662. clearTimeout(handler.timer);
  663. handler.timer = setTimeout(handler.resizeCode, 100);
  664. })
  665. ;
  666. $downloadDropdown
  667. .dropdown({
  668. on : 'click',
  669. transition : 'scale'
  670. })
  671. ;
  672. // attach events
  673. if($.fn.tablesort !== undefined) {
  674. $sortTable
  675. .tablesort()
  676. ;
  677. }
  678. if( $pageTabs.size() > 0 ) {
  679. $pageTabs
  680. .tab({
  681. context : '.main.container',
  682. childrenOnly : true,
  683. history : true,
  684. onTabInit : handler.makeCode,
  685. onTabLoad : function() {
  686. $.proxy(handler.makeStickyColumns, this)();
  687. $peekItem.removeClass('active').first().addClass('active');
  688. }
  689. })
  690. ;
  691. }
  692. else {
  693. handler.makeCode();
  694. }
  695. handler.createIcon();
  696. $example
  697. .one('mousemove', handler.generateCode)
  698. .find('i.code')
  699. .on('click', handler.createCode)
  700. ;
  701. $themeDropdown
  702. .dropdown({
  703. action: 'select',
  704. onChange: handler.less.changeTheme
  705. })
  706. ;
  707. $shownExample
  708. .each(handler.createCode)
  709. ;
  710. $helpPopup
  711. .popup()
  712. ;
  713. $swap
  714. .on('click', handler.swapStyle)
  715. ;
  716. $increaseFont
  717. .on('click', handler.font.increase)
  718. ;
  719. $decreaseFont
  720. .on('click', handler.font.decrease)
  721. ;
  722. $developer
  723. .on('click', handler.developerMode)
  724. ;
  725. $designer
  726. .on('click', handler.designerMode)
  727. ;
  728. $overview
  729. .on('click', handler.overviewMode)
  730. ;
  731. $menuPopup
  732. .popup({
  733. position : 'bottom center',
  734. className: {
  735. popup: 'ui popup'
  736. }
  737. })
  738. ;
  739. $sortableTables
  740. .tablesort()
  741. ;
  742. $menuDropdown
  743. .dropdown({
  744. on : 'hover',
  745. action : 'nothing'
  746. })
  747. ;
  748. $sidebarButton
  749. .on('mouseenter', handler.menu.mouseenter)
  750. .on('mouseleave', handler.menu.mouseleave)
  751. ;
  752. $menu
  753. .sidebar('attach events', '.launch.button, .view-ui.button, .launch.item')
  754. .sidebar('attach events', $hideMenu, 'hide')
  755. ;
  756. $waypoints
  757. .waypoint({
  758. continuous : false,
  759. offset : 100,
  760. handler : function(direction) {
  761. var
  762. index = (direction == 'down')
  763. ? $waypoints.index(this)
  764. : ($waypoints.index(this) - 1 >= 0)
  765. ? ($waypoints.index(this) - 1)
  766. : 0
  767. ;
  768. $peekItem
  769. .removeClass('active')
  770. .eq( index )
  771. .addClass('active')
  772. ;
  773. }
  774. })
  775. ;
  776. /* $('body')
  777. .waypoint({
  778. handler: function(direction) {
  779. if(direction == 'down') {
  780. if( !$('body').is(':animated') ) {
  781. $peekItem
  782. .removeClass('active')
  783. .eq( $peekItem.size() - 1 )
  784. .addClass('active')
  785. ;
  786. }
  787. }
  788. },
  789. offset: 'bottom-in-view'
  790. })
  791. ;*/
  792. $peek
  793. .waypoint('sticky', {
  794. offset : 85,
  795. stuckClass : 'stuck'
  796. })
  797. ;
  798. $peekItem
  799. .on('click', handler.peek)
  800. ;
  801. $peekSubItem
  802. .on('click', handler.peekSub)
  803. ;
  804. };
  805. // attach ready event
  806. $(document)
  807. .ready(semantic.ready)
  808. ;