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.

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