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.

795 lines
20 KiB

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