├── vendor ├── composer │ ├── installed.json │ ├── installed_dev.json │ ├── autoload_classmap.php │ ├── autoload_namespaces.php │ ├── autoload_real.php │ └── ClassLoader.php ├── autoload.php └── markdown │ ├── MarkdownInterface.inc.php │ ├── Michelf │ ├── MarkdownInterface.inc.php │ ├── Markdown.inc.php │ ├── MarkdownExtra.inc.php │ ├── MarkdownInterface.php │ └── MarkdownExtra.php │ ├── Markdown.inc.php │ ├── MarkdownExtra.inc.php │ ├── Readme.php │ ├── MarkdownInterface.php │ └── MarkdownExtra.php ├── app.php ├── single.php ├── layout.php ├── README.md ├── config.php ├── comment.php ├── index.php ├── views ├── layout.php ├── admin │ ├── edit.view.php │ ├── create.view.php │ └── dashboard.view.php ├── index.view.php └── single.view.php ├── static ├── markdown │ ├── css │ │ └── jquery.pagedown-bootstrap.css │ ├── README.md │ ├── less │ │ └── jquery.pagedown-bootstrap.less │ ├── LICENSE.txt │ ├── js │ │ ├── jquery.pagedown-bootstrap.js │ │ ├── Markdown.Sanitizer.js │ │ ├── jquery.pagedown-bootstrap.combined.min.js │ │ └── Markdown.Converter.js │ └── demo │ │ └── index.html ├── css │ ├── styles.css │ └── bootstrap-responsive.min.css └── js │ └── bootstrap.min.js ├── sftp-config.json ├── admin ├── auth.php └── index.php └── db.php /vendor/composer/installed.json: -------------------------------------------------------------------------------- 1 | [ 2 | ] -------------------------------------------------------------------------------- /vendor/composer/installed_dev.json: -------------------------------------------------------------------------------- 1 | [ 2 | ] -------------------------------------------------------------------------------- /vendor/autoload.php: -------------------------------------------------------------------------------- 1 | getById($_GET['id'],'posts'); 7 | if ($post == FALSE) { 8 | header('Location: index.php'); 9 | 10 | } else { 11 | 12 | $layout->view('single', array( 13 | 'article' => $post 14 | )); 15 | } 16 | -------------------------------------------------------------------------------- /layout.php: -------------------------------------------------------------------------------- 1 | 'duythien', 8 | 'password' => 'qazwsx2013@', 9 | 'dbname' => 'blog', 10 | //'cn' => sprintf('mongodb://%s:%d/%s', $hosts, $port,$database), 11 | 'connection_string'=> sprintf('mongodb://%s:%d/%s','127.0.0.1','27017','blog') 12 | ); 13 | -------------------------------------------------------------------------------- /vendor/markdown/Markdown.inc.php: -------------------------------------------------------------------------------- 1 | $_POST['fName'], 10 | 'email' => $_POST['fEmail'], 11 | 'comment' => $_POST['fComment'], 12 | 'posted_at' => new MongoDate() 13 | ); 14 | $status = $db->commentId($id,'posts',$comment); 15 | 16 | if ($status == TRUE) { 17 | header('Location: single.php?id='.$id); 18 | } 19 | 20 | 21 | } 22 | -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | get($currentPage,'posts'); 9 | 10 | 11 | $layout->view('index',array( 12 | 'currentPage' => $data[0], 13 | 'totalPages' => $data[1], 14 | 'cursor' => $data[2], 15 | 'name' => 'Duy Thien' 16 | 17 | )); 18 | 19 | 20 | } catch (Exception $e) { 21 | echo 'Caught exception: ', $e->getMessage(), "\n"; 22 | } 23 | -------------------------------------------------------------------------------- /views/layout.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Blog php and Mongo 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 |
17 | 18 | 19 | 20 |
21 |
22 | 23 | 24 | -------------------------------------------------------------------------------- /vendor/markdown/Readme.php: -------------------------------------------------------------------------------- 1 | 20 | 21 | 22 | 23 | PHP Markdown Lib - Readme 24 | 25 | 26 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /vendor/markdown/MarkdownInterface.php: -------------------------------------------------------------------------------- 1 | 8 | # 9 | # Original Markdown 10 | # Copyright (c) 2004-2006 John Gruber 11 | # 12 | # 13 | namespace Michelf; 14 | 15 | 16 | # 17 | # Markdown Parser Interface 18 | # 19 | 20 | interface MarkdownInterface { 21 | 22 | # 23 | # Initialize the parser and return the result of its transform method. 24 | # This will work fine for derived classes too. 25 | # 26 | public static function defaultTransform($text); 27 | 28 | # 29 | # Main function. Performs some preprocessing on the input text 30 | # and pass it through the document gamut. 31 | # 32 | public function transform($text); 33 | 34 | } 35 | 36 | 37 | ?> -------------------------------------------------------------------------------- /vendor/markdown/Michelf/MarkdownInterface.php: -------------------------------------------------------------------------------- 1 | 8 | # 9 | # Original Markdown 10 | # Copyright (c) 2004-2006 John Gruber 11 | # 12 | # 13 | namespace Michelf; 14 | 15 | 16 | # 17 | # Markdown Parser Interface 18 | # 19 | 20 | interface MarkdownInterface { 21 | 22 | # 23 | # Initialize the parser and return the result of its transform method. 24 | # This will work fine for derived classes too. 25 | # 26 | public static function defaultTransform($text); 27 | 28 | # 29 | # Main function. Performs some preprocessing on the input text 30 | # and pass it through the document gamut. 31 | # 32 | public function transform($text); 33 | 34 | } 35 | 36 | 37 | ?> -------------------------------------------------------------------------------- /static/markdown/css/jquery.pagedown-bootstrap.css: -------------------------------------------------------------------------------- 1 | .wmd-panel{width:100%;} 2 | .wmd-input{height:300px;width:100%;box-sizing:border-box;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;} 3 | .wmd-preview{width:100%;box-sizing:border-box;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;} 4 | .wmd-panel .btn-toolbar{margin-bottom:0;padding:0 0 5px;width:100%;} 5 | .fa-header:before{content:'H';font-family:arial,helvetica,sans-serif;font-weight:bold;} 6 | .wmd-prompt-background{background-color:Black;} 7 | .wmd-prompt-dialog{border:1px solid #999999;background-color:#F5F5F5;} 8 | .wmd-prompt-dialog>div{font-size:0.8em;font-family:arial,helvetica,sans-serif;} 9 | .wmd-prompt-dialog>form>input[type="text"]{border:1px solid #999999;color:black;} 10 | .wmd-prompt-dialog>form>input[type="button"]{border:1px solid #888888;font-family:trebuchet MS,helvetica,sans-serif;font-size:0.8em;font-weight:bold;} 11 | -------------------------------------------------------------------------------- /static/markdown/README.md: -------------------------------------------------------------------------------- 1 | # PageDown-Bootstrap 2 | 3 | A **jQuery** plugin that dynamically generates a **WYSIWYG** editor for **Markdown** with integrated **Twitter Bootstrap** styling. 4 | 5 | ## Requirements 6 | * [jQuery 1.9+](http://jquery.com) (you know you should be keeping it up to date) 7 | * [Twitter Bootstrap 3.0+](http://getbootstrap.com/) 8 | * [FontAwesome 4.0+](http://fontawesome.io/) 9 | 10 | ## Releases 11 | 12 | ```1.0``` - April 22, 2013 13 | * Initial release 14 | 15 | ```1.1``` - December 14, 2013 16 | * Moved to support Bootstrap 3.x 17 | * Changed to FontAwesome as the icon provider 18 | 19 | ## Demo & Documentation 20 | [http://kevin.oconnor.mp/pagedown-bootstrap](http://kevin.oconnor.mp/pagedown-bootstrap) 21 | 22 | ## Thanks 23 | * Editor and converter written by the [Pagedown](http://code.google.com/p/pagedown/) project. 24 | * [Sam Willis](https://github.com/samwillis/pagedown-bootstrap) for his original Bootstrap integration 25 | * New icons based on [GLYPHICONS](http://glyphicons.com), [Julian Leiss' mini glyphs](http://dribbble.com/shots/365544-Mini-glyphs-12-px-Free-PSD), and the origional icons of [http://code.google.com/p/pagedown/](Pagedown). 26 | -------------------------------------------------------------------------------- /vendor/markdown/MarkdownExtra.php: -------------------------------------------------------------------------------- 1 | 8 | # 9 | # Original Markdown 10 | # Copyright (c) 2004-2006 John Gruber 11 | # 12 | # 13 | namespace Michelf; 14 | 15 | 16 | # Just force Michelf/Markdown.php to load. This is needed to load 17 | # the temporary implementation class. See below for details. 18 | \Michelf\Markdown::MARKDOWNLIB_VERSION; 19 | 20 | # 21 | # Markdown Extra Parser Class 22 | # 23 | # Note: Currently the implementation resides in the temporary class 24 | # \Michelf\MarkdownExtra_TmpImpl (in the same file as \Michelf\Markdown). 25 | # This makes it easier to propagate the changes between the three different 26 | # packaging styles of PHP Markdown. Once this issue is resolved, the 27 | # _MarkdownExtra_TmpImpl will disappear and this one will contain the code. 28 | # 29 | 30 | class MarkdownExtra extends \Michelf\_MarkdownExtra_TmpImpl { 31 | 32 | ### Parser Implementation ### 33 | 34 | # Temporarily, the implemenation is in the _MarkdownExtra_TmpImpl class. 35 | # See note above. 36 | 37 | } 38 | 39 | -------------------------------------------------------------------------------- /vendor/markdown/Michelf/MarkdownExtra.php: -------------------------------------------------------------------------------- 1 | 8 | # 9 | # Original Markdown 10 | # Copyright (c) 2004-2006 John Gruber 11 | # 12 | # 13 | namespace Michelf; 14 | 15 | 16 | # Just force Michelf/Markdown.php to load. This is needed to load 17 | # the temporary implementation class. See below for details. 18 | \Michelf\Markdown::MARKDOWNLIB_VERSION; 19 | 20 | # 21 | # Markdown Extra Parser Class 22 | # 23 | # Note: Currently the implementation resides in the temporary class 24 | # \Michelf\MarkdownExtra_TmpImpl (in the same file as \Michelf\Markdown). 25 | # This makes it easier to propagate the changes between the three different 26 | # packaging styles of PHP Markdown. Once this issue is resolved, the 27 | # _MarkdownExtra_TmpImpl will disappear and this one will contain the code. 28 | # 29 | 30 | class MarkdownExtra extends \Michelf\_MarkdownExtra_TmpImpl { 31 | 32 | ### Parser Implementation ### 33 | 34 | # Temporarily, the implemenation is in the _MarkdownExtra_TmpImpl class. 35 | # See note above. 36 | 37 | } 38 | 39 | -------------------------------------------------------------------------------- /static/markdown/less/jquery.pagedown-bootstrap.less: -------------------------------------------------------------------------------- 1 | .wmd-panel { 2 | width: 100%; 3 | } 4 | 5 | .wmd-input { 6 | height: 300px; 7 | width: 100%; 8 | box-sizing: border-box; 9 | -webkit-box-sizing:border-box; 10 | -moz-box-sizing: border-box; 11 | -ms-box-sizing: border-box; 12 | } 13 | 14 | .wmd-preview { 15 | width: 100%; 16 | box-sizing: border-box; 17 | -webkit-box-sizing:border-box; 18 | -moz-box-sizing: border-box; 19 | -ms-box-sizing: border-box; 20 | } 21 | 22 | .wmd-panel .btn-toolbar { 23 | margin-bottom: 0; 24 | padding: 0 0 5px; 25 | width: 100%; 26 | } 27 | 28 | .fa-header:before { 29 | content: 'H'; 30 | font-family: arial, helvetica, sans-serif; 31 | font-weight: bold; 32 | } 33 | 34 | 35 | 36 | 37 | 38 | .wmd-prompt-background 39 | { 40 | background-color: Black; 41 | } 42 | 43 | .wmd-prompt-dialog 44 | { 45 | border: 1px solid #999999; 46 | background-color: #F5F5F5; 47 | } 48 | 49 | .wmd-prompt-dialog > div { 50 | font-size: 0.8em; 51 | font-family: arial, helvetica, sans-serif; 52 | } 53 | 54 | 55 | .wmd-prompt-dialog > form > input[type="text"] { 56 | border: 1px solid #999999; 57 | color: black; 58 | } 59 | 60 | .wmd-prompt-dialog > form > input[type="button"]{ 61 | border: 1px solid #888888; 62 | font-family: trebuchet MS, helvetica, sans-serif; 63 | font-size: 0.8em; 64 | font-weight: bold; 65 | } 66 | -------------------------------------------------------------------------------- /views/admin/edit.view.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 |
6 | '; 9 | echo ''; 10 | echo($data['status']); 11 | echo ' ← Go back'; 12 | echo '
'; 13 | } 14 | ?> 15 |

Edit Post

16 | 17 |
18 | 19 |
20 | 21 |
22 |
23 | 25 |
26 |
27 | 28 | 29 |
30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /vendor/composer/autoload_real.php: -------------------------------------------------------------------------------- 1 | $path) { 31 | $loader->set($namespace, $path); 32 | } 33 | 34 | $classMap = require __DIR__ . '/autoload_classmap.php'; 35 | if ($classMap) { 36 | $loader->addClassMap($classMap); 37 | } 38 | 39 | $loader->register(true); 40 | 41 | return $loader; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /sftp-config.json: -------------------------------------------------------------------------------- 1 | { 2 | // The tab key will cycle through the settings when first created 3 | // Visit http://wbond.net/sublime_packages/sftp/settings for help 4 | 5 | // sftp, ftp or ftps 6 | "type": "sftp", 7 | 8 | "save_before_upload": true, 9 | "upload_on_save": false, 10 | "sync_down_on_open": false, 11 | "sync_skip_deletes": false, 12 | "sync_same_age": true, 13 | "confirm_downloads": false, 14 | "confirm_sync": true, 15 | "confirm_overwrite_newer": false, 16 | 17 | "host": "phpmongodb-duythien.rhcloud.com", 18 | "user": "", 19 | //"password": "password", 20 | "port": "22", 21 | 22 | "remote_path": "/var/lib/openshift//app-root/runtime/repo/php", 23 | "ignore_regexes": [ 24 | "\\.sublime-(project|workspace)", "sftp-config(-alt\\d?)?\\.json", 25 | "sftp-settings\\.json", "/venv/", "\\.svn", "\\.hg", "\\.git", 26 | "\\.bzr", "_darcs", "CVS", "\\.DS_Store", "Thumbs\\.db", "desktop\\.ini" 27 | ], 28 | "file_permissions": "664", 29 | "dir_permissions": "775", 30 | 31 | //"extra_list_connections": 0, 32 | 33 | "connect_timeout": 30, 34 | //"keepalive": 120, 35 | //"ftp_passive_mode": true, 36 | "ssh_key_file": "~/.ssh/id_rsa", 37 | //"sftp_flags": ["-F", "/path/to/ssh_config"], 38 | 39 | //"preserve_modification_times": false, 40 | //"remote_time_offset_in_hours": 0, 41 | //"remote_encoding": "utf-8", 42 | //"remote_locale": "C", 43 | } 44 | -------------------------------------------------------------------------------- /views/index.view.php: -------------------------------------------------------------------------------- 1 |
2 | 3 | Duy Thien 4 | 5 |

Here are some articles I've written:

6 | 7 |
8 |
9 |
10 |
11 | hasNext()): 12 | $article = $cursor->getNext(); ?> 13 |

14 | sec); ?> post By 15 | 16 |

17 | Read more 18 | 19 |
20 |
21 |
22 | 23 |
24 |
25 |
    26 |
  • 27 | 28 | ← Older 29 | 30 | 31 |
  • 32 |
  • 33 | 34 |
  • 35 | 36 | Newer → 37 | 38 |
  • 39 |
40 |
41 |
42 | -------------------------------------------------------------------------------- /views/admin/create.view.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 |
6 | '; 9 | echo ''; 10 | echo($data['status']); 11 | echo ' ← Go back'; 12 | echo '
'; 13 | } 14 | ?> 15 |

Create A New Post

16 | 17 |
18 | 19 |
20 | 21 |
22 | 23 |

24 | 25 |
26 |
27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /static/markdown/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Pagedown Bootstrap 2 | ------------------- 3 | 4 | An extension of Pagedown which brings in Bootstrap and jQuery. Released 5 | under the MIT lciense (included below). 6 | 7 | Copyright (c) 2013 Kevin O'Connor 8 | 9 | 10 | Pagedown License 11 | ------------------- 12 | 13 | A javascript port of Markdown, as used on Stack Overflow 14 | and the rest of Stack Exchange network. 15 | 16 | Largely based on showdown.js by John Fraser (Attacklab). 17 | 18 | Original Markdown Copyright (c) 2004-2005 John Gruber 19 | 20 | 21 | 22 | Original Showdown code copyright (c) 2007 John Fraser 23 | 24 | Modifications and bugfixes (c) 2009 Dana Robinson 25 | Modifications and bugfixes (c) 2009-2011 Stack Exchange Inc. 26 | 27 | MIT License 28 | ------------------- 29 | 30 | Permission is hereby granted, free of charge, to any person obtaining a copy 31 | of this software and associated documentation files (the "Software"), to deal 32 | in the Software without restriction, including without limitation the rights 33 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 34 | copies of the Software, and to permit persons to whom the Software is 35 | furnished to do so, subject to the following conditions: 36 | 37 | The above copyright notice and this permission notice shall be included in 38 | all copies or substantial portions of the Software. 39 | 40 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 41 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 42 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 43 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 44 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 45 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 46 | THE SOFTWARE. 47 | 48 | -------------------------------------------------------------------------------- /views/single.view.php: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |
5 |
6 |



7 |

8 |

9 |
10 |
11 | 12 | 13 |
14 |
15 |
16 |
    17 |
18 |
19 |
20 |
21 |
22 |
23 | 24 |

Comments

25 | says... ';?> 27 |

28 | sec); ?>
29 | 31 | 32 |

Post your comment

33 |
34 |
35 | 36 |
37 |
38 | 39 |
40 | 41 |
42 | 43 |
44 | 45 |
46 |
47 |
48 | 49 |
-------------------------------------------------------------------------------- /admin/auth.php: -------------------------------------------------------------------------------- 1 | 2 | Try again

'; 16 | exit; 17 | } else { 18 | $user = isset($_SERVER['PHP_AUTH_USER']) ? $_SERVER['PHP_AUTH_USER'] : ''; 19 | $password = isset($_SERVER['PHP_AUTH_PW']) ? $_SERVER['PHP_AUTH_PW'] : ''; 20 | $result = $this->authenticate($user, $password); 21 | if ($result == 0) { 22 | $_SESSION['username'] = $user; 23 | } else { 24 | session_unset($_SESSION['login']); 25 | $this->errMes($result); 26 | echo '

Try again

'; 27 | exit; 28 | }; 29 | }; 30 | } 31 | } 32 | 33 | public function authenticate($user, $password) { 34 | 35 | if (($user == UserAuth)&&($password == PasswordAuth)){ 36 | return 0; 37 | }else{ 38 | return 1; 39 | } 40 | } 41 | 42 | public function errMes($errno) { 43 | switch ($errno) { 44 | case 0: 45 | break; 46 | case 1: 47 | echo 'The username or password you entered is incorrect'; 48 | break; 49 | default: 50 | echo 'Unknown error'; 51 | }; 52 | } 53 | 54 | public function logOut() { 55 | session_destroy(); 56 | if (isset($_SESSION['username'])) { 57 | session_unset($_SESSION['username']); 58 | echo "You've successfully logged out
"; 59 | } else { 60 | header("Location: ?action=logIn", TRUE, 301); 61 | }; 62 | if (isset($_SESSION['login'])) { session_unset($_SESSION['login']); }; 63 | exit; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /views/admin/dashboard.view.php: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Dashboard

4 | Create Post 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | hasNext()): 15 | $article = $cursor->getNext();?> 16 | 17 | 18 | 19 | 22 | 26 | 29 | 30 | 31 | 32 |
TitleSaved atConfirmed?
sec);?> 20 | View 21 | 23 | Edit 24 | 25 | 27 | Delete 28 |
33 |
34 | 35 | 36 |
37 |
38 |
    39 |
  • 40 | 41 | ← Older 42 | 43 | 44 |
  • 45 |
  • 46 | 47 |
  • 48 | 49 | Newer → 50 | 51 |
  • 52 |
53 |
54 |
55 | -------------------------------------------------------------------------------- /static/markdown/js/jquery.pagedown-bootstrap.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Pagedown Bootstrap 3 | * Author: Kevin O'Connor 4 | * Version: 1.0 5 | * 6 | * Copyright (c) 2013 Kevin O'Connor 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 9 | * associated documentation files (the "Software"), to deal in the Software without restriction, 10 | * including without limitation the rights to use, copy, modify, merge, publish, distribute, 11 | * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in all copies or 15 | * substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 18 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 20 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | * 23 | */ 24 | 25 | (function( $ ){ 26 | 27 | $.fn.pagedownBootstrap = function( options ) { 28 | 29 | // Default settings 30 | var settings = $.extend( { 31 | 'sanatize' : true, 32 | 'help' : null, 33 | 'hooks' : Array() 34 | }, options); 35 | 36 | return this.each(function() { 37 | 38 | //Setup converter 39 | var converter = null; 40 | if(settings.sanatize) 41 | { 42 | converter = Markdown.getSanitizingConverter(); 43 | } else { 44 | converter = new Markdown.Converter() 45 | } 46 | 47 | //Register hooks 48 | for(var i in settings.hooks) 49 | { 50 | var hook = settings.hooks[i]; 51 | if(typeof hook !== 'object' || typeof hook.event === 'underfined' 52 | || typeof hook.callback !== 'function') 53 | { 54 | //A bad hook object was given 55 | continue; 56 | } 57 | 58 | converter.hooks.chain(hook.event, hook.callback); 59 | 60 | } 61 | 62 | //Try to find a valid id for this element 63 | var id = "wmd-input"; 64 | var idAppend = 0; 65 | while($("#"+id+"-"+idAppend.toString()).length > 0) 66 | { 67 | idAppend++; 68 | } 69 | 70 | //Assign the choosen id to the element 71 | $(this).attr('id', id+"-"+idAppend.toString()); 72 | 73 | //Wrap the element with the needed html 74 | $(this).wrap('
'); 75 | $(this).before('
'); 76 | $(this).after('
'); 77 | $(this).addClass('wmd-input'); 78 | 79 | //Setup help function 80 | help = null; 81 | if($.isFunction(settings.help)) 82 | { 83 | help = { handler: settings.help }; 84 | } 85 | 86 | //Setup editor 87 | var editor = new Markdown.Editor(converter, "-"+idAppend.toString(), help); 88 | editor.run(); 89 | 90 | }); 91 | 92 | }; 93 | })( jQuery ); 94 | -------------------------------------------------------------------------------- /admin/index.php: -------------------------------------------------------------------------------- 1 | create('posts',$article); 40 | $data['status'] = 'Row has successfully been inserted.'; 41 | } 42 | } 43 | $layout->view('admin/create', $data); 44 | break; 45 | case 'edit': 46 | $id = $_REQUEST['id']; 47 | $data['status'] =null; 48 | 49 | if ($_SERVER['REQUEST_METHOD'] === 'POST' ) { 50 | 51 | $article = array(); 52 | $article['title'] = $_POST['title']; 53 | $article['html'] = Markdown::defaultTransform($_POST['content']); 54 | $article['content'] =$_POST['content']; 55 | $article['saved_at'] = new MongoDate(); 56 | 57 | if ( empty($article['title']) || empty($article['content']) ) { 58 | $data['status'] = 'Please fill out both inputs.'; 59 | }else { 60 | // then create a new row in the table 61 | $db->update($id,'posts',$article); 62 | $data['status'] = 'Row has successfully been update.'; 63 | } 64 | } 65 | $layout->view('admin/edit',array( 66 | 'article' => $db->getById($id,'posts'), 67 | 'status' => $data['status'] 68 | )); 69 | break; 70 | case 'delete': 71 | $id = $_GET['id']; 72 | $status = $db->delete($id,'posts'); 73 | if ($status ==TRUE ) { 74 | header("Location:index"); 75 | } 76 | break; 77 | default: 78 | $currentPage = (isset($_GET['page'])) ? (int) $_GET['page'] : 1; //current page number 79 | $data = $db->get($currentPage,'posts'); 80 | 81 | 82 | $layout->view('admin/dashboard',array( 83 | 'currentPage' => $data[0], 84 | 'totalPages' => $data[1], 85 | 'cursor' => $data[2], 86 | 87 | )); 88 | break; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /static/markdown/js/Markdown.Sanitizer.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | var output, Converter; 3 | if (typeof exports === "object" && typeof require === "function") { // we're in a CommonJS (e.g. Node.js) module 4 | output = exports; 5 | Converter = require("./Markdown.Converter").Converter; 6 | } else { 7 | output = window.Markdown; 8 | Converter = output.Converter; 9 | } 10 | 11 | output.getSanitizingConverter = function () { 12 | var converter = new Converter(); 13 | converter.hooks.chain("postConversion", sanitizeHtml); 14 | converter.hooks.chain("postConversion", balanceTags); 15 | return converter; 16 | } 17 | 18 | function sanitizeHtml(html) { 19 | return html.replace(/<[^>]*>?/gi, sanitizeTag); 20 | } 21 | 22 | // (tags that can be opened/closed) | (tags that stand alone) 23 | var basic_tag_whitelist = /^(<\/?(b|blockquote|code|del|dd|dl|dt|em|h1|h2|h3|i|kbd|li|ol|p|s|sup|sub|strong|strike|ul)>|<(br|hr)\s?\/?>)$/i; 24 | // | 25 | var a_white = /^(]+")?\s?>|<\/a>)$/i; 26 | 27 | // ]*")?(\stitle="[^"<>]*")?\s?\/?>)$/i; 29 | 30 | //
|
for twitter bootstrap 31 | var pre_white = /^(|<\/pre>)$/i; 32 | 33 | function sanitizeTag(tag) { 34 | if (tag.match(basic_tag_whitelist) || tag.match(a_white) || tag.match(img_white) || tag.match(pre_white)) 35 | return tag; 36 | else 37 | return ""; 38 | } 39 | 40 | /// 41 | /// attempt to balance HTML tags in the html string 42 | /// by removing any unmatched opening or closing tags 43 | /// IMPORTANT: we *assume* HTML has *already* been 44 | /// sanitized and is safe/sane before balancing! 45 | /// 46 | /// adapted from CODESNIPPET: A8591DBA-D1D3-11DE-947C-BA5556D89593 47 | /// 48 | function balanceTags(html) { 49 | 50 | if (html == "") 51 | return ""; 52 | 53 | var re = /<\/?\w+[^>]*(\s|$|>)/g; 54 | // convert everything to lower case; this makes 55 | // our case insensitive comparisons easier 56 | var tags = html.toLowerCase().match(re); 57 | 58 | // no HTML tags present? nothing to do; exit now 59 | var tagcount = (tags || []).length; 60 | if (tagcount == 0) 61 | return html; 62 | 63 | var tagname, tag; 64 | var ignoredtags = "



  • "; 65 | var match; 66 | var tagpaired = []; 67 | var tagremove = []; 68 | var needsRemoval = false; 69 | 70 | // loop through matched tags in forward order 71 | for (var ctag = 0; ctag < tagcount; ctag++) { 72 | tagname = tags[ctag].replace(/<\/?(\w+).*/, "$1"); 73 | // skip any already paired tags 74 | // and skip tags in our ignore list; assume they're self-closed 75 | if (tagpaired[ctag] || ignoredtags.search("<" + tagname + ">") > -1) 76 | continue; 77 | 78 | tag = tags[ctag]; 79 | match = -1; 80 | 81 | if (!/^<\//.test(tag)) { 82 | // this is an opening tag 83 | // search forwards (next tags), look for closing tags 84 | for (var ntag = ctag + 1; ntag < tagcount; ntag++) { 85 | if (!tagpaired[ntag] && tags[ntag] == "") { 86 | match = ntag; 87 | break; 88 | } 89 | } 90 | } 91 | 92 | if (match == -1) 93 | needsRemoval = tagremove[ctag] = true; // mark for removal 94 | else 95 | tagpaired[match] = true; // mark paired 96 | } 97 | 98 | if (!needsRemoval) 99 | return html; 100 | 101 | // delete all orphaned tags from the string 102 | 103 | var ctag = 0; 104 | html = html.replace(re, function (match) { 105 | var res = tagremove[ctag] ? "" : match; 106 | ctag++; 107 | return res; 108 | }); 109 | return html; 110 | } 111 | })(); 112 | -------------------------------------------------------------------------------- /db.php: -------------------------------------------------------------------------------- 1 | connect($config); 20 | } 21 | 22 | private function connect($config){ 23 | try{ 24 | if ( !class_exists('Mongo')){ 25 | echo ("The MongoDB PECL extension has not been installed or enabled"); 26 | return false; 27 | } 28 | $connection= new \MongoClient($config['connection_string'],array('username'=>$config['username'],'password'=>$config['password'])); 29 | return $this->db = $connection->selectDB($config['dbname']); 30 | }catch(Exception $e) { 31 | return false; 32 | } 33 | } 34 | /** 35 | * get one article by id 36 | * @return array 37 | */ 38 | public function getById($id,$collection){ 39 | // Convert strings of right length to MongoID 40 | if (strlen($id) == 24){ 41 | $id = new \MongoId($id); 42 | } 43 | $table = $this->db->selectCollection($collection); 44 | $cursor = $table->find(array('_id' => $id)); 45 | $article = $cursor->getNext(); 46 | 47 | if (!$article ){ 48 | return false ; 49 | } 50 | return $article; 51 | } 52 | /** 53 | * get all data in collection and paginator 54 | * 55 | * @return multi array 56 | */ 57 | public function get($page,$collection){ 58 | 59 | $currentPage = $page; 60 | $articlesPerPage = $this->limit; 61 | 62 | //number of article to skip from beginning 63 | $skip = ($currentPage - 1) * $articlesPerPage; 64 | 65 | $table = $this->db->selectCollection($collection); 66 | 67 | $cursor = $table->find(); 68 | //total number of articles in database 69 | $totalArticles = $cursor->count(); 70 | //total number of pages to display 71 | $totalPages = (int) ceil($totalArticles / $articlesPerPage); 72 | 73 | $cursor->sort(array('saved_at' => -1))->skip($skip)->limit($articlesPerPage); 74 | //$cursor = iterator_to_array($cursor); 75 | $data=array($currentPage,$totalPages,$cursor); 76 | 77 | return $data; 78 | } 79 | /** 80 | * Create article 81 | * @return boolean 82 | */ 83 | public function create($collection,$article){ 84 | 85 | $table = $this->db->selectCollection($collection); 86 | return $result = $table->insert($article); 87 | } 88 | /** 89 | * delete article via id 90 | * @return boolean 91 | */ 92 | public function delete($id,$collection){ 93 | // Convert strings of right length to MongoID 94 | if (strlen($id) == 24){ 95 | $id = new \MongoId($id); 96 | } 97 | $table = $this->db->selectCollection($collection); 98 | $result = $table->remove(array('_id'=>$id)); 99 | if (!$id){ 100 | return false; 101 | } 102 | return $result; 103 | 104 | } 105 | /** 106 | * Update article 107 | * @return boolean 108 | */ 109 | public function update($id,$collection,$article){ 110 | // Convert strings of right length to MongoID 111 | if (strlen($id) == 24){ 112 | $id = new \MongoId($id); 113 | } 114 | $table = $this->db->selectCollection($collection); 115 | $result = $table->update( 116 | array('_id' => new \MongoId($id)), 117 | array('$set' => $article) 118 | ); 119 | if (!$id){ 120 | return false; 121 | } 122 | return $result; 123 | 124 | } 125 | /** 126 | * create and update comment 127 | * @return boolean 128 | */ 129 | public function commentId($id,$collection,$comment){ 130 | 131 | $postCollection = $this->db->selectCollection($collection); 132 | $post = $postCollection->findOne(array('_id' => new \MongoId($id))); 133 | 134 | if (isset($post['comments'])) { 135 | $comments = $post['comments']; 136 | }else{ 137 | $comments = array(); 138 | } 139 | array_push($comments, $comment); 140 | 141 | return $postCollection->update( 142 | array('_id' => new \MongoId($id)), 143 | array('$set' => array('comments' => $comments)) 144 | ); 145 | } 146 | 147 | } 148 | -------------------------------------------------------------------------------- /static/css/styles.css: -------------------------------------------------------------------------------- 1 | body{ 2 | font-family : 'Ubuntu', sans-serif; 3 | font-weight:; 4 | /* background-color: #162029;; 5 | */ 6 | font-family: Verdana,Arial,Helvetica,SunSans-Regular,Sans-Serif; 7 | font-size: 12px; 8 | margin: 0; 9 | padding: 20px; 10 | 11 | } 12 | div.container{ 13 | background-color:#FFFFFF; 14 | } 15 | div.remember { 16 | margin-top: 7px; 17 | color: #969696; 18 | } 19 | 20 | div.remember label { 21 | padding-top: 15px; 22 | } 23 | 24 | div.forgot { 25 | margin-top: 7px; 26 | color: #dadada; 27 | } 28 | div.center { 29 | text-align: center; 30 | } 31 | footer { 32 | background: url("../img/feature-gradient.png") no-repeat scroll center 100% white; 33 | color: #B7B7B7; 34 | font-size: 12px; 35 | padding: 30px 0; 36 | margin-top: 95px; 37 | text-align: center; 38 | } 39 | 40 | footer a { 41 | margin-left: 10px; 42 | margin-right: 10px; 43 | } 44 | #footerAdmin { 45 | background: url("../img/feature-gradient.png") no-repeat scroll center 100% white; 46 | color: #B7B7B7; 47 | font-size: 12px; 48 | padding: 6px 0; 49 | text-align: center; 50 | } 51 | 52 | #footerAdmin a { 53 | margin-left: 10px; 54 | margin-right: 10px; 55 | } 56 | 57 | table.signup td { 58 | padding: 10px; 59 | } 60 | 61 | table.signup .alert { 62 | margin-bottom: 0; 63 | margin-top: 3px; 64 | } 65 | 66 | table.perms select { 67 | margin-top: 5px; 68 | margin-right: 10px; 69 | } 70 | 71 | table.perms label { 72 | margin-right: 10px; 73 | } 74 | 75 | div.main-container { 76 | min-height: 450px; 77 | } 78 | form#search-form{ 79 | height: 0px; 80 | margin: 6px 14px; 81 | } 82 | 83 | div.content p { 84 | 85 | font-size: 18px; 86 | line-height: 1.5em; 87 | color: #444; 88 | } 89 | a{ 90 | color: #444; 91 | } 92 | 93 | /*custom block code*/ 94 | abbr.initialism { 95 | font-size: 90%; 96 | text-transform: uppercase; 97 | } 98 | 99 | blockquote { 100 | background-color: rgba(102, 128, 153, 0.05); 101 | border-bottom-right-radius: 5px; 102 | border-left-width: 10px; 103 | border-top-right-radius: 5px; 104 | padding: 15px 20px; 105 | } 106 | blockquote p { 107 | font-size: 14px; 108 | line-height: 1.42857; 109 | margin-bottom: 15px; 110 | } 111 | blockquote p:last-child { 112 | margin-bottom: 0; 113 | } 114 | blockquote small { 115 | color: #999999; 116 | display: block; 117 | line-height: 1.42857; 118 | } 119 | blockquote small:before { 120 | content: "— "; 121 | } 122 | blockquote.pull-right { 123 | border-left: 0 none; 124 | border-right: 5px solid rgba(102, 128, 153, 0.075); 125 | padding-left: 0; 126 | padding-right: 15px; 127 | } 128 | blockquote.pull-right p, blockquote.pull-right small { 129 | text-align: right; 130 | } 131 | blockquote.pull-right small:before { 132 | content: ""; 133 | } 134 | blockquote.pull-right small:after { 135 | content: " —"; 136 | } 137 | q:before, q:after, blockquote:before, blockquote:after { 138 | content: ""; 139 | } 140 | address { 141 | display: block; 142 | font-style: normal; 143 | line-height: 1.42857; 144 | margin-bottom: 20px; 145 | } 146 | code, pre { 147 | font-family: Monaco,Menlo,Consolas,"Courier New",monospace; 148 | } 149 | code { 150 | background-color: rgba(102, 128, 153, 0.05); 151 | border-radius: 4px; 152 | color: #162029; 153 | font-size: 90%; 154 | padding: 2px 4px; 155 | white-space: nowrap; 156 | } 157 | pre { 158 | background-color: rgba(102, 128, 153, 0.05); 159 | border: 1px solid #DEE6ED; 160 | border-radius: 4px; 161 | color: #333333; 162 | display: block; 163 | font-size: 13px; 164 | line-height: 1.42857; 165 | margin: 0 0 10px; 166 | padding: 9.5px; 167 | word-break: break-all; 168 | word-wrap: break-word; 169 | } 170 | pre.prettyprint { 171 | margin-bottom: 20px; 172 | } 173 | pre code { 174 | background-color: rgba(0, 0, 0, 0); 175 | border: 0 none; 176 | color: inherit; 177 | font-size: inherit; 178 | padding: 0; 179 | white-space: pre-wrap; 180 | } 181 | p { 182 | margin-bottom: 0; 183 | } 184 | 185 | 186 | form textarea, form input { 187 | border-color: #999999 #CCCCCC #CFCFCF #CFCFCF; 188 | border-style: solid; 189 | border-width: 1px; 190 | box-shadow: -2px 1px 2px 2px rgba(0, 0, 0, 0.1) inset; 191 | width: 250px; 192 | } 193 | #post-admin { 194 | margin-top: 70px; 195 | } 196 | .blog-image img { 197 | border-radius: 50%; 198 | margin-left: 437px; 199 | margin-top: 66px; 200 | } 201 | .blog-image{ 202 | padding-bottom: 12px; 203 | } -------------------------------------------------------------------------------- /static/markdown/demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | PageDown-Bootstrap 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 20 | 21 | 22 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 |
    34 | 35 |
    36 |

    PageDown-Bootstrap

    37 |

    38 | An extension of Pagedown to neatly integrate into Twitter Bootstrap for a WYSIWYG Markdown editor. This project is a fork of the work of Sam Willis. 39 |

    40 |

    41 | This project is hosted on GitHub where issues can be reported. It is released under the MIT License. 42 |

    43 |

    44 | 45 | Fork on GitHub 46 | 47 |

    48 |
    49 | 50 |
    51 |

    Requirements

    52 | 57 | 58 |
    59 | 60 |

    Basic usage

    61 | 62 | 63 |
    64 | 65 |

    Options

    66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 95 | 96 | 97 |
    NameTypeDefaultOptions/Description
    sanatizebooleantruetrue or false, enables or disables sanatization of HTML
    helpfunctionnullA function to be called when the help button it clicked. Null precludes the rendering of the help button.
    hooksarray[] 93 | An array of objects that define hooks for the converter. Each object should define a string, 'event', and a function, 'callback'. A full list of events can be found here. 94 |
    98 | 99 |
    100 | 101 |

    Styling

    102 |

    103 | All of the created elements are wrapped in nice helpful HTML tags as defined: 104 |

    105 |
    106 |
    div.wmd-panel
    107 |
    A wrapper around all of the elements of the textarea, button bar, and preview
    108 |
    div.wmd-button-bar
    109 |
    A wrapper that contains the editor's button bar.
    110 |
    textarea.wmd-input
    111 |
    The textarea that has been transformed into an editor
    112 |
    div.wmd-preview
    113 |
    A wrapper for the preview generated by the editor
    114 |
    115 | 116 |
    117 | 118 |

    Demo

    119 | 120 |

    1. This is the basic editor

    121 | 129 |

    Code:

    130 | 131 | 132 |
    133 | 134 |

    2. This is a custom editor

    135 | 136 | 152 |

    Code:

    153 | 154 |
    155 | 156 | 184 | 185 | 186 | -------------------------------------------------------------------------------- /vendor/composer/ClassLoader.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Autoload; 14 | 15 | /** 16 | * ClassLoader implements a PSR-0 class loader 17 | * 18 | * See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md 19 | * 20 | * $loader = new \Composer\Autoload\ClassLoader(); 21 | * 22 | * // register classes with namespaces 23 | * $loader->add('Symfony\Component', __DIR__.'/component'); 24 | * $loader->add('Symfony', __DIR__.'/framework'); 25 | * 26 | * // activate the autoloader 27 | * $loader->register(); 28 | * 29 | * // to enable searching the include path (eg. for PEAR packages) 30 | * $loader->setUseIncludePath(true); 31 | * 32 | * In this example, if you try to use a class in the Symfony\Component 33 | * namespace or one of its children (Symfony\Component\Console for instance), 34 | * the autoloader will first look for the class under the component/ 35 | * directory, and it will then fallback to the framework/ directory if not 36 | * found before giving up. 37 | * 38 | * This class is loosely based on the Symfony UniversalClassLoader. 39 | * 40 | * @author Fabien Potencier 41 | * @author Jordi Boggiano 42 | */ 43 | class ClassLoader 44 | { 45 | private $prefixes = array(); 46 | private $fallbackDirs = array(); 47 | private $useIncludePath = false; 48 | private $classMap = array(); 49 | 50 | public function getPrefixes() 51 | { 52 | return call_user_func_array('array_merge', $this->prefixes); 53 | } 54 | 55 | public function getFallbackDirs() 56 | { 57 | return $this->fallbackDirs; 58 | } 59 | 60 | public function getClassMap() 61 | { 62 | return $this->classMap; 63 | } 64 | 65 | /** 66 | * @param array $classMap Class to filename map 67 | */ 68 | public function addClassMap(array $classMap) 69 | { 70 | if ($this->classMap) { 71 | $this->classMap = array_merge($this->classMap, $classMap); 72 | } else { 73 | $this->classMap = $classMap; 74 | } 75 | } 76 | 77 | /** 78 | * Registers a set of classes, merging with any others previously set. 79 | * 80 | * @param string $prefix The classes prefix 81 | * @param array|string $paths The location(s) of the classes 82 | * @param bool $prepend Prepend the location(s) 83 | */ 84 | public function add($prefix, $paths, $prepend = false) 85 | { 86 | if (!$prefix) { 87 | if ($prepend) { 88 | $this->fallbackDirs = array_merge( 89 | (array) $paths, 90 | $this->fallbackDirs 91 | ); 92 | } else { 93 | $this->fallbackDirs = array_merge( 94 | $this->fallbackDirs, 95 | (array) $paths 96 | ); 97 | } 98 | 99 | return; 100 | } 101 | 102 | $first = $prefix[0]; 103 | if (!isset($this->prefixes[$first][$prefix])) { 104 | $this->prefixes[$first][$prefix] = (array) $paths; 105 | 106 | return; 107 | } 108 | if ($prepend) { 109 | $this->prefixes[$first][$prefix] = array_merge( 110 | (array) $paths, 111 | $this->prefixes[$first][$prefix] 112 | ); 113 | } else { 114 | $this->prefixes[$first][$prefix] = array_merge( 115 | $this->prefixes[$first][$prefix], 116 | (array) $paths 117 | ); 118 | } 119 | } 120 | 121 | /** 122 | * Registers a set of classes, replacing any others previously set. 123 | * 124 | * @param string $prefix The classes prefix 125 | * @param array|string $paths The location(s) of the classes 126 | */ 127 | public function set($prefix, $paths) 128 | { 129 | if (!$prefix) { 130 | $this->fallbackDirs = (array) $paths; 131 | 132 | return; 133 | } 134 | $this->prefixes[substr($prefix, 0, 1)][$prefix] = (array) $paths; 135 | } 136 | 137 | /** 138 | * Turns on searching the include path for class files. 139 | * 140 | * @param bool $useIncludePath 141 | */ 142 | public function setUseIncludePath($useIncludePath) 143 | { 144 | $this->useIncludePath = $useIncludePath; 145 | } 146 | 147 | /** 148 | * Can be used to check if the autoloader uses the include path to check 149 | * for classes. 150 | * 151 | * @return bool 152 | */ 153 | public function getUseIncludePath() 154 | { 155 | return $this->useIncludePath; 156 | } 157 | 158 | /** 159 | * Registers this instance as an autoloader. 160 | * 161 | * @param bool $prepend Whether to prepend the autoloader or not 162 | */ 163 | public function register($prepend = false) 164 | { 165 | spl_autoload_register(array($this, 'loadClass'), true, $prepend); 166 | } 167 | 168 | /** 169 | * Unregisters this instance as an autoloader. 170 | */ 171 | public function unregister() 172 | { 173 | spl_autoload_unregister(array($this, 'loadClass')); 174 | } 175 | 176 | /** 177 | * Loads the given class or interface. 178 | * 179 | * @param string $class The name of the class 180 | * @return bool|null True if loaded, null otherwise 181 | */ 182 | public function loadClass($class) 183 | { 184 | if ($file = $this->findFile($class)) { 185 | include $file; 186 | 187 | return true; 188 | } 189 | } 190 | 191 | /** 192 | * Finds the path to the file where the class is defined. 193 | * 194 | * @param string $class The name of the class 195 | * 196 | * @return string|false The path if found, false otherwise 197 | */ 198 | public function findFile($class) 199 | { 200 | // work around for PHP 5.3.0 - 5.3.2 https://bugs.php.net/50731 201 | if ('\\' == $class[0]) { 202 | $class = substr($class, 1); 203 | } 204 | 205 | if (isset($this->classMap[$class])) { 206 | return $this->classMap[$class]; 207 | } 208 | 209 | if (false !== $pos = strrpos($class, '\\')) { 210 | // namespaced class name 211 | $classPath = strtr(substr($class, 0, $pos), '\\', DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR; 212 | $className = substr($class, $pos + 1); 213 | } else { 214 | // PEAR-like class name 215 | $classPath = null; 216 | $className = $class; 217 | } 218 | 219 | $classPath .= strtr($className, '_', DIRECTORY_SEPARATOR) . '.php'; 220 | 221 | $first = $class[0]; 222 | if (isset($this->prefixes[$first])) { 223 | foreach ($this->prefixes[$first] as $prefix => $dirs) { 224 | if (0 === strpos($class, $prefix)) { 225 | foreach ($dirs as $dir) { 226 | if (file_exists($dir . DIRECTORY_SEPARATOR . $classPath)) { 227 | return $dir . DIRECTORY_SEPARATOR . $classPath; 228 | } 229 | } 230 | } 231 | } 232 | } 233 | 234 | foreach ($this->fallbackDirs as $dir) { 235 | if (file_exists($dir . DIRECTORY_SEPARATOR . $classPath)) { 236 | return $dir . DIRECTORY_SEPARATOR . $classPath; 237 | } 238 | } 239 | 240 | if ($this->useIncludePath && $file = stream_resolve_include_path($classPath)) { 241 | return $file; 242 | } 243 | 244 | return $this->classMap[$class] = false; 245 | } 246 | } 247 | -------------------------------------------------------------------------------- /static/css/bootstrap-responsive.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Responsive v2.3.2 3 | * 4 | * Copyright 2013 Twitter, Inc 5 | * Licensed under the Apache License v2.0 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Designed and built with all the love in the world by @mdo and @fat. 9 | */.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;line-height:0;content:""}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}@-ms-viewport{width:device-width}.hidden{display:none;visibility:hidden}.visible-phone{display:none!important}.visible-tablet{display:none!important}.hidden-desktop{display:none!important}.visible-desktop{display:inherit!important}@media(min-width:768px) and (max-width:979px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-tablet{display:inherit!important}.hidden-tablet{display:none!important}}@media(max-width:767px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-phone{display:inherit!important}.hidden-phone{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:inherit!important}.hidden-print{display:none!important}}@media(min-width:1200px){.row{margin-left:-30px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:30px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:1170px}.span12{width:1170px}.span11{width:1070px}.span10{width:970px}.span9{width:870px}.span8{width:770px}.span7{width:670px}.span6{width:570px}.span5{width:470px}.span4{width:370px}.span3{width:270px}.span2{width:170px}.span1{width:70px}.offset12{margin-left:1230px}.offset11{margin-left:1130px}.offset10{margin-left:1030px}.offset9{margin-left:930px}.offset8{margin-left:830px}.offset7{margin-left:730px}.offset6{margin-left:630px}.offset5{margin-left:530px}.offset4{margin-left:430px}.offset3{margin-left:330px}.offset2{margin-left:230px}.offset1{margin-left:130px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.564102564102564%;*margin-left:2.5109110747408616%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.564102564102564%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.45299145299145%;*width:91.39979996362975%}.row-fluid .span10{width:82.90598290598291%;*width:82.8527914166212%}.row-fluid .span9{width:74.35897435897436%;*width:74.30578286961266%}.row-fluid .span8{width:65.81196581196582%;*width:65.75877432260411%}.row-fluid .span7{width:57.26495726495726%;*width:57.21176577559556%}.row-fluid .span6{width:48.717948717948715%;*width:48.664757228587014%}.row-fluid .span5{width:40.17094017094017%;*width:40.11774868157847%}.row-fluid .span4{width:31.623931623931625%;*width:31.570740134569924%}.row-fluid .span3{width:23.076923076923077%;*width:23.023731587561375%}.row-fluid .span2{width:14.52991452991453%;*width:14.476723040552828%}.row-fluid .span1{width:5.982905982905983%;*width:5.929714493544281%}.row-fluid .offset12{margin-left:105.12820512820512%;*margin-left:105.02182214948171%}.row-fluid .offset12:first-child{margin-left:102.56410256410257%;*margin-left:102.45771958537915%}.row-fluid .offset11{margin-left:96.58119658119658%;*margin-left:96.47481360247316%}.row-fluid .offset11:first-child{margin-left:94.01709401709402%;*margin-left:93.91071103837061%}.row-fluid .offset10{margin-left:88.03418803418803%;*margin-left:87.92780505546462%}.row-fluid .offset10:first-child{margin-left:85.47008547008548%;*margin-left:85.36370249136206%}.row-fluid .offset9{margin-left:79.48717948717949%;*margin-left:79.38079650845607%}.row-fluid .offset9:first-child{margin-left:76.92307692307693%;*margin-left:76.81669394435352%}.row-fluid .offset8{margin-left:70.94017094017094%;*margin-left:70.83378796144753%}.row-fluid .offset8:first-child{margin-left:68.37606837606839%;*margin-left:68.26968539734497%}.row-fluid .offset7{margin-left:62.393162393162385%;*margin-left:62.28677941443899%}.row-fluid .offset7:first-child{margin-left:59.82905982905982%;*margin-left:59.72267685033642%}.row-fluid .offset6{margin-left:53.84615384615384%;*margin-left:53.739770867430444%}.row-fluid .offset6:first-child{margin-left:51.28205128205128%;*margin-left:51.175668303327875%}.row-fluid .offset5{margin-left:45.299145299145295%;*margin-left:45.1927623204219%}.row-fluid .offset5:first-child{margin-left:42.73504273504273%;*margin-left:42.62865975631933%}.row-fluid .offset4{margin-left:36.75213675213675%;*margin-left:36.645753773413354%}.row-fluid .offset4:first-child{margin-left:34.18803418803419%;*margin-left:34.081651209310785%}.row-fluid .offset3{margin-left:28.205128205128204%;*margin-left:28.0987452264048%}.row-fluid .offset3:first-child{margin-left:25.641025641025642%;*margin-left:25.53464266230224%}.row-fluid .offset2{margin-left:19.65811965811966%;*margin-left:19.551736679396257%}.row-fluid .offset2:first-child{margin-left:17.094017094017094%;*margin-left:16.98763411529369%}.row-fluid .offset1{margin-left:11.11111111111111%;*margin-left:11.004728132387708%}.row-fluid .offset1:first-child{margin-left:8.547008547008547%;*margin-left:8.440625568285142%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:30px}input.span12,textarea.span12,.uneditable-input.span12{width:1156px}input.span11,textarea.span11,.uneditable-input.span11{width:1056px}input.span10,textarea.span10,.uneditable-input.span10{width:956px}input.span9,textarea.span9,.uneditable-input.span9{width:856px}input.span8,textarea.span8,.uneditable-input.span8{width:756px}input.span7,textarea.span7,.uneditable-input.span7{width:656px}input.span6,textarea.span6,.uneditable-input.span6{width:556px}input.span5,textarea.span5,.uneditable-input.span5{width:456px}input.span4,textarea.span4,.uneditable-input.span4{width:356px}input.span3,textarea.span3,.uneditable-input.span3{width:256px}input.span2,textarea.span2,.uneditable-input.span2{width:156px}input.span1,textarea.span1,.uneditable-input.span1{width:56px}.thumbnails{margin-left:-30px}.thumbnails>li{margin-left:30px}.row-fluid .thumbnails{margin-left:0}}@media(min-width:768px) and (max-width:979px){.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:20px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:724px}.span12{width:724px}.span11{width:662px}.span10{width:600px}.span9{width:538px}.span8{width:476px}.span7{width:414px}.span6{width:352px}.span5{width:290px}.span4{width:228px}.span3{width:166px}.span2{width:104px}.span1{width:42px}.offset12{margin-left:764px}.offset11{margin-left:702px}.offset10{margin-left:640px}.offset9{margin-left:578px}.offset8{margin-left:516px}.offset7{margin-left:454px}.offset6{margin-left:392px}.offset5{margin-left:330px}.offset4{margin-left:268px}.offset3{margin-left:206px}.offset2{margin-left:144px}.offset1{margin-left:82px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.7624309392265194%;*margin-left:2.709239449864817%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.7624309392265194%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.43646408839778%;*width:91.38327259903608%}.row-fluid .span10{width:82.87292817679558%;*width:82.81973668743387%}.row-fluid .span9{width:74.30939226519337%;*width:74.25620077583166%}.row-fluid .span8{width:65.74585635359117%;*width:65.69266486422946%}.row-fluid .span7{width:57.18232044198895%;*width:57.12912895262725%}.row-fluid .span6{width:48.61878453038674%;*width:48.56559304102504%}.row-fluid .span5{width:40.05524861878453%;*width:40.00205712942283%}.row-fluid .span4{width:31.491712707182323%;*width:31.43852121782062%}.row-fluid .span3{width:22.92817679558011%;*width:22.87498530621841%}.row-fluid .span2{width:14.3646408839779%;*width:14.311449394616199%}.row-fluid .span1{width:5.801104972375691%;*width:5.747913483013988%}.row-fluid .offset12{margin-left:105.52486187845304%;*margin-left:105.41847889972962%}.row-fluid .offset12:first-child{margin-left:102.76243093922652%;*margin-left:102.6560479605031%}.row-fluid .offset11{margin-left:96.96132596685082%;*margin-left:96.8549429881274%}.row-fluid .offset11:first-child{margin-left:94.1988950276243%;*margin-left:94.09251204890089%}.row-fluid .offset10{margin-left:88.39779005524862%;*margin-left:88.2914070765252%}.row-fluid .offset10:first-child{margin-left:85.6353591160221%;*margin-left:85.52897613729868%}.row-fluid .offset9{margin-left:79.8342541436464%;*margin-left:79.72787116492299%}.row-fluid .offset9:first-child{margin-left:77.07182320441989%;*margin-left:76.96544022569647%}.row-fluid .offset8{margin-left:71.2707182320442%;*margin-left:71.16433525332079%}.row-fluid .offset8:first-child{margin-left:68.50828729281768%;*margin-left:68.40190431409427%}.row-fluid .offset7{margin-left:62.70718232044199%;*margin-left:62.600799341718584%}.row-fluid .offset7:first-child{margin-left:59.94475138121547%;*margin-left:59.838368402492065%}.row-fluid .offset6{margin-left:54.14364640883978%;*margin-left:54.037263430116376%}.row-fluid .offset6:first-child{margin-left:51.38121546961326%;*margin-left:51.27483249088986%}.row-fluid .offset5{margin-left:45.58011049723757%;*margin-left:45.47372751851417%}.row-fluid .offset5:first-child{margin-left:42.81767955801105%;*margin-left:42.71129657928765%}.row-fluid .offset4{margin-left:37.01657458563536%;*margin-left:36.91019160691196%}.row-fluid .offset4:first-child{margin-left:34.25414364640884%;*margin-left:34.14776066768544%}.row-fluid .offset3{margin-left:28.45303867403315%;*margin-left:28.346655695309746%}.row-fluid .offset3:first-child{margin-left:25.69060773480663%;*margin-left:25.584224756083227%}.row-fluid .offset2{margin-left:19.88950276243094%;*margin-left:19.783119783707537%}.row-fluid .offset2:first-child{margin-left:17.12707182320442%;*margin-left:17.02068884448102%}.row-fluid .offset1{margin-left:11.32596685082873%;*margin-left:11.219583872105325%}.row-fluid .offset1:first-child{margin-left:8.56353591160221%;*margin-left:8.457152932878806%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:20px}input.span12,textarea.span12,.uneditable-input.span12{width:710px}input.span11,textarea.span11,.uneditable-input.span11{width:648px}input.span10,textarea.span10,.uneditable-input.span10{width:586px}input.span9,textarea.span9,.uneditable-input.span9{width:524px}input.span8,textarea.span8,.uneditable-input.span8{width:462px}input.span7,textarea.span7,.uneditable-input.span7{width:400px}input.span6,textarea.span6,.uneditable-input.span6{width:338px}input.span5,textarea.span5,.uneditable-input.span5{width:276px}input.span4,textarea.span4,.uneditable-input.span4{width:214px}input.span3,textarea.span3,.uneditable-input.span3{width:152px}input.span2,textarea.span2,.uneditable-input.span2{width:90px}input.span1,textarea.span1,.uneditable-input.span1{width:28px}}@media(max-width:767px){body{padding-right:20px;padding-left:20px}.navbar-fixed-top,.navbar-fixed-bottom,.navbar-static-top{margin-right:-20px;margin-left:-20px}.container-fluid{padding:0}.dl-horizontal dt{float:none;width:auto;clear:none;text-align:left}.dl-horizontal dd{margin-left:0}.container{width:auto}.row-fluid{width:100%}.row,.thumbnails{margin-left:0}.thumbnails>li{float:none;margin-left:0}[class*="span"],.uneditable-input[class*="span"],.row-fluid [class*="span"]{display:block;float:none;width:100%;margin-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.span12,.row-fluid .span12{width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="offset"]:first-child{margin-left:0}.input-large,.input-xlarge,.input-xxlarge,input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.input-prepend input,.input-append input,.input-prepend input[class*="span"],.input-append input[class*="span"]{display:inline-block;width:auto}.controls-row [class*="span"]+[class*="span"]{margin-left:0}.modal{position:fixed;top:20px;right:20px;left:20px;width:auto;margin:0}.modal.fade{top:-100px}.modal.fade.in{top:20px}}@media(max-width:480px){.nav-collapse{-webkit-transform:translate3d(0,0,0)}.page-header h1 small{display:block;line-height:20px}input[type="checkbox"],input[type="radio"]{border:1px solid #ccc}.form-horizontal .control-label{float:none;width:auto;padding-top:0;text-align:left}.form-horizontal .controls{margin-left:0}.form-horizontal .control-list{padding-top:0}.form-horizontal .form-actions{padding-right:10px;padding-left:10px}.media .pull-left,.media .pull-right{display:block;float:none;margin-bottom:10px}.media-object{margin-right:0;margin-left:0}.modal{top:10px;right:10px;left:10px}.modal-header .close{padding:10px;margin:-10px}.carousel-caption{position:static}}@media(max-width:979px){body{padding-top:0}.navbar-fixed-top,.navbar-fixed-bottom{position:static}.navbar-fixed-top{margin-bottom:20px}.navbar-fixed-bottom{margin-top:20px}.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding:5px}.navbar .container{width:auto;padding:0}.navbar .brand{padding-right:10px;padding-left:10px;margin:0 0 0 -5px}.nav-collapse{clear:both}.nav-collapse .nav{float:none;margin:0 0 10px}.nav-collapse .nav>li{float:none}.nav-collapse .nav>li>a{margin-bottom:2px}.nav-collapse .nav>.divider-vertical{display:none}.nav-collapse .nav .nav-header{color:#777;text-shadow:none}.nav-collapse .nav>li>a,.nav-collapse .dropdown-menu a{padding:9px 15px;font-weight:bold;color:#777;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.nav-collapse .btn{padding:4px 10px 4px;font-weight:normal;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.nav-collapse .dropdown-menu li+li a{margin-bottom:2px}.nav-collapse .nav>li>a:hover,.nav-collapse .nav>li>a:focus,.nav-collapse .dropdown-menu a:hover,.nav-collapse .dropdown-menu a:focus{background-color:#f2f2f2}.navbar-inverse .nav-collapse .nav>li>a,.navbar-inverse .nav-collapse .dropdown-menu a{color:#999}.navbar-inverse .nav-collapse .nav>li>a:hover,.navbar-inverse .nav-collapse .nav>li>a:focus,.navbar-inverse .nav-collapse .dropdown-menu a:hover,.navbar-inverse .nav-collapse .dropdown-menu a:focus{background-color:#111}.nav-collapse.in .btn-group{padding:0;margin-top:5px}.nav-collapse .dropdown-menu{position:static;top:auto;left:auto;display:none;float:none;max-width:none;padding:0;margin:0 15px;background-color:transparent;border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.nav-collapse .open>.dropdown-menu{display:block}.nav-collapse .dropdown-menu:before,.nav-collapse .dropdown-menu:after{display:none}.nav-collapse .dropdown-menu .divider{display:none}.nav-collapse .nav>li>.dropdown-menu:before,.nav-collapse .nav>li>.dropdown-menu:after{display:none}.nav-collapse .navbar-form,.nav-collapse .navbar-search{float:none;padding:10px 15px;margin:10px 0;border-top:1px solid #f2f2f2;border-bottom:1px solid #f2f2f2;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1)}.navbar-inverse .nav-collapse .navbar-form,.navbar-inverse .nav-collapse .navbar-search{border-top-color:#111;border-bottom-color:#111}.navbar .nav-collapse .nav.pull-right{float:none;margin-left:0}.nav-collapse,.nav-collapse.collapse{height:0;overflow:hidden}.navbar .btn-navbar{display:block}.navbar-static .navbar-inner{padding-right:10px;padding-left:10px}}@media(min-width:980px){.nav-collapse.collapse{height:auto!important;overflow:visible!important}} 10 | -------------------------------------------------------------------------------- /static/js/bootstrap.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bootstrap.js by @fat & @mdo 3 | * plugins: bootstrap-transition.js, bootstrap-modal.js, bootstrap-dropdown.js, bootstrap-scrollspy.js, bootstrap-tab.js, bootstrap-tooltip.js, bootstrap-popover.js, bootstrap-affix.js, bootstrap-alert.js, bootstrap-button.js, bootstrap-collapse.js, bootstrap-carousel.js, bootstrap-typeahead.js 4 | * Copyright 2012 Twitter, Inc. 5 | * http://www.apache.org/licenses/LICENSE-2.0.txt 6 | */ 7 | !function(a){a(function(){a.support.transition=function(){var a=function(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"},c;for(c in b)if(a.style[c]!==undefined)return b[c]}();return a&&{end:a}}()})}(window.jQuery),!function(a){var b=function(b,c){this.options=c,this.$element=a(b).delegate('[data-dismiss="modal"]',"click.dismiss.modal",a.proxy(this.hide,this)),this.options.remote&&this.$element.find(".modal-body").load(this.options.remote)};b.prototype={constructor:b,toggle:function(){return this[this.isShown?"hide":"show"]()},show:function(){var b=this,c=a.Event("show");this.$element.trigger(c);if(this.isShown||c.isDefaultPrevented())return;this.isShown=!0,this.escape(),this.backdrop(function(){var c=a.support.transition&&b.$element.hasClass("fade");b.$element.parent().length||b.$element.appendTo(document.body),b.$element.show(),c&&b.$element[0].offsetWidth,b.$element.addClass("in").attr("aria-hidden",!1),b.enforceFocus(),c?b.$element.one(a.support.transition.end,function(){b.$element.focus().trigger("shown")}):b.$element.focus().trigger("shown")})},hide:function(b){b&&b.preventDefault();var c=this;b=a.Event("hide"),this.$element.trigger(b);if(!this.isShown||b.isDefaultPrevented())return;this.isShown=!1,this.escape(),a(document).off("focusin.modal"),this.$element.removeClass("in").attr("aria-hidden",!0),a.support.transition&&this.$element.hasClass("fade")?this.hideWithTransition():this.hideModal()},enforceFocus:function(){var b=this;a(document).on("focusin.modal",function(a){b.$element[0]!==a.target&&!b.$element.has(a.target).length&&b.$element.focus()})},escape:function(){var a=this;this.isShown&&this.options.keyboard?this.$element.on("keyup.dismiss.modal",function(b){b.which==27&&a.hide()}):this.isShown||this.$element.off("keyup.dismiss.modal")},hideWithTransition:function(){var b=this,c=setTimeout(function(){b.$element.off(a.support.transition.end),b.hideModal()},500);this.$element.one(a.support.transition.end,function(){clearTimeout(c),b.hideModal()})},hideModal:function(){var a=this;this.$element.hide(),this.backdrop(function(){a.removeBackdrop(),a.$element.trigger("hidden")})},removeBackdrop:function(){this.$backdrop&&this.$backdrop.remove(),this.$backdrop=null},backdrop:function(b){var c=this,d=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var e=a.support.transition&&d;this.$backdrop=a('
  • ',minLength:1},a.fn.typeahead.Constructor=b,a.fn.typeahead.noConflict=function(){return a.fn.typeahead=c,this},a(document).on("focus.typeahead.data-api",'[data-provide="typeahead"]',function(b){var c=a(this);if(c.data("typeahead"))return;c.typeahead(c.data())})}(window.jQuery) -------------------------------------------------------------------------------- /static/markdown/js/jquery.pagedown-bootstrap.combined.min.js: -------------------------------------------------------------------------------- 1 | var Markdown;if(typeof exports==="object"&&typeof require==="function"){Markdown=exports}else{Markdown={}}(function(){function c(e){return e}function d(e){return false}function b(){}b.prototype={chain:function(g,f){var e=this[g];if(!e){throw new Error("unknown hook "+g)}if(e===c){this[g]=f}else{this[g]=function(h){return f(e(h))}}},set:function(f,e){if(!this[f]){throw new Error("unknown hook "+f)}this[f]=e},addNoop:function(e){this[e]=c},addFalse:function(e){this[e]=d}};Markdown.HookCollection=b;function a(){}a.prototype={set:function(e,f){this["s_"+e]=f},get:function(e){return this["s_"+e]}};Markdown.Converter=function(){var j=this.hooks=new b();j.addNoop("plainLinkText");j.addNoop("preConversion");j.addNoop("postConversion");var w;var n;var e;var z;this.makeHtml=function(P){if(w){throw new Error("Recursive call to converter.makeHtml")}w=new a();n=new a();e=[];z=0;P=j.preConversion(P);P=P.replace(/~/g,"~T");P=P.replace(/\$/g,"~D");P=P.replace(/\r\n/g,"\n");P=P.replace(/\r/g,"\n");P="\n\n"+P+"\n\n";P=J(P);P=P.replace(/^[ \t]+$/mg,"");P=o(P);P=m(P);P=f(P);P=M(P);P=P.replace(/~D/g,"$$");P=P.replace(/~T/g,"~");P=j.postConversion(P);e=n=w=null;return P};function m(P){P=P.replace(/^[ ]{0,3}\[(.+)\]:[ \t]*\n?[ \t]*?(?=\s|$)[ \t]*\n?[ \t]*((\n*)["(](.+?)[")][ \t]*)?(?:\n+)/gm,function(S,U,T,R,Q,V){U=U.toLowerCase();w.set(U,C(T));if(Q){return R}else{if(V){n.set(U,V.replace(/"/g,"""))}}return""});return P}function o(R){var Q="p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del";var P="p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math";R=R.replace(/^(<(p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del)\b[^\r]*?\n<\/\2>[ \t]*(?=\n+))/gm,O);R=R.replace(/^(<(p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math)\b[^\r]*?.*<\/\2>[ \t]*(?=\n+)\n)/gm,O);R=R.replace(/\n[ ]{0,3}((<(hr)\b([^<>])*?\/?>)[ \t]*(?=\n{2,}))/g,O);R=R.replace(/\n\n[ ]{0,3}(-]|-[^>])(?:[^-]|-[^-])*)--)>[ \t]*(?=\n{2,}))/g,O);R=R.replace(/(?:\n\n)([ ]{0,3}(?:<([?%])[^\r]*?\2>)[ \t]*(?=\n{2,}))/g,O);return R}function O(P,Q){var R=Q;R=R.replace(/^\n+/,"");R=R.replace(/\n+$/g,"");R="\n\n~K"+(e.push(R)-1)+"K\n\n";return R}function f(R,Q){R=i(R);var P="
    \n";R=R.replace(/^[ ]{0,2}([ ]?\*[ ]?){3,}[ \t]*$/gm,P);R=R.replace(/^[ ]{0,2}([ ]?-[ ]?){3,}[ \t]*$/gm,P);R=R.replace(/^[ ]{0,2}([ ]?_[ ]?){3,}[ \t]*$/gm,P);R=L(R);R=q(R);R=g(R);R=o(R);R=I(R,Q);return R}function k(P){P=r(P);P=v(P);P=H(P);P=D(P);P=E(P);P=K(P);P=P.replace(/~P/g,"://");P=C(P);P=x(P);P=P.replace(/ +\n/g,"
    \n");return P}function v(Q){var P=/(<[a-z\/!$]("[^"]*"|'[^']*'|[^'">])*>|-]|-[^>])(?:[^-]|-[^-])*)--)>)/gi;Q=Q.replace(P,function(S){var R=S.replace(/(.)<\/?code>(?=.)/g,"$1`");R=y(R,S.charAt(1)=="!"?"\\`*_/":"\\`*_");return R});return Q}function E(P){P=P.replace(/(\[((?:\[[^\]]*\]|[^\[\]])*)\][ ]?(?:\n[ ]*)?\[(.*?)\])()()()()/g,h);P=P.replace(/(\[((?:\[[^\]]*\]|[^\[\]])*)\]\([ \t]*()?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g,h);P=P.replace(/(\[([^\[\]]+)\])()()()()()/g,h);return P}function h(V,ab,aa,Z,Y,X,U,T){if(T==undefined){T=""}var S=ab;var Q=aa.replace(/:\/\//g,"~P");var R=Z.toLowerCase();var P=Y;var W=T;if(P==""){if(R==""){R=Q.toLowerCase().replace(/ ?\n/g," ")}P="#"+R;if(w.get(R)!=undefined){P=w.get(R);if(n.get(R)!=undefined){W=n.get(R)}}else{if(S.search(/\(\s*\)$/m)>-1){P=""}else{return S}}}P=A(P);P=y(P,"*_");var ac='";return ac}function D(P){P=P.replace(/(!\[(.*?)\][ ]?(?:\n[ ]*)?\[(.*?)\])()()()()/g,F);P=P.replace(/(!\[(.*?)\]\s?\([ \t]*()?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g,F);return P}function G(P){return P.replace(/>/g,">").replace(/"+k(R)+"\n\n"});P=P.replace(/^(.+)[ \t]*\n-+[ \t]*\n+/gm,function(R,Q){return"

    "+k(Q)+"

    \n\n"});P=P.replace(/^(\#{1,6})[ \t]*(.+?)[ \t]*\#*\n+/gm,function(Q,T,S){var R=T.length;return""+k(S)+"\n\n"});return P}function L(Q){Q+="~0";var P=/^(([ ]{0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm;if(z){Q=Q.replace(P,function(S,V,U){var W=V;var T=(U.search(/[*+-]/g)>-1)?"ul":"ol";var R=l(W,T);R=R.replace(/\s+$/,"");R="<"+T+">"+R+"\n";return R})}else{P=/(\n\n|^\n?)(([ ]{0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/g;Q=Q.replace(P,function(T,X,V,S){var W=X;var Y=V;var U=(S.search(/[*+-]/g)>-1)?"ul":"ol";var R=l(Y,U);R=W+"<"+U+">\n"+R+"\n";return R})}Q=Q.replace(/~0/,"");return Q}var p={ol:"\\d+[.]",ul:"[*+-]"};function l(R,Q){z++;R=R.replace(/\n{2,}$/,"\n");R+="~0";var P=p[Q];var S=new RegExp("(^[ \\t]*)("+P+")[ \\t]+([^\\r]+?(\\n+))(?=(~0|\\1("+P+")[ \\t]+))","gm");var T=false;R=R.replace(S,function(V,X,W,U){var aa=U;var ab=X;var Z=/\n\n$/.test(aa);var Y=Z||aa.search(/\n{2,}/)>-1;if(Y||T){aa=f(t(aa),true)}else{aa=L(t(aa));aa=aa.replace(/\n$/,"");aa=k(aa)}T=Z;return"
  • "+aa+"
  • \n"});R=R.replace(/~0/g,"");z--;return R}function q(P){P+="~0";P=P.replace(/(?:\n\n|^)((?:(?:[ ]{4}|\t).*\n+)+)(\n*[ ]{0,3}[^ \t\n]|(?=~0))/g,function(Q,S,R){var T=S;var U=R;T=B(t(T));T=J(T);T=T.replace(/^\n+/g,"");T=T.replace(/\n+$/g,"");T='
    '+T+"\n
    ";return"\n\n"+T+"\n\n"+U});P=P.replace(/~0/,"");return P}function N(P){P=P.replace(/(^\n+|\n+$)/g,"");return"\n\n~K"+(e.push(P)-1)+"K\n\n"}function r(P){P=P.replace(/(^|[^\\])(`+)([^\r]*?[^`])\2(?!`)/gm,function(S,U,T,R,Q){var V=R;V=V.replace(/^([ \t]*)/g,"");V=V.replace(/[ \t]*$/g,"");V=B(V);V=V.replace(/:\/\//g,"~P");return U+""+V+""});return P}function B(P){P=P.replace(/&/g,"&");P=P.replace(//g,">");P=y(P,"*_{}[]\\",false);return P}function x(P){P=P.replace(/([\W_]|^)(\*\*|__)(?=\S)([^\r]*?\S[\*_]*)\2([\W_]|$)/g,"$1$3$4");P=P.replace(/([\W_]|^)(\*|_)(?=\S)([^\r\*_]*?\S)\2([\W_]|$)/g,"$1$3$4");return P}function g(P){P=P.replace(/((^[ \t]*>[ \t]?.+\n(.+\n)*\n*)+)/gm,function(Q,R){var S=R;S=S.replace(/^[ \t]*>[ \t]?/gm,"~0");S=S.replace(/~0/g,"");S=S.replace(/^[ \t]+$/gm,"");S=f(S);S=S.replace(/(^|\n)/g,"$1 ");S=S.replace(/(\s*
    [^\r]+?<\/pre>)/gm,function(T,U){var V=U;V=V.replace(/^  /mg,"~0");V=V.replace(/~0/g,"");return V});return N("
    \n"+S+"\n
    ")});return P}function I(W,P){W=W.replace(/^\n+/g,"");W=W.replace(/\n+$/g,"");var X=W.split(/\n{2,}/g);var U=[];var Q=/~K(\d+)K/;var R=X.length;for(var S=0;S");T+="

    ";U.push(T)}}}if(!P){R=U.length;for(var S=0;S#+-.!])/g,s);return P}function K(R){R=R.replace(/(^|\s)(https?|ftp)(:\/\/[-A-Z0-9+&@#\/%?=~_|\[\]\(\)!:,\.;]*[-A-Z0-9+&@#\/%=~_|\[\]])($|\W)/gi,"$1<$2$3>$4");var Q=function(T,S){return'
    '+j.plainLinkText(S)+""};R=R.replace(/<((https?|ftp):[^'">\s]+)>/gi,Q);var P=function(W,U){var S="mailto:";var V;var T;if(U.substring(0,S.length)!=S){V=S+U;T=U}else{V=U;T=U.substring(S.length,U.length)}return''+j.plainLinkText(T)+""};R=R.replace(/<((?:mailto:)?([-.\w]+\@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+))>/gi,P);return R}function M(P){P=P.replace(/~E(\d+)E/g,function(Q,S){var R=parseInt(S);return String.fromCharCode(R)});return P}function t(P){P=P.replace(/^(\t|[ ]{1,4})/gm,"~0");P=P.replace(/~0/g,"");return P}function J(S){if(!/\t/.test(S)){return S}var R=[" "," "," "," "],Q=0,P;return S.replace(/[\n\t]/g,function(T,U){if(T==="\n"){Q=U+1;return T}P=(U-Q)%4;Q=U+1;return R[P]})}var u=/(?:["'*()[\]:]|~D)/g;function A(Q){if(!Q){return""}var P=Q.length;return Q.replace(u,function(R,S){if(R=="~D"){return"%24"}if(R==":"){if(S==P-1||/[0-9\/]/.test(Q.charAt(S+1))){return":"}if(Q.substring(0,"mailto:".length)==="mailto:"){return":"}if(Q.substring(0,"magnet:".length)==="magnet:"){return":"}}return"%"+R.charCodeAt(0).toString(16)})}function y(T,Q,R){var P="(["+Q.replace(/([\[\]\\])/g,"\\$1")+"])";if(R){P="\\\\"+P}var S=new RegExp(P,"g");T=T.replace(S,s);return T}function s(P,R){var Q=R.charCodeAt(0);return"~E"+Q+"E"}}})();(function(){var a={},s={},l={},u=window.document,m=window.RegExp,g=window.navigator,o={lineLength:72},t={isIE:/msie/.test(g.userAgent.toLowerCase()),isIE_5or6:/msie 6/.test(g.userAgent.toLowerCase())||/msie 5/.test(g.userAgent.toLowerCase()),isOpera:/opera/.test(g.userAgent.toLowerCase())};var v='

    http://example.com/ "optional title"

    ';var p='

    http://example.com/images/diagram.jpg "optional title"

    ';var c="http://";var d="http://";var j="Markdown Editing Help";Markdown.Editor=function(z,B,y){B=B||"";var w=this.hooks=new Markdown.HookCollection();w.addNoop("onPreviewRefresh");w.addNoop("postBlockquoteCreation");w.addFalse("insertImageDialog");this.getConverter=function(){return z};var A=this,x;this.run=function(){if(x){return}x=new i(B);var E=new k(w);var C=new h(z,x,function(){w.onPreviewRefresh()});var F,D;if(!/\?noundo/.test(u.location.href)){F=new e(function(){C.refresh();if(D){D.setUndoRedoButtonStates()}},x);this.textOperation=function(H){F.setCommandMode();H();A.refreshPreview()}}D=new q(B,x,F,C,E,y);D.setUndoRedoButtonStates();var G=A.refreshPreview=function(){C.refresh(true)};G()}};function r(){}r.prototype.findTags=function(x,z){var w=this;var y;if(x){y=a.extendRegExp(x,"","$");this.before=this.before.replace(y,function(A){w.startTag=w.startTag+A;return""});y=a.extendRegExp(x,"^","");this.selection=this.selection.replace(y,function(A){w.startTag=w.startTag+A;return""})}if(z){y=a.extendRegExp(z,"","$");this.selection=this.selection.replace(y,function(A){w.endTag=A+w.endTag;return""});y=a.extendRegExp(z,"^","");this.after=this.after.replace(y,function(A){w.endTag=A+w.endTag;return""})}};r.prototype.trimWhitespace=function(x){var w,z,y=this;if(x){w=z=""}else{w=function(A){y.before+=A;return""};z=function(A){y.after=A+y.after;return""}}this.selection=this.selection.replace(/^(\s*)/,w).replace(/(\s*)$/,z)};r.prototype.skipLines=function(y,x,w){if(y===undefined){y=1}if(x===undefined){x=1}y++;x++;var z;var A;if(navigator.userAgent.match(/Chrome/)){"X".match(/()./)}this.selection=this.selection.replace(/(^\n*)/,"");this.startTag=this.startTag+m.$1;this.selection=this.selection.replace(/(\n*$)/,"");this.endTag=this.endTag+m.$1;this.startTag=this.startTag.replace(/(^\n*)/,"");this.before=this.before+m.$1;this.endTag=this.endTag.replace(/(\n*$)/,"");this.after=this.after+m.$1;if(this.before){z=A="";while(y--){z+="\\n?";A+="\n"}if(w){z="\\n*"}this.before=this.before.replace(new m(z+"$",""),A)}if(this.after){z=A="";while(x--){z+="\\n?";A+="\n"}if(w){z="\\n*"}this.after=this.after.replace(new m(z,""),A)}};function i(w){this.buttonBar=u.getElementById("wmd-button-bar"+w);this.preview=u.getElementById("wmd-preview"+w);this.input=u.getElementById("wmd-input"+w)}a.isVisible=function(w){if(window.getComputedStyle){return window.getComputedStyle(w,null).getPropertyValue("display")!=="none"}else{if(w.currentStyle){return w.currentStyle.display!=="none"}}};a.addEvent=function(x,w,y){if(x.attachEvent){x.attachEvent("on"+w,y)}else{x.addEventListener(w,y,false)}};a.removeEvent=function(x,w,y){if(x.detachEvent){x.detachEvent("on"+w,y)}else{x.removeEventListener(w,y,false)}};a.fixEolChars=function(w){w=w.replace(/\r\n/g,"\n");w=w.replace(/\r/g,"\n");return w};a.extendRegExp=function(y,A,x){if(A===null||A===undefined){A=""}if(x===null||x===undefined){x=""}var z=y.toString();var w;z=z.replace(/\/([gim]*)$/,function(B,C){w=C;return""});z=z.replace(/(^\/|\/$)/g,"");z=A+z+x;return new m(z,w)};s.getTop=function(y,x){var w=y.offsetTop;if(!x){while(y=y.offsetParent){w+=y.offsetTop}}return w};s.getHeight=function(w){return w.offsetHeight||w.scrollHeight};s.getWidth=function(w){return w.offsetWidth||w.scrollWidth};s.getPageSize=function(){var x,y;var w,B;if(self.innerHeight&&self.scrollMaxY){x=u.body.scrollWidth;y=self.innerHeight+self.scrollMaxY}else{if(u.body.scrollHeight>u.body.offsetHeight){x=u.body.scrollWidth;y=u.body.scrollHeight}else{x=u.body.offsetWidth;y=u.body.offsetHeight}}if(self.innerHeight){w=self.innerWidth;B=self.innerHeight}else{if(u.documentElement&&u.documentElement.clientHeight){w=u.documentElement.clientWidth;B=u.documentElement.clientHeight}else{if(u.body){w=u.body.clientWidth;B=u.body.clientHeight}}}var A=Math.max(x,w);var z=Math.max(y,B);return[A,z,w,B]};function e(I,F){var L=this;var G=[];var D=0;var C="none";var x;var y;var B;var w=function(N,M){if(C!=N){C=N;if(!M){z()}}if(!t.isIE||C!="moving"){y=setTimeout(E,1)}else{B=null}};var E=function(M){B=new b(F,M);y=undefined};this.setCommandMode=function(){C="command";z();y=setTimeout(E,0)};this.canUndo=function(){return D>1};this.canRedo=function(){if(G[D+1]){return true}return false};this.undo=function(){if(L.canUndo()){if(x){x.restore();x=null}else{G[D]=new b(F);G[--D].restore();if(I){I()}}}C="none";F.input.focus();E()};this.redo=function(){if(L.canRedo()){G[++D].restore();if(I){I()}}C="none";F.input.focus();E()};var z=function(){var M=B||new b(F);if(!M){return false}if(C=="moving"){if(!x){x=M}return}if(x){if(G[D-1].text!=x.text){G[D++]=x}x=null}G[D++]=M;G[D+1]=null;if(I){I()}};var H=function(M){var O=false;if(M.ctrlKey||M.metaKey){var N=M.charCode||M.keyCode;var P=String.fromCharCode(N);switch(P){case"y":L.redo();O=true;break;case"z":if(!M.shiftKey){L.undo()}else{L.redo()}O=true;break}}if(O){if(M.preventDefault){M.preventDefault()}if(window.event){window.event.returnValue=false}return}};var K=function(M){if(!M.ctrlKey&&!M.metaKey){var N=M.keyCode;if((N>=33&&N<=40)||(N>=63232&&N<=63235)){w("moving")}else{if(N==8||N==46||N==127){w("deleting")}else{if(N==13){w("newlines")}else{if(N==27){w("escape")}else{if((N<16||N>20)&&N!=91){w("typing")}}}}}}};var A=function(){a.addEvent(F.input,"keypress",function(N){if((N.ctrlKey||N.metaKey)&&(N.keyCode==89||N.keyCode==90)){N.preventDefault()}});var M=function(){if(t.isIE||(B&&B.text!=F.input.value)){if(y==undefined){C="paste";z();E()}}};a.addEvent(F.input,"keydown",H);a.addEvent(F.input,"keydown",K);a.addEvent(F.input,"mousedown",function(){w("moving")});F.input.onpaste=M;F.input.ondrop=M};var J=function(){A();E(true);z()};J()}function b(x,z){var w=this;var y=x.input;this.init=function(){if(!a.isVisible(y)){return}if(!z&&u.activeElement&&u.activeElement!==y){return}this.setInputAreaSelectionStartEnd();this.scrollTop=y.scrollTop;if(!this.text&&y.selectionStart||y.selectionStart===0){this.text=y.value}};this.setInputAreaSelection=function(){if(!a.isVisible(y)){return}if(y.selectionStart!==undefined&&!t.isOpera){y.focus();y.selectionStart=w.start;y.selectionEnd=w.end;y.scrollTop=w.scrollTop}else{if(u.selection){if(u.activeElement&&u.activeElement!==y){return}y.focus();var A=y.createTextRange();A.moveStart("character",-y.value.length);A.moveEnd("character",-y.value.length);A.moveEnd("character",w.end);A.moveStart("character",w.start);A.select()}}};this.setInputAreaSelectionStartEnd=function(){if(!x.ieCachedRange&&(y.selectionStart||y.selectionStart===0)){w.start=y.selectionStart;w.end=y.selectionEnd}else{if(u.selection){w.text=a.fixEolChars(y.value);var D=x.ieCachedRange||u.selection.createRange();var E=a.fixEolChars(D.text);var C="\x07";var B=C+E+C;D.text=B;var F=a.fixEolChars(y.value);D.moveStart("character",-B.length);D.text=E;w.start=F.indexOf(C);w.end=F.lastIndexOf(C)-C.length;var A=w.text.length-a.fixEolChars(y.value).length;if(A){D.moveStart("character",-E.length);while(A--){E+="\n";w.end+=1}D.text=E}if(x.ieCachedRange){w.scrollTop=x.ieCachedScrollTop}x.ieCachedRange=null;this.setInputAreaSelection()}}};this.restore=function(){if(w.text!=undefined&&w.text!=y.value){y.value=w.text}this.setInputAreaSelection();y.scrollTop=w.scrollTop};this.getChunks=function(){var A=new r();A.before=a.fixEolChars(w.text.substring(0,w.start));A.startTag="";A.selection=a.fixEolChars(w.text.substring(w.start,w.end));A.endTag="";A.after=a.fixEolChars(w.text.substring(w.end));A.scrollTop=w.scrollTop;return A};this.setChunks=function(A){A.before=A.before+A.startTag;A.after=A.endTag+A.after;this.start=A.before.length;this.end=A.before.length+A.selection.length;this.text=A.before+A.selection+A.after;this.scrollTop=A.scrollTop};this.init()}function h(Q,z,K){var x=this;var E;var D;var N;var y=3000;var F="delayed";var B=function(S,T){a.addEvent(S,"input",T);S.onpaste=T;S.ondrop=T;a.addEvent(S,"keypress",T);a.addEvent(S,"keydown",T)};var J=function(){var S=0;if(window.innerHeight){S=window.pageYOffset}else{if(u.documentElement&&u.documentElement.scrollTop){S=u.documentElement.scrollTop}else{if(u.body){S=u.body.scrollTop}}}return S};var C=function(){if(!z.preview){return}var U=z.input.value;if(U&&U==N){return}else{N=U}var T=new Date().getTime();U=Q.makeHtml(U);var S=new Date().getTime();D=S-T;w(U)};var P=function(){if(E){clearTimeout(E);E=undefined}if(F!=="manual"){var S=0;if(F==="delayed"){S=D}if(S>y){S=y}E=setTimeout(C,S)}};var A=function(S){if(S.scrollHeight<=S.clientHeight){return 1}return S.scrollTop/(S.scrollHeight-S.clientHeight)};var R=function(){if(z.preview){z.preview.scrollTop=(z.preview.scrollHeight-z.preview.clientHeight)*A(z.preview)}};this.refresh=function(S){if(S){N="";C()}else{P()}};this.processingTime=function(){return D};var G=true;var H=function(V){var U=z.preview;var T=U.parentNode;var S=U.nextSibling;T.removeChild(U);U.innerHTML=V;if(!S){T.appendChild(U)}else{T.insertBefore(U,S)}};var M=function(S){z.preview.innerHTML=S};var I;var L=function(T){if(I){return I(T)}try{M(T);I=M}catch(S){I=H;I(T)}};var w=function(U){var S=s.getTop(z.input)-J();if(z.preview){L(U);K()}R();if(G){G=false;return}var T=s.getTop(z.input)-J();if(t.isIE){setTimeout(function(){window.scrollBy(0,T-S)},0)}else{window.scrollBy(0,T-S)}};var O=function(){B(z.input,P);C();if(z.preview){z.preview.scrollTop=0}};O()}l.prompt=function(x,B,E,z){var w;var y;if(E===undefined){E=""}var A=function(F){var G=(F.charCode||F.keyCode);if(G===27){C(true)}};var C=function(F){a.removeEvent(u.body,"keydown",A);var G=y.value;if(F){G=null}else{G=G.replace(/^http:\/\/(https?|ftp):\/\//,"$1://");if(!/^(?:https?|ftp):\/\//.test(G)){G="http://"+G}}$(w).modal("hide");z(G);return false};var D=function(){w=u.createElement("div");w.className="modal fade";var J=u.createElement("div");J.className="modal-dialog";w.appendChild(J);var M=u.createElement("div");M.className="modal-content";J.appendChild(M);var K=u.createElement("div");K.className="modal-header";K.innerHTML='× ";M.appendChild(K);var L=u.createElement("div");L.className="modal-body";M.appendChild(L);var O=u.createElement("div");O.className="modal-footer";M.appendChild(O);var I=u.createElement("p");I.innerHTML=B;I.style.padding="5px";L.appendChild(I);var G=u.createElement("form"),F=G.style;G.onsubmit=function(){return C(false)};F.padding="0";F.margin="0";L.appendChild(G);y=u.createElement("input");y.type="text";y.value=E;y.className="form-control";F=y.style;F.display="block";F.width="80%";F.marginLeft=F.marginRight="auto";G.appendChild(y);var N=u.createElement("button");N.className="btn btn-primary";N.type="button";N.onclick=function(){return C(false)};N.innerHTML="OK";var H=u.createElement("button");H.className="btn btn-primary";H.type="button";H.onclick=function(){return C(true)};H.innerHTML="Cancel";O.appendChild(N);O.appendChild(H);a.addEvent(u.body,"keydown",A);u.body.appendChild(w)};setTimeout(function(){D();var G=E.length;if(y.selectionStart!==undefined){y.selectionStart=0;y.selectionEnd=G}else{if(y.createTextRange){var F=y.createTextRange();F.collapse(false);F.moveStart("character",-G);F.moveEnd("character",G);F.select()}}$(w).on("shown",function(){y.focus()});$(w).on("hidden",function(){w.parentNode.removeChild(w)});$(w).modal()},0)};function q(H,C,J,y,G,B){var A=C.input,E={};z();var D="keydown";if(t.isOpera){D="keypress"}a.addEvent(A,D,function(L){if((L.ctrlKey||L.metaKey)&&!L.altKey&&!L.shiftKey){var M=L.charCode||L.keyCode;var K=String.fromCharCode(M).toLowerCase();switch(K){case"b":I(E.bold);break;case"i":I(E.italic);break;case"l":I(E.link);break;case"q":I(E.quote);break;case"k":I(E.code);break;case"g":I(E.image);break;case"o":I(E.olist);break;case"u":I(E.ulist);break;case"h":I(E.heading);break;case"r":I(E.hr);break;case"y":I(E.redo);break;case"z":if(L.shiftKey){I(E.redo)}else{I(E.undo)}break;default:return}if(L.preventDefault){L.preventDefault()}if(window.event){window.event.returnValue=false}}});a.addEvent(A,"keyup",function(L){if(L.shiftKey&&!L.ctrlKey&&!L.metaKey){var M=L.charCode||L.keyCode;if(M===13){var K={};K.textOp=x("doAutoindent");I(K)}}});if(t.isIE){a.addEvent(A,"keydown",function(K){var L=K.keyCode;if(L===27){return false}})}function I(L){A.focus();if(L.textOp){if(J){J.setCommandMode()}var N=new b(C);if(!N){return}var O=N.getChunks();var K=function(){A.focus();if(O){N.setChunks(O)}N.restore();y.refresh()};var M=L.textOp(O,K);if(!M){K()}}if(L.execute){L.execute(J)}}function w(K,L){if(L){K.disabled=false;if(!K.isHelp){K.onclick=function(){if(this.onmouseout){this.onmouseout()}I(this);return false}}}else{K.disabled=true}}function x(K){if(typeof K==="string"){K=G[K]}return function(){K.apply(G,arguments)}}function z(){var L=C.buttonBar;var N=document.createElement("div");N.id="wmd-button-row"+H;N.className="btn-toolbar";N=L.appendChild(N);var M=function(X,V,T,W,U){var S=document.createElement("button");S.className="btn";var R=document.createElement("i");R.className=T;S.id=X+H;S.appendChild(R);S.title=V;$(S).tooltip({placement:"bottom",container:"body"});if(W){S.textOp=W}w(S,true);if(U){U.appendChild(S)}else{N.appendChild(S)}return S};var P=function(R){var S=document.createElement("div");S.className="btn-group wmd-button-group"+R;S.id="wmd-button-group"+R+H;N.appendChild(S);return S};group1=P(1);E.bold=M("wmd-bold-button","Bold - Ctrl+B","fa fa-bold",x("doBold"),group1);E.italic=M("wmd-italic-button","Italic - Ctrl+I","fa fa-italic",x("doItalic"),group1);group2=P(2);E.link=M("wmd-link-button","Link - Ctrl+L","fa fa-link",x(function(R,S){return this.doLinkOrImage(R,S,false)}),group2);E.quote=M("wmd-quote-button","Blockquote - Ctrl+Q","fa fa-quote-left",x("doBlockquote"),group2);E.code=M("wmd-code-button","Code Sample - Ctrl+K","fa fa-code",x("doCode"),group2);E.image=M("wmd-image-button","Image - Ctrl+G","fa fa-picture-o",x(function(R,S){return this.doLinkOrImage(R,S,true)}),group2);group3=P(3);E.olist=M("wmd-olist-button","Numbered List - Ctrl+O","fa fa-list-ol",x(function(R,S){this.doList(R,S,true)}),group3);E.ulist=M("wmd-ulist-button","Bulleted List - Ctrl+U","fa fa-list-ul",x(function(R,S){this.doList(R,S,false)}),group3);E.heading=M("wmd-heading-button","Heading - Ctrl+H","fa fa-header",x("doHeading"),group3);E.hr=M("wmd-hr-button","Horizontal Rule - Ctrl+R","fa fa-ellipsis-h",x("doHorizontalRule"),group3);group4=P(4);E.undo=M("wmd-undo-button","Undo - Ctrl+Z","fa fa-undo",null,group4);E.undo.execute=function(R){if(R){R.undo()}};var O=/win/.test(g.platform.toLowerCase())?"Redo - Ctrl+Y":"Redo - Ctrl+Shift+Z";E.redo=M("wmd-redo-button",O,"fa fa-rotate-right",null,group4);E.redo.execute=function(R){if(R){R.redo()}};if(B){group5=P(5);group5.className=group5.className+" pull-right";var Q=document.createElement("button");var K=document.createElement("i");K.className="fa fa-question";Q.appendChild(K);Q.className="btn";Q.id="wmd-help-button"+H;Q.isHelp=true;Q.title=B.title||j;$(Q).tooltip({placement:"bottom",container:"body"});Q.onclick=B.handler;w(Q,true);group5.appendChild(Q);E.help=Q}F()}function F(){if(J){w(E.undo,J.canUndo());w(E.redo,J.canRedo())}}this.setUndoRedoButtonStates=F}function k(w){this.hooks=w}var f=k.prototype;f.prefixes="(?:\\s{4,}|\\s*>|\\s*-\\s+|\\s*\\d+\\.|=|\\+|-|_|\\*|#|\\s*\\[[^\n]]+\\]:)";f.unwrap=function(x){var w=new m("([^\\n])\\n(?!(\\n|"+this.prefixes+"))","g");x.selection=x.selection.replace(w,"$1 $2")};f.wrap=function(x,w){this.unwrap(x);var z=new m("(.{1,"+w+"})( +|$\\n?)","gm"),y=this;x.selection=x.selection.replace(z,function(A,B){if(new m("^"+y.prefixes,"").test(A)){return A}return B+"\n"});x.selection=x.selection.replace(/\s+$/,"")};f.doBold=function(w,x){return this.doBorI(w,x,2,"strong text")};f.doItalic=function(w,x){return this.doBorI(w,x,1,"emphasized text")};f.doBorI=function(C,A,B,w){C.trimWhitespace();C.selection=C.selection.replace(/\n{2,}/g,"\n");var z=/(\**$)/.exec(C.before)[0];var x=/(^\**)/.exec(C.after)[0];var D=Math.min(z.length,x.length);if((D>=B)&&(D!=2||B!=1)){C.before=C.before.replace(m("[*]{"+B+"}$",""),"");C.after=C.after.replace(m("^[*]{"+B+"}",""),"")}else{if(!C.selection&&x){C.after=C.after.replace(/^([*_]*)/,"");C.before=C.before.replace(/(\s?)$/,"");var y=m.$1;C.before=C.before+x+y}else{if(!C.selection&&!x){C.selection=w}var E=B<=1?"*":"**";C.before=C.before+E;C.after=E+C.after}}return};f.stripLinkDefs=function(x,w){x=x.replace(/^[ ]{0,3}\[(\d+)\]:[ \t]*\n?[ \t]*?[ \t]*\n?[ \t]*(?:(\n*)["(](.+?)[")][ \t]*)?(?:\n+|$)/gm,function(B,C,y,z,A){w[C]=B.replace(/\s*$/,"");if(z){w[C]=B.replace(/["(](.+?)[")]$/,"");return z+A}return""});return x};f.addLinkDef=function(D,z){var w=0;var y={};D.before=this.stripLinkDefs(D.before,y);D.selection=this.stripLinkDefs(D.selection,y);D.after=this.stripLinkDefs(D.after,y);var x="";var C=/(\[)((?:\[[^\]]*\]|[^\[\]])*)(\][ ]?(?:\n[ ]*)?\[)(\d+)(\])/g;var B=function(F){w++;F=F.replace(/^[ ]{0,3}\[(\d+)\]:/," ["+w+"]:");x+="\n"+F};var A=function(G,J,H,I,K,F){H=H.replace(C,A);if(y[K]){B(y[K]);return J+H+I+w+F}return G};D.before=D.before.replace(C,A);if(z){B(z)}else{D.selection=D.selection.replace(C,A)}var E=w;D.after=D.after.replace(C,A);if(D.after){D.after=D.after.replace(/\n*$/,"")}if(!D.after){D.selection=D.selection.replace(/\n*$/,"")}D.after+="\n\n"+x;return E};function n(w){return w.replace(/^\s*(.*?)(?:\s+"(.+)")?\s*$/,function(y,x,z){x=x.replace(/\?.*$/,function(A){return A.replace(/\+/g," ")});x=decodeURIComponent(x);x=encodeURI(x).replace(/'/g,"%27").replace(/\(/g,"%28").replace(/\)/g,"%29");x=x.replace(/\?.*$/,function(A){return A.replace(/\+/g,"%2b")});if(z){z=z.trim?z.trim():z.replace(/^\s*/,"").replace(/\s*$/,"");z=$.trim(z).replace(/"/g,"quot;").replace(/\(/g,"(").replace(/\)/g,")").replace(//g,">")}return z?x+' "'+z+'"':x})}f.doLinkOrImage=function(w,y,B){w.trimWhitespace();w.findTags(/\s*!?\[/,/\][ ]?(?:\n[ ]*)?(\[.*?\])?/);var x;if(w.endTag.length>1&&w.startTag.length>0){w.startTag=w.startTag.replace(/!?\[/,"");w.endTag="";this.addLinkDef(w,null)}else{w.selection=w.startTag+w.selection+w.endTag;w.startTag=w.endTag="";if(/\n\n/.test(w.selection)){this.addLinkDef(w,null);return}var z=this;var A=function(E){if(E!==null){w.selection=(" "+w.selection).replace(/([^\\](?:\\\\)*)(?=[[\]])/g,"$1\\").substr(1);var D=" [999]: "+n(E);var C=z.addLinkDef(w,D);w.startTag=B?"![":"[";w.endTag="]["+C+"]";if(!w.selection){if(B){w.selection="enter image description here"}else{w.selection="enter link description here"}}}y()};if(B){if(!this.hooks.insertImageDialog(A)){l.prompt("Insert Image",p,c,A)}}else{l.prompt("Insert Link",v,d,A)}return true}};f.doAutoindent=function(y,z){var x=this,w=false;y.before=y.before.replace(/(\n|^)[ ]{0,3}([*+-]|\d+[.])[ \t]*\n$/,"\n\n");y.before=y.before.replace(/(\n|^)[ ]{0,3}>[ \t]*\n$/,"\n\n");y.before=y.before.replace(/(\n|^)[ \t]+\n$/,"\n\n");if(!y.selection&&!/^[ \t]*(?:\n|$)/.test(y.after)){y.after=y.after.replace(/^[^\n]*/,function(A){y.selection=A;return""});w=true}if(/(\n|^)[ ]{0,3}([*+-]|\d+[.])[ \t]+.*\n$/.test(y.before)){if(x.doList){x.doList(y)}}if(/(\n|^)[ ]{0,3}>[ \t]+.*\n$/.test(y.before)){if(x.doBlockquote){x.doBlockquote(y)}}if(/(\n|^)(\t|[ ]{4,}).*\n$/.test(y.before)){if(x.doCode){x.doCode(y)}}if(w){y.after=y.selection+y.after;y.selection=""}};f.doBlockquote=function(D,y){D.selection=D.selection.replace(/^(\n*)([^\r]+?)(\n*)$/,function(J,I,H,G){D.before+=I;D.after=G+D.after;return H});D.before=D.before.replace(/(>[ \t]*)$/,function(H,G){D.selection=G+D.selection;return""});D.selection=D.selection.replace(/^(\s|>)+$/,"");D.selection=D.selection||"Blockquote";var C="",B="",E;if(D.before){var F=D.before.replace(/\n$/,"").split("\n");var A=false;for(var z=0;z0;if(/^>/.test(E)){x=true;if(!A&&E.length>1){A=true}}else{if(/^[ \t]*$/.test(E)){x=true}else{x=A}}if(x){C+=E+"\n"}else{B+=C+E;C="\n"}}if(!/(^|\n)>/.test(C)){B+=C;C=""}}D.startTag=C;D.before=B;if(D.after){D.after=D.after.replace(/^\n?/,"\n")}D.after=D.after.replace(/^(((\n|^)(\n[ \t]*)*>(.+\n)*.*)+(\n[ \t]*)*)/,function(G){D.endTag=G;return""});var w=function(H){var G=H?"> ":"";if(D.startTag){D.startTag=D.startTag.replace(/\n((>|\s)*)\n$/,function(J,I){return"\n"+I.replace(/^[ ]{0,3}>?[ \t]*$/gm,G)+"\n"})}if(D.endTag){D.endTag=D.endTag.replace(/^\n((>|\s)*)\n/,function(J,I){return"\n"+I.replace(/^[ ]{0,3}>?[ \t]*$/gm,G)+"\n"})}};if(/^(?![ ]{0,3}>)/m.test(D.selection)){this.wrap(D,o.lineLength-2);D.selection=D.selection.replace(/^/gm,"> ");w(true);D.skipLines()}else{D.selection=D.selection.replace(/^[ ]{0,3}> ?/gm,"");this.unwrap(D);w(false);if(!/^(\n|^)[ ]{0,3}>/.test(D.selection)&&D.startTag){D.startTag=D.startTag.replace(/\n{0,2}$/,"\n\n")}if(!/(\n|^)[ ]{0,3}>.*$/.test(D.selection)&&D.endTag){D.endTag=D.endTag.replace(/^\n{0,2}/,"\n\n")}}D.selection=this.hooks.postBlockquoteCreation(D.selection);if(!/\n/.test(D.selection)){D.selection=D.selection.replace(/^(> *)/,function(G,H){D.startTag+=H;return""})}};f.doCode=function(w,x){var z=/\S[ ]*$/.test(w.before);var B=/^[ ]*\S/.test(w.after);if((!B&&!z)||/\n/.test(w.selection)){w.before=w.before.replace(/[ ]{4}$/,function(C){w.selection=C+w.selection;return""});var A=1;var y=1;if(/(\n|^)(\t|[ ]{4,}).*\n$/.test(w.before)){A=0}if(/^\n(\t|[ ]{4,})/.test(w.after)){y=0}w.skipLines(A,y);if(!w.selection){w.startTag=" ";w.selection="enter code here"}else{if(/^[ ]{0,3}\S/m.test(w.selection)){if(/\n/.test(w.selection)){w.selection=w.selection.replace(/^/gm," ")}else{w.before+=" "}}else{w.selection=w.selection.replace(/^[ ]{4}/gm,"")}}}else{w.trimWhitespace();w.findTags(/`/,/`/);if(!w.startTag&&!w.endTag){w.startTag=w.endTag="`";if(!w.selection){w.selection="enter code here"}}else{if(w.endTag&&!w.startTag){w.before+=w.endTag;w.endTag=""}else{w.startTag=w.endTag=""}}}};f.doList=function(H,A,z){var J=/(\n|^)(([ ]{0,3}([*+-]|\d+[.])[ \t]+.*)(\n.+|\n{2,}([*+-].*|\d+[.])[ \t]+.*|\n{2,}[ \t]+\S.*)*)\n*$/;var I=/^\n*(([ ]{0,3}([*+-]|\d+[.])[ \t]+.*)(\n.+|\n{2,}([*+-].*|\d+[.])[ \t]+.*|\n{2,}[ \t]+\S.*)*)\n*/;var w="-";var E=1;var C=function(){var K;if(z){K=" "+E+". ";E++}else{K=" "+w+" "}return K};var D=function(K){if(z===undefined){z=/^\s*\d/.test(K)}K=K.replace(/^[ ]{0,3}([*+-]|\d+[.])\s/gm,function(L){return C()});return K};H.findTags(/(\n|^)*[ ]{0,3}([*+-]|\d+[.])\s+/,null);if(H.before&&!/\n$/.test(H.before)&&!/^\n/.test(H.startTag)){H.before+=H.startTag;H.startTag=""}if(H.startTag){var y=/\d+[.]/.test(H.startTag);H.startTag="";H.selection=H.selection.replace(/\n[ ]{4}/g,"\n");this.unwrap(H);H.skipLines();if(y){H.after=H.after.replace(I,D)}if(z==y){return}}var B=1;H.before=H.before.replace(J,function(K){if(/^\s*([*+-])/.test(K)){w=m.$1}B=/[^\n]\n\n[^\n]/.test(K)?1:0;return D(K)});if(!H.selection){H.selection="List item"}var F=C();var x=1;H.after=H.after.replace(I,function(K){x=/[^\n]\n\n[^\n]/.test(K)?1:0;return D(K)});H.trimWhitespace(true);H.skipLines(B,x,true);H.startTag=F;var G=F.replace(/./g," ");this.wrap(H,o.lineLength-G.length);H.selection=H.selection.replace(/\n/g,"\n"+G)};f.doHeading=function(y,z){y.selection=y.selection.replace(/\s+/g," ");y.selection=y.selection.replace(/(^\s+|\s+$)/g,"");if(!y.selection){y.startTag="## ";y.selection="Heading";y.endTag=" ##";return}var A=0;y.findTags(/#+[ ]*/,/[ ]*#+/);if(/#+/.test(y.startTag)){A=m.lastMatch.length}y.startTag=y.endTag="";y.findTags(null,/\s?(-+|=+)/);if(/=+/.test(y.endTag)){A=1}if(/-+/.test(y.endTag)){A=2}y.startTag=y.endTag="";y.skipLines(1,1);var B=A==0?2:A-1;if(B>0){var x=B>=2?"-":"=";var w=y.selection.length;if(w>o.lineLength){w=o.lineLength}y.endTag="\n";while(w--){y.endTag+=x}}};f.doHorizontalRule=function(w,x){w.startTag="----------\n";w.selection="";w.skipLines(2,1,true)}})();(function(){var b,e;if(typeof exports==="object"&&typeof require==="function"){b=exports;e=require("./Markdown.Converter").Converter}else{b=window.Markdown;e=b.Converter}b.getSanitizingConverter=function(){var j=new e();j.hooks.chain("postConversion",h);j.hooks.chain("postConversion",a);return j};function h(j){return j.replace(/<[^>]*>?/gi,g)}var i=/^(<\/?(b|blockquote|code|del|dd|dl|dt|em|h1|h2|h3|i|kbd|li|ol|p|s|sup|sub|strong|strike|ul)>|<(br|hr)\s?\/?>)$/i;var d=/^(]+")?\s?>|<\/a>)$/i;var c=/^(]*")?(\stitle="[^"<>]*")?\s?\/?>)$/i;var f=/^(|<\/pre>)$/i;function g(j){if(j.match(i)||j.match(d)||j.match(c)||j.match(f)){return j}else{return""}}function a(n){if(n==""){return""}var t=/<\/?\w+[^>]*(\s|$|>)/g;var u=n.toLowerCase().match(t);var s=(u||[]).length;if(s==0){return n}var r,v;var q="



  • ";var o;var p=[];var k=[];var m=false;for(var j=0;j")>-1){continue}v=u[j];o=-1;if(!/^<\//.test(v)){for(var l=j+1;l"){o=l;break}}}if(o==-1){m=k[j]=true}else{p[o]=true}}if(!m){return n}var j=0;n=n.replace(t,function(w){var x=k[j]?"":w;j++;return x});return n}})();(function(a){a.fn.pagedownBootstrap=function(b){var c=a.extend({sanatize:true,help:null,hooks:Array()},b);return this.each(function(){var f=null;if(c.sanatize){f=Markdown.getSanitizingConverter()}else{f=new Markdown.Converter()}for(var d in c.hooks){var g=c.hooks[d];if(typeof g!=="object"||typeof g.event==="underfined"||typeof g.callback!=="function"){continue}f.hooks.chain(g.event,g.callback)}var j="wmd-input";var h=0;while(a("#"+j+"-"+h.toString()).length>0){h++}a(this).attr("id",j+"-"+h.toString());a(this).wrap('
    ');a(this).before('
    ');a(this).after('
    ');a(this).addClass("wmd-input");help=null;if(a.isFunction(c.help)){help={handler:c.help}}var e=new Markdown.Editor(f,"-"+h.toString(),help);e.run()})}})(jQuery); -------------------------------------------------------------------------------- /static/markdown/js/Markdown.Converter.js: -------------------------------------------------------------------------------- 1 | var Markdown; 2 | 3 | if (typeof exports === "object" && typeof require === "function") // we're in a CommonJS (e.g. Node.js) module 4 | Markdown = exports; 5 | else 6 | Markdown = {}; 7 | 8 | // The following text is included for historical reasons, but should 9 | // be taken with a pinch of salt; it's not all true anymore. 10 | 11 | // 12 | // Wherever possible, Showdown is a straight, line-by-line port 13 | // of the Perl version of Markdown. 14 | // 15 | // This is not a normal parser design; it's basically just a 16 | // series of string substitutions. It's hard to read and 17 | // maintain this way, but keeping Showdown close to the original 18 | // design makes it easier to port new features. 19 | // 20 | // More importantly, Showdown behaves like markdown.pl in most 21 | // edge cases. So web applications can do client-side preview 22 | // in Javascript, and then build identical HTML on the server. 23 | // 24 | // This port needs the new RegExp functionality of ECMA 262, 25 | // 3rd Edition (i.e. Javascript 1.5). Most modern web browsers 26 | // should do fine. Even with the new regular expression features, 27 | // We do a lot of work to emulate Perl's regex functionality. 28 | // The tricky changes in this file mostly have the "attacklab:" 29 | // label. Major or self-explanatory changes don't. 30 | // 31 | // Smart diff tools like Araxis Merge will be able to match up 32 | // this file with markdown.pl in a useful way. A little tweaking 33 | // helps: in a copy of markdown.pl, replace "#" with "//" and 34 | // replace "$text" with "text". Be sure to ignore whitespace 35 | // and line endings. 36 | // 37 | 38 | 39 | // 40 | // Usage: 41 | // 42 | // var text = "Markdown *rocks*."; 43 | // 44 | // var converter = new Markdown.Converter(); 45 | // var html = converter.makeHtml(text); 46 | // 47 | // alert(html); 48 | // 49 | // Note: move the sample code to the bottom of this 50 | // file before uncommenting it. 51 | // 52 | 53 | (function () { 54 | 55 | function identity(x) { return x; } 56 | function returnFalse(x) { return false; } 57 | 58 | function HookCollection() { } 59 | 60 | HookCollection.prototype = { 61 | 62 | chain: function (hookname, func) { 63 | var original = this[hookname]; 64 | if (!original) 65 | throw new Error("unknown hook " + hookname); 66 | 67 | if (original === identity) 68 | this[hookname] = func; 69 | else 70 | this[hookname] = function (x) { return func(original(x)); } 71 | }, 72 | set: function (hookname, func) { 73 | if (!this[hookname]) 74 | throw new Error("unknown hook " + hookname); 75 | this[hookname] = func; 76 | }, 77 | addNoop: function (hookname) { 78 | this[hookname] = identity; 79 | }, 80 | addFalse: function (hookname) { 81 | this[hookname] = returnFalse; 82 | } 83 | }; 84 | 85 | Markdown.HookCollection = HookCollection; 86 | 87 | // g_urls and g_titles allow arbitrary user-entered strings as keys. This 88 | // caused an exception (and hence stopped the rendering) when the user entered 89 | // e.g. [push] or [__proto__]. Adding a prefix to the actual key prevents this 90 | // (since no builtin property starts with "s_"). See 91 | // http://meta.stackoverflow.com/questions/64655/strange-wmd-bug 92 | // (granted, switching from Array() to Object() alone would have left only __proto__ 93 | // to be a problem) 94 | function SaveHash() { } 95 | SaveHash.prototype = { 96 | set: function (key, value) { 97 | this["s_" + key] = value; 98 | }, 99 | get: function (key) { 100 | return this["s_" + key]; 101 | } 102 | }; 103 | 104 | Markdown.Converter = function () { 105 | var pluginHooks = this.hooks = new HookCollection(); 106 | pluginHooks.addNoop("plainLinkText"); // given a URL that was encountered by itself (without markup), should return the link text that's to be given to this link 107 | pluginHooks.addNoop("preConversion"); // called with the orignal text as given to makeHtml. The result of this plugin hook is the actual markdown source that will be cooked 108 | pluginHooks.addNoop("postConversion"); // called with the final cooked HTML code. The result of this plugin hook is the actual output of makeHtml 109 | 110 | // 111 | // Private state of the converter instance: 112 | // 113 | 114 | // Global hashes, used by various utility routines 115 | var g_urls; 116 | var g_titles; 117 | var g_html_blocks; 118 | 119 | // Used to track when we're inside an ordered or unordered list 120 | // (see _ProcessListItems() for details): 121 | var g_list_level; 122 | 123 | this.makeHtml = function (text) { 124 | 125 | // 126 | // Main function. The order in which other subs are called here is 127 | // essential. Link and image substitutions need to happen before 128 | // _EscapeSpecialCharsWithinTagAttributes(), so that any *'s or _'s in the 129 | // and tags get encoded. 130 | // 131 | 132 | // This will only happen if makeHtml on the same converter instance is called from a plugin hook. 133 | // Don't do that. 134 | if (g_urls) 135 | throw new Error("Recursive call to converter.makeHtml"); 136 | 137 | // Create the private state objects. 138 | g_urls = new SaveHash(); 139 | g_titles = new SaveHash(); 140 | g_html_blocks = []; 141 | g_list_level = 0; 142 | 143 | text = pluginHooks.preConversion(text); 144 | 145 | // attacklab: Replace ~ with ~T 146 | // This lets us use tilde as an escape char to avoid md5 hashes 147 | // The choice of character is arbitray; anything that isn't 148 | // magic in Markdown will work. 149 | text = text.replace(/~/g, "~T"); 150 | 151 | // attacklab: Replace $ with ~D 152 | // RegExp interprets $ as a special character 153 | // when it's in a replacement string 154 | text = text.replace(/\$/g, "~D"); 155 | 156 | // Standardize line endings 157 | text = text.replace(/\r\n/g, "\n"); // DOS to Unix 158 | text = text.replace(/\r/g, "\n"); // Mac to Unix 159 | 160 | // Make sure text begins and ends with a couple of newlines: 161 | text = "\n\n" + text + "\n\n"; 162 | 163 | // Convert all tabs to spaces. 164 | text = _Detab(text); 165 | 166 | // Strip any lines consisting only of spaces and tabs. 167 | // This makes subsequent regexen easier to write, because we can 168 | // match consecutive blank lines with /\n+/ instead of something 169 | // contorted like /[ \t]*\n+/ . 170 | text = text.replace(/^[ \t]+$/mg, ""); 171 | 172 | // Turn block-level HTML blocks into hash entries 173 | text = _HashHTMLBlocks(text); 174 | 175 | // Strip link definitions, store in hashes. 176 | text = _StripLinkDefinitions(text); 177 | 178 | text = _RunBlockGamut(text); 179 | 180 | text = _UnescapeSpecialChars(text); 181 | 182 | // attacklab: Restore dollar signs 183 | text = text.replace(/~D/g, "$$"); 184 | 185 | // attacklab: Restore tildes 186 | text = text.replace(/~T/g, "~"); 187 | 188 | text = pluginHooks.postConversion(text); 189 | 190 | g_html_blocks = g_titles = g_urls = null; 191 | 192 | return text; 193 | }; 194 | 195 | function _StripLinkDefinitions(text) { 196 | // 197 | // Strips link definitions from text, stores the URLs and titles in 198 | // hash references. 199 | // 200 | 201 | // Link defs are in the form: ^[id]: url "optional title" 202 | 203 | /* 204 | text = text.replace(/ 205 | ^[ ]{0,3}\[(.+)\]: // id = $1 attacklab: g_tab_width - 1 206 | [ \t]* 207 | \n? // maybe *one* newline 208 | [ \t]* 209 | ? // url = $2 210 | (?=\s|$) // lookahead for whitespace instead of the lookbehind removed below 211 | [ \t]* 212 | \n? // maybe one newline 213 | [ \t]* 214 | ( // (potential) title = $3 215 | (\n*) // any lines skipped = $4 attacklab: lookbehind removed 216 | [ \t]+ 217 | ["(] 218 | (.+?) // title = $5 219 | [")] 220 | [ \t]* 221 | )? // title is optional 222 | (?:\n+|$) 223 | /gm, function(){...}); 224 | */ 225 | 226 | text = text.replace(/^[ ]{0,3}\[(.+)\]:[ \t]*\n?[ \t]*?(?=\s|$)[ \t]*\n?[ \t]*((\n*)["(](.+?)[")][ \t]*)?(?:\n+)/gm, 227 | function (wholeMatch, m1, m2, m3, m4, m5) { 228 | m1 = m1.toLowerCase(); 229 | g_urls.set(m1, _EncodeAmpsAndAngles(m2)); // Link IDs are case-insensitive 230 | if (m4) { 231 | // Oops, found blank lines, so it's not a title. 232 | // Put back the parenthetical statement we stole. 233 | return m3; 234 | } else if (m5) { 235 | g_titles.set(m1, m5.replace(/"/g, """)); 236 | } 237 | 238 | // Completely remove the definition from the text 239 | return ""; 240 | } 241 | ); 242 | 243 | return text; 244 | } 245 | 246 | function _HashHTMLBlocks(text) { 247 | 248 | // Hashify HTML blocks: 249 | // We only want to do this for block-level HTML tags, such as headers, 250 | // lists, and tables. That's because we still want to wrap

    s around 251 | // "paragraphs" that are wrapped in non-block-level tags, such as anchors, 252 | // phrase emphasis, and spans. The list of tags we're looking for is 253 | // hard-coded: 254 | var block_tags_a = "p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del" 255 | var block_tags_b = "p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math" 256 | 257 | // First, look for nested blocks, e.g.: 258 | //

    259 | //
    260 | // tags for inner block must be indented. 261 | //
    262 | //
    263 | // 264 | // The outermost tags must start at the left margin for this to match, and 265 | // the inner nested divs must be indented. 266 | // We need to do this before the next, more liberal match, because the next 267 | // match will start at the first `
    ` and stop at the first `
    `. 268 | 269 | // attacklab: This regex can be expensive when it fails. 270 | 271 | /* 272 | text = text.replace(/ 273 | ( // save in $1 274 | ^ // start of line (with /m) 275 | <($block_tags_a) // start tag = $2 276 | \b // word break 277 | // attacklab: hack around khtml/pcre bug... 278 | [^\r]*?\n // any number of lines, minimally matching 279 | // the matching end tag 280 | [ \t]* // trailing spaces/tabs 281 | (?=\n+) // followed by a newline 282 | ) // attacklab: there are sentinel newlines at end of document 283 | /gm,function(){...}}; 284 | */ 285 | text = text.replace(/^(<(p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del)\b[^\r]*?\n<\/\2>[ \t]*(?=\n+))/gm, hashElement); 286 | 287 | // 288 | // Now match more liberally, simply from `\n` to `\n` 289 | // 290 | 291 | /* 292 | text = text.replace(/ 293 | ( // save in $1 294 | ^ // start of line (with /m) 295 | <($block_tags_b) // start tag = $2 296 | \b // word break 297 | // attacklab: hack around khtml/pcre bug... 298 | [^\r]*? // any number of lines, minimally matching 299 | .* // the matching end tag 300 | [ \t]* // trailing spaces/tabs 301 | (?=\n+) // followed by a newline 302 | ) // attacklab: there are sentinel newlines at end of document 303 | /gm,function(){...}}; 304 | */ 305 | text = text.replace(/^(<(p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math)\b[^\r]*?.*<\/\2>[ \t]*(?=\n+)\n)/gm, hashElement); 306 | 307 | // Special case just for
    . It was easier to make a special case than 308 | // to make the other regex more complicated. 309 | 310 | /* 311 | text = text.replace(/ 312 | \n // Starting after a blank line 313 | [ ]{0,3} 314 | ( // save in $1 315 | (<(hr) // start tag = $2 316 | \b // word break 317 | ([^<>])*? 318 | \/?>) // the matching end tag 319 | [ \t]* 320 | (?=\n{2,}) // followed by a blank line 321 | ) 322 | /g,hashElement); 323 | */ 324 | text = text.replace(/\n[ ]{0,3}((<(hr)\b([^<>])*?\/?>)[ \t]*(?=\n{2,}))/g, hashElement); 325 | 326 | // Special case for standalone HTML comments: 327 | 328 | /* 329 | text = text.replace(/ 330 | \n\n // Starting after a blank line 331 | [ ]{0,3} // attacklab: g_tab_width - 1 332 | ( // save in $1 333 | -]|-[^>])(?:[^-]|-[^-])*)--) // see http://www.w3.org/TR/html-markup/syntax.html#comments and http://meta.stackoverflow.com/q/95256 335 | > 336 | [ \t]* 337 | (?=\n{2,}) // followed by a blank line 338 | ) 339 | /g,hashElement); 340 | */ 341 | text = text.replace(/\n\n[ ]{0,3}(-]|-[^>])(?:[^-]|-[^-])*)--)>[ \t]*(?=\n{2,}))/g, hashElement); 342 | 343 | // PHP and ASP-style processor instructions ( and <%...%>) 344 | 345 | /* 346 | text = text.replace(/ 347 | (?: 348 | \n\n // Starting after a blank line 349 | ) 350 | ( // save in $1 351 | [ ]{0,3} // attacklab: g_tab_width - 1 352 | (?: 353 | <([?%]) // $2 354 | [^\r]*? 355 | \2> 356 | ) 357 | [ \t]* 358 | (?=\n{2,}) // followed by a blank line 359 | ) 360 | /g,hashElement); 361 | */ 362 | text = text.replace(/(?:\n\n)([ ]{0,3}(?:<([?%])[^\r]*?\2>)[ \t]*(?=\n{2,}))/g, hashElement); 363 | 364 | return text; 365 | } 366 | 367 | function hashElement(wholeMatch, m1) { 368 | var blockText = m1; 369 | 370 | // Undo double lines 371 | blockText = blockText.replace(/^\n+/, ""); 372 | 373 | // strip trailing blank lines 374 | blockText = blockText.replace(/\n+$/g, ""); 375 | 376 | // Replace the element text with a marker ("~KxK" where x is its key) 377 | blockText = "\n\n~K" + (g_html_blocks.push(blockText) - 1) + "K\n\n"; 378 | 379 | return blockText; 380 | } 381 | 382 | function _RunBlockGamut(text, doNotUnhash) { 383 | // 384 | // These are all the transformations that form block-level 385 | // tags like paragraphs, headers, and list items. 386 | // 387 | text = _DoHeaders(text); 388 | 389 | // Do Horizontal Rules: 390 | var replacement = "
    \n"; 391 | text = text.replace(/^[ ]{0,2}([ ]?\*[ ]?){3,}[ \t]*$/gm, replacement); 392 | text = text.replace(/^[ ]{0,2}([ ]?-[ ]?){3,}[ \t]*$/gm, replacement); 393 | text = text.replace(/^[ ]{0,2}([ ]?_[ ]?){3,}[ \t]*$/gm, replacement); 394 | 395 | text = _DoLists(text); 396 | text = _DoCodeBlocks(text); 397 | text = _DoBlockQuotes(text); 398 | 399 | // We already ran _HashHTMLBlocks() before, in Markdown(), but that 400 | // was to escape raw HTML in the original Markdown source. This time, 401 | // we're escaping the markup we've just created, so that we don't wrap 402 | //

    tags around block-level tags. 403 | text = _HashHTMLBlocks(text); 404 | text = _FormParagraphs(text, doNotUnhash); 405 | 406 | return text; 407 | } 408 | 409 | function _RunSpanGamut(text) { 410 | // 411 | // These are all the transformations that occur *within* block-level 412 | // tags like paragraphs, headers, and list items. 413 | // 414 | 415 | text = _DoCodeSpans(text); 416 | text = _EscapeSpecialCharsWithinTagAttributes(text); 417 | text = _EncodeBackslashEscapes(text); 418 | 419 | // Process anchor and image tags. Images must come first, 420 | // because ![foo][f] looks like an anchor. 421 | text = _DoImages(text); 422 | text = _DoAnchors(text); 423 | 424 | // Make links out of things like `` 425 | // Must come after _DoAnchors(), because you can use < and > 426 | // delimiters in inline links like [this](). 427 | text = _DoAutoLinks(text); 428 | 429 | text = text.replace(/~P/g, "://"); // put in place to prevent autolinking; reset now 430 | 431 | text = _EncodeAmpsAndAngles(text); 432 | text = _DoItalicsAndBold(text); 433 | 434 | // Do hard breaks: 435 | text = text.replace(/ +\n/g, "
    \n"); 436 | 437 | return text; 438 | } 439 | 440 | function _EscapeSpecialCharsWithinTagAttributes(text) { 441 | // 442 | // Within tags -- meaning between < and > -- encode [\ ` * _] so they 443 | // don't conflict with their use in Markdown for code, italics and strong. 444 | // 445 | 446 | // Build a regex to find HTML tags and comments. See Friedl's 447 | // "Mastering Regular Expressions", 2nd Ed., pp. 200-201. 448 | 449 | // SE: changed the comment part of the regex 450 | 451 | var regex = /(<[a-z\/!$]("[^"]*"|'[^']*'|[^'">])*>|-]|-[^>])(?:[^-]|-[^-])*)--)>)/gi; 452 | 453 | text = text.replace(regex, function (wholeMatch) { 454 | var tag = wholeMatch.replace(/(.)<\/?code>(?=.)/g, "$1`"); 455 | tag = escapeCharacters(tag, wholeMatch.charAt(1) == "!" ? "\\`*_/" : "\\`*_"); // also escape slashes in comments to prevent autolinking there -- http://meta.stackoverflow.com/questions/95987 456 | return tag; 457 | }); 458 | 459 | return text; 460 | } 461 | 462 | function _DoAnchors(text) { 463 | // 464 | // Turn Markdown link shortcuts into XHTML
    tags. 465 | // 466 | // 467 | // First, handle reference-style links: [link text] [id] 468 | // 469 | 470 | /* 471 | text = text.replace(/ 472 | ( // wrap whole match in $1 473 | \[ 474 | ( 475 | (?: 476 | \[[^\]]*\] // allow brackets nested one level 477 | | 478 | [^\[] // or anything else 479 | )* 480 | ) 481 | \] 482 | 483 | [ ]? // one optional space 484 | (?:\n[ ]*)? // one optional newline followed by spaces 485 | 486 | \[ 487 | (.*?) // id = $3 488 | \] 489 | ) 490 | ()()()() // pad remaining backreferences 491 | /g, writeAnchorTag); 492 | */ 493 | text = text.replace(/(\[((?:\[[^\]]*\]|[^\[\]])*)\][ ]?(?:\n[ ]*)?\[(.*?)\])()()()()/g, writeAnchorTag); 494 | 495 | // 496 | // Next, inline-style links: [link text](url "optional title") 497 | // 498 | 499 | /* 500 | text = text.replace(/ 501 | ( // wrap whole match in $1 502 | \[ 503 | ( 504 | (?: 505 | \[[^\]]*\] // allow brackets nested one level 506 | | 507 | [^\[\]] // or anything else 508 | )* 509 | ) 510 | \] 511 | \( // literal paren 512 | [ \t]* 513 | () // no id, so leave $3 empty 514 | ? 521 | [ \t]* 522 | ( // $5 523 | (['"]) // quote char = $6 524 | (.*?) // Title = $7 525 | \6 // matching quote 526 | [ \t]* // ignore any spaces/tabs between closing quote and ) 527 | )? // title is optional 528 | \) 529 | ) 530 | /g, writeAnchorTag); 531 | */ 532 | 533 | text = text.replace(/(\[((?:\[[^\]]*\]|[^\[\]])*)\]\([ \t]*()?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g, writeAnchorTag); 534 | 535 | // 536 | // Last, handle reference-style shortcuts: [link text] 537 | // These must come last in case you've also got [link test][1] 538 | // or [link test](/foo) 539 | // 540 | 541 | /* 542 | text = text.replace(/ 543 | ( // wrap whole match in $1 544 | \[ 545 | ([^\[\]]+) // link text = $2; can't contain '[' or ']' 546 | \] 547 | ) 548 | ()()()()() // pad rest of backreferences 549 | /g, writeAnchorTag); 550 | */ 551 | text = text.replace(/(\[([^\[\]]+)\])()()()()()/g, writeAnchorTag); 552 | 553 | return text; 554 | } 555 | 556 | function writeAnchorTag(wholeMatch, m1, m2, m3, m4, m5, m6, m7) { 557 | if (m7 == undefined) m7 = ""; 558 | var whole_match = m1; 559 | var link_text = m2.replace(/:\/\//g, "~P"); // to prevent auto-linking withing the link. will be converted back after the auto-linker runs 560 | var link_id = m3.toLowerCase(); 561 | var url = m4; 562 | var title = m7; 563 | 564 | if (url == "") { 565 | if (link_id == "") { 566 | // lower-case and turn embedded newlines into spaces 567 | link_id = link_text.toLowerCase().replace(/ ?\n/g, " "); 568 | } 569 | url = "#" + link_id; 570 | 571 | if (g_urls.get(link_id) != undefined) { 572 | url = g_urls.get(link_id); 573 | if (g_titles.get(link_id) != undefined) { 574 | title = g_titles.get(link_id); 575 | } 576 | } 577 | else { 578 | if (whole_match.search(/\(\s*\)$/m) > -1) { 579 | // Special case for explicit empty url 580 | url = ""; 581 | } else { 582 | return whole_match; 583 | } 584 | } 585 | } 586 | url = encodeProblemUrlChars(url); 587 | url = escapeCharacters(url, "*_"); 588 | var result = ""; 597 | 598 | return result; 599 | } 600 | 601 | function _DoImages(text) { 602 | // 603 | // Turn Markdown image shortcuts into tags. 604 | // 605 | 606 | // 607 | // First, handle reference-style labeled images: ![alt text][id] 608 | // 609 | 610 | /* 611 | text = text.replace(/ 612 | ( // wrap whole match in $1 613 | !\[ 614 | (.*?) // alt text = $2 615 | \] 616 | 617 | [ ]? // one optional space 618 | (?:\n[ ]*)? // one optional newline followed by spaces 619 | 620 | \[ 621 | (.*?) // id = $3 622 | \] 623 | ) 624 | ()()()() // pad rest of backreferences 625 | /g, writeImageTag); 626 | */ 627 | text = text.replace(/(!\[(.*?)\][ ]?(?:\n[ ]*)?\[(.*?)\])()()()()/g, writeImageTag); 628 | 629 | // 630 | // Next, handle inline images: ![alt text](url "optional title") 631 | // Don't forget: encode * and _ 632 | 633 | /* 634 | text = text.replace(/ 635 | ( // wrap whole match in $1 636 | !\[ 637 | (.*?) // alt text = $2 638 | \] 639 | \s? // One optional whitespace character 640 | \( // literal paren 641 | [ \t]* 642 | () // no id, so leave $3 empty 643 | ? // src url = $4 644 | [ \t]* 645 | ( // $5 646 | (['"]) // quote char = $6 647 | (.*?) // title = $7 648 | \6 // matching quote 649 | [ \t]* 650 | )? // title is optional 651 | \) 652 | ) 653 | /g, writeImageTag); 654 | */ 655 | text = text.replace(/(!\[(.*?)\]\s?\([ \t]*()?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g, writeImageTag); 656 | 657 | return text; 658 | } 659 | 660 | function attributeEncode(text) { 661 | // unconditionally replace angle brackets here -- what ends up in an attribute (e.g. alt or title) 662 | // never makes sense to have verbatim HTML in it (and the sanitizer would totally break it) 663 | return text.replace(/>/g, ">").replace(/" + _RunSpanGamut(m1) + "\n\n"; } 722 | ); 723 | 724 | text = text.replace(/^(.+)[ \t]*\n-+[ \t]*\n+/gm, 725 | function (matchFound, m1) { return "

    " + _RunSpanGamut(m1) + "

    \n\n"; } 726 | ); 727 | 728 | // atx-style headers: 729 | // # Header 1 730 | // ## Header 2 731 | // ## Header 2 with closing hashes ## 732 | // ... 733 | // ###### Header 6 734 | // 735 | 736 | /* 737 | text = text.replace(/ 738 | ^(\#{1,6}) // $1 = string of #'s 739 | [ \t]* 740 | (.+?) // $2 = Header text 741 | [ \t]* 742 | \#* // optional closing #'s (not counted) 743 | \n+ 744 | /gm, function() {...}); 745 | */ 746 | 747 | text = text.replace(/^(\#{1,6})[ \t]*(.+?)[ \t]*\#*\n+/gm, 748 | function (wholeMatch, m1, m2) { 749 | var h_level = m1.length; 750 | return "" + _RunSpanGamut(m2) + "\n\n"; 751 | } 752 | ); 753 | 754 | return text; 755 | } 756 | 757 | function _DoLists(text) { 758 | // 759 | // Form HTML ordered (numbered) and unordered (bulleted) lists. 760 | // 761 | 762 | // attacklab: add sentinel to hack around khtml/safari bug: 763 | // http://bugs.webkit.org/show_bug.cgi?id=11231 764 | text += "~0"; 765 | 766 | // Re-usable pattern to match any entirel ul or ol list: 767 | 768 | /* 769 | var whole_list = / 770 | ( // $1 = whole list 771 | ( // $2 772 | [ ]{0,3} // attacklab: g_tab_width - 1 773 | ([*+-]|\d+[.]) // $3 = first list item marker 774 | [ \t]+ 775 | ) 776 | [^\r]+? 777 | ( // $4 778 | ~0 // sentinel for workaround; should be $ 779 | | 780 | \n{2,} 781 | (?=\S) 782 | (?! // Negative lookahead for another list item marker 783 | [ \t]* 784 | (?:[*+-]|\d+[.])[ \t]+ 785 | ) 786 | ) 787 | ) 788 | /g 789 | */ 790 | var whole_list = /^(([ ]{0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm; 791 | 792 | if (g_list_level) { 793 | text = text.replace(whole_list, function (wholeMatch, m1, m2) { 794 | var list = m1; 795 | var list_type = (m2.search(/[*+-]/g) > -1) ? "ul" : "ol"; 796 | 797 | var result = _ProcessListItems(list, list_type); 798 | 799 | // Trim any trailing whitespace, to put the closing `` 800 | // up on the preceding line, to get it past the current stupid 801 | // HTML block parser. This is a hack to work around the terrible 802 | // hack that is the HTML block parser. 803 | result = result.replace(/\s+$/, ""); 804 | result = "<" + list_type + ">" + result + "\n"; 805 | return result; 806 | }); 807 | } else { 808 | whole_list = /(\n\n|^\n?)(([ ]{0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/g; 809 | text = text.replace(whole_list, function (wholeMatch, m1, m2, m3) { 810 | var runup = m1; 811 | var list = m2; 812 | 813 | var list_type = (m3.search(/[*+-]/g) > -1) ? "ul" : "ol"; 814 | var result = _ProcessListItems(list, list_type); 815 | result = runup + "<" + list_type + ">\n" + result + "\n"; 816 | return result; 817 | }); 818 | } 819 | 820 | // attacklab: strip sentinel 821 | text = text.replace(/~0/, ""); 822 | 823 | return text; 824 | } 825 | 826 | var _listItemMarkers = { ol: "\\d+[.]", ul: "[*+-]" }; 827 | 828 | function _ProcessListItems(list_str, list_type) { 829 | // 830 | // Process the contents of a single ordered or unordered list, splitting it 831 | // into individual list items. 832 | // 833 | // list_type is either "ul" or "ol". 834 | 835 | // The $g_list_level global keeps track of when we're inside a list. 836 | // Each time we enter a list, we increment it; when we leave a list, 837 | // we decrement. If it's zero, we're not in a list anymore. 838 | // 839 | // We do this because when we're not inside a list, we want to treat 840 | // something like this: 841 | // 842 | // I recommend upgrading to version 843 | // 8. Oops, now this line is treated 844 | // as a sub-list. 845 | // 846 | // As a single paragraph, despite the fact that the second line starts 847 | // with a digit-period-space sequence. 848 | // 849 | // Whereas when we're inside a list (or sub-list), that line will be 850 | // treated as the start of a sub-list. What a kludge, huh? This is 851 | // an aspect of Markdown's syntax that's hard to parse perfectly 852 | // without resorting to mind-reading. Perhaps the solution is to 853 | // change the syntax rules such that sub-lists must start with a 854 | // starting cardinal number; e.g. "1." or "a.". 855 | 856 | g_list_level++; 857 | 858 | // trim trailing blank lines: 859 | list_str = list_str.replace(/\n{2,}$/, "\n"); 860 | 861 | // attacklab: add sentinel to emulate \z 862 | list_str += "~0"; 863 | 864 | // In the original attacklab showdown, list_type was not given to this function, and anything 865 | // that matched /[*+-]|\d+[.]/ would just create the next
  • , causing this mismatch: 866 | // 867 | // Markdown rendered by WMD rendered by MarkdownSharp 868 | // ------------------------------------------------------------------ 869 | // 1. first 1. first 1. first 870 | // 2. second 2. second 2. second 871 | // - third 3. third * third 872 | // 873 | // We changed this to behave identical to MarkdownSharp. This is the constructed RegEx, 874 | // with {MARKER} being one of \d+[.] or [*+-], depending on list_type: 875 | 876 | /* 877 | list_str = list_str.replace(/ 878 | (^[ \t]*) // leading whitespace = $1 879 | ({MARKER}) [ \t]+ // list marker = $2 880 | ([^\r]+? // list item text = $3 881 | (\n+) 882 | ) 883 | (?= 884 | (~0 | \2 ({MARKER}) [ \t]+) 885 | ) 886 | /gm, function(){...}); 887 | */ 888 | 889 | var marker = _listItemMarkers[list_type]; 890 | var re = new RegExp("(^[ \\t]*)(" + marker + ")[ \\t]+([^\\r]+?(\\n+))(?=(~0|\\1(" + marker + ")[ \\t]+))", "gm"); 891 | var last_item_had_a_double_newline = false; 892 | list_str = list_str.replace(re, 893 | function (wholeMatch, m1, m2, m3) { 894 | var item = m3; 895 | var leading_space = m1; 896 | var ends_with_double_newline = /\n\n$/.test(item); 897 | var contains_double_newline = ends_with_double_newline || item.search(/\n{2,}/) > -1; 898 | 899 | if (contains_double_newline || last_item_had_a_double_newline) { 900 | item = _RunBlockGamut(_Outdent(item), /* doNotUnhash = */true); 901 | } 902 | else { 903 | // Recursion for sub-lists: 904 | item = _DoLists(_Outdent(item)); 905 | item = item.replace(/\n$/, ""); // chomp(item) 906 | item = _RunSpanGamut(item); 907 | } 908 | last_item_had_a_double_newline = ends_with_double_newline; 909 | return "
  • " + item + "
  • \n"; 910 | } 911 | ); 912 | 913 | // attacklab: strip sentinel 914 | list_str = list_str.replace(/~0/g, ""); 915 | 916 | g_list_level--; 917 | return list_str; 918 | } 919 | 920 | function _DoCodeBlocks(text) { 921 | // 922 | // Process Markdown `
    ` blocks.
     923 | 			//  
     924 | 
     925 | 			/*
     926 | 			text = text.replace(/
     927 | 				(?:\n\n|^)
     928 | 				(                               // $1 = the code block -- one or more lines, starting with a space/tab
     929 | 					(?:
     930 | 						(?:[ ]{4}|\t)           // Lines must start with a tab or a tab-width of spaces - attacklab: g_tab_width
     931 | 						.*\n+
     932 | 					)+
     933 | 				)
     934 | 				(\n*[ ]{0,3}[^ \t\n]|(?=~0))    // attacklab: g_tab_width
     935 | 			/g ,function(){...});
     936 | 			*/
     937 | 
     938 | 			// attacklab: sentinel workarounds for lack of \A and \Z, safari\khtml bug
     939 | 			text += "~0";
     940 | 
     941 | 			text = text.replace(/(?:\n\n|^)((?:(?:[ ]{4}|\t).*\n+)+)(\n*[ ]{0,3}[^ \t\n]|(?=~0))/g,
     942 | 				function (wholeMatch, m1, m2) {
     943 | 					var codeblock = m1;
     944 | 					var nextChar = m2;
     945 | 
     946 | 					codeblock = _EncodeCode(_Outdent(codeblock));
     947 | 					codeblock = _Detab(codeblock);
     948 | 					codeblock = codeblock.replace(/^\n+/g, ""); // trim leading newlines
     949 | 					codeblock = codeblock.replace(/\n+$/g, ""); // trim trailing whitespace
     950 | 
     951 | 					codeblock = '
    ' + codeblock + '\n
    '; 952 | 953 | return "\n\n" + codeblock + "\n\n" + nextChar; 954 | } 955 | ); 956 | 957 | // attacklab: strip sentinel 958 | text = text.replace(/~0/, ""); 959 | 960 | return text; 961 | } 962 | 963 | function hashBlock(text) { 964 | text = text.replace(/(^\n+|\n+$)/g, ""); 965 | return "\n\n~K" + (g_html_blocks.push(text) - 1) + "K\n\n"; 966 | } 967 | 968 | function _DoCodeSpans(text) { 969 | // 970 | // * Backtick quotes are used for spans. 971 | // 972 | // * You can use multiple backticks as the delimiters if you want to 973 | // include literal backticks in the code span. So, this input: 974 | // 975 | // Just type ``foo `bar` baz`` at the prompt. 976 | // 977 | // Will translate to: 978 | // 979 | //

    Just type foo `bar` baz at the prompt.

    980 | // 981 | // There's no arbitrary limit to the number of backticks you 982 | // can use as delimters. If you need three consecutive backticks 983 | // in your code, use four for delimiters, etc. 984 | // 985 | // * You can use spaces to get literal backticks at the edges: 986 | // 987 | // ... type `` `bar` `` ... 988 | // 989 | // Turns to: 990 | // 991 | // ... type `bar` ... 992 | // 993 | 994 | /* 995 | text = text.replace(/ 996 | (^|[^\\]) // Character before opening ` can't be a backslash 997 | (`+) // $2 = Opening run of ` 998 | ( // $3 = The code block 999 | [^\r]*? 1000 | [^`] // attacklab: work around lack of lookbehind 1001 | ) 1002 | \2 // Matching closer 1003 | (?!`) 1004 | /gm, function(){...}); 1005 | */ 1006 | 1007 | text = text.replace(/(^|[^\\])(`+)([^\r]*?[^`])\2(?!`)/gm, 1008 | function (wholeMatch, m1, m2, m3, m4) { 1009 | var c = m3; 1010 | c = c.replace(/^([ \t]*)/g, ""); // leading whitespace 1011 | c = c.replace(/[ \t]*$/g, ""); // trailing whitespace 1012 | c = _EncodeCode(c); 1013 | c = c.replace(/:\/\//g, "~P"); // to prevent auto-linking. Not necessary in code *blocks*, but in code spans. Will be converted back after the auto-linker runs. 1014 | return m1 + "" + c + ""; 1015 | } 1016 | ); 1017 | 1018 | return text; 1019 | } 1020 | 1021 | function _EncodeCode(text) { 1022 | // 1023 | // Encode/escape certain characters inside Markdown code runs. 1024 | // The point is that in code, these characters are literals, 1025 | // and lose their special Markdown meanings. 1026 | // 1027 | // Encode all ampersands; HTML entities are not 1028 | // entities within a Markdown code span. 1029 | text = text.replace(/&/g, "&"); 1030 | 1031 | // Do the angle bracket song and dance: 1032 | text = text.replace(//g, ">"); 1034 | 1035 | // Now, escape characters that are magic in Markdown: 1036 | text = escapeCharacters(text, "\*_{}[]\\", false); 1037 | 1038 | // jj the line above breaks this: 1039 | //--- 1040 | 1041 | //* Item 1042 | 1043 | // 1. Subitem 1044 | 1045 | // special char: * 1046 | //--- 1047 | 1048 | return text; 1049 | } 1050 | 1051 | function _DoItalicsAndBold(text) { 1052 | 1053 | // must go first: 1054 | text = text.replace(/([\W_]|^)(\*\*|__)(?=\S)([^\r]*?\S[\*_]*)\2([\W_]|$)/g, 1055 | "$1$3$4"); 1056 | 1057 | text = text.replace(/([\W_]|^)(\*|_)(?=\S)([^\r\*_]*?\S)\2([\W_]|$)/g, 1058 | "$1$3$4"); 1059 | 1060 | return text; 1061 | } 1062 | 1063 | function _DoBlockQuotes(text) { 1064 | 1065 | /* 1066 | text = text.replace(/ 1067 | ( // Wrap whole match in $1 1068 | ( 1069 | ^[ \t]*>[ \t]? // '>' at the start of a line 1070 | .+\n // rest of the first line 1071 | (.+\n)* // subsequent consecutive lines 1072 | \n* // blanks 1073 | )+ 1074 | ) 1075 | /gm, function(){...}); 1076 | */ 1077 | 1078 | text = text.replace(/((^[ \t]*>[ \t]?.+\n(.+\n)*\n*)+)/gm, 1079 | function (wholeMatch, m1) { 1080 | var bq = m1; 1081 | 1082 | // attacklab: hack around Konqueror 3.5.4 bug: 1083 | // "----------bug".replace(/^-/g,"") == "bug" 1084 | 1085 | bq = bq.replace(/^[ \t]*>[ \t]?/gm, "~0"); // trim one level of quoting 1086 | 1087 | // attacklab: clean up hack 1088 | bq = bq.replace(/~0/g, ""); 1089 | 1090 | bq = bq.replace(/^[ \t]+$/gm, ""); // trim whitespace-only lines 1091 | bq = _RunBlockGamut(bq); // recurse 1092 | 1093 | bq = bq.replace(/(^|\n)/g, "$1 "); 1094 | // These leading spaces screw with
     content, so we need to fix that:
    1095 | 					bq = bq.replace(
    1096 | 							/(\s*
    [^\r]+?<\/pre>)/gm,
    1097 | 						function (wholeMatch, m1) {
    1098 | 							var pre = m1;
    1099 | 							// attacklab: hack around Konqueror 3.5.4 bug:
    1100 | 							pre = pre.replace(/^  /mg, "~0");
    1101 | 							pre = pre.replace(/~0/g, "");
    1102 | 							return pre;
    1103 | 						});
    1104 | 
    1105 | 					return hashBlock("
    \n" + bq + "\n
    "); 1106 | } 1107 | ); 1108 | return text; 1109 | } 1110 | 1111 | function _FormParagraphs(text, doNotUnhash) { 1112 | // 1113 | // Params: 1114 | // $text - string to process with html

    tags 1115 | // 1116 | 1117 | // Strip leading and trailing lines: 1118 | text = text.replace(/^\n+/g, ""); 1119 | text = text.replace(/\n+$/g, ""); 1120 | 1121 | var grafs = text.split(/\n{2,}/g); 1122 | var grafsOut = []; 1123 | 1124 | var markerRe = /~K(\d+)K/; 1125 | 1126 | // 1127 | // Wrap

    tags. 1128 | // 1129 | var end = grafs.length; 1130 | for (var i = 0; i < end; i++) { 1131 | var str = grafs[i]; 1132 | 1133 | // if this is an HTML marker, copy it 1134 | if (markerRe.test(str)) { 1135 | grafsOut.push(str); 1136 | } 1137 | else if (/\S/.test(str)) { 1138 | str = _RunSpanGamut(str); 1139 | str = str.replace(/^([ \t]*)/g, "

    "); 1140 | str += "

    " 1141 | grafsOut.push(str); 1142 | } 1143 | 1144 | } 1145 | // 1146 | // Unhashify HTML blocks 1147 | // 1148 | if (!doNotUnhash) { 1149 | end = grafsOut.length; 1150 | for (var i = 0; i < end; i++) { 1151 | var foundAny = true; 1152 | while (foundAny) { // we may need several runs, since the data may be nested 1153 | foundAny = false; 1154 | grafsOut[i] = grafsOut[i].replace(/~K(\d+)K/g, function (wholeMatch, id) { 1155 | foundAny = true; 1156 | return g_html_blocks[id]; 1157 | }); 1158 | } 1159 | } 1160 | } 1161 | return grafsOut.join("\n\n"); 1162 | } 1163 | 1164 | function _EncodeAmpsAndAngles(text) { 1165 | // Smart processing for ampersands and angle brackets that need to be encoded. 1166 | 1167 | // Ampersand-encoding based entirely on Nat Irons's Amputator MT plugin: 1168 | // http://bumppo.net/projects/amputator/ 1169 | text = text.replace(/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/g, "&"); 1170 | 1171 | // Encode naked <'s 1172 | text = text.replace(/<(?![a-z\/?\$!])/gi, "<"); 1173 | 1174 | return text; 1175 | } 1176 | 1177 | function _EncodeBackslashEscapes(text) { 1178 | // 1179 | // Parameter: String. 1180 | // Returns: The string, with after processing the following backslash 1181 | // escape sequences. 1182 | // 1183 | 1184 | // attacklab: The polite way to do this is with the new 1185 | // escapeCharacters() function: 1186 | // 1187 | // text = escapeCharacters(text,"\\",true); 1188 | // text = escapeCharacters(text,"`*_{}[]()>#+-.!",true); 1189 | // 1190 | // ...but we're sidestepping its use of the (slow) RegExp constructor 1191 | // as an optimization for Firefox. This function gets called a LOT. 1192 | 1193 | text = text.replace(/\\(\\)/g, escapeCharacters_callback); 1194 | text = text.replace(/\\([`*_{}\[\]()>#+-.!])/g, escapeCharacters_callback); 1195 | return text; 1196 | } 1197 | 1198 | function _DoAutoLinks(text) { 1199 | 1200 | // note that at this point, all other URL in the text are already hyperlinked as
    1201 | // *except* for the case 1202 | 1203 | // automatically add < and > around unadorned raw hyperlinks 1204 | // must be preceded by space/BOF and followed by non-word/EOF character 1205 | text = text.replace(/(^|\s)(https?|ftp)(:\/\/[-A-Z0-9+&@#\/%?=~_|\[\]\(\)!:,\.;]*[-A-Z0-9+&@#\/%=~_|\[\]])($|\W)/gi, "$1<$2$3>$4"); 1206 | 1207 | // autolink anything like 1208 | 1209 | var replacer = function (wholematch, m1) { return "" + pluginHooks.plainLinkText(m1) + ""; } 1210 | text = text.replace(/<((https?|ftp):[^'">\s]+)>/gi, replacer); 1211 | 1212 | // Email addresses: 1213 | /* 1214 | text = text.replace(/ 1215 | < 1216 | (?:mailto:)? 1217 | ( 1218 | [-.\w]+ 1219 | \@ 1220 | [-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+ 1221 | ) 1222 | > 1223 | /gi, _DoAutoLinks_callback()); 1224 | */ 1225 | 1226 | var email_replacer = function(wholematch, m1) { 1227 | var mailto = 'mailto:' 1228 | var link 1229 | var email 1230 | if (m1.substring(0, mailto.length) != mailto){ 1231 | link = mailto + m1; 1232 | email = m1; 1233 | } else { 1234 | link = m1; 1235 | email = m1.substring(mailto.length, m1.length); 1236 | } 1237 | return "" + pluginHooks.plainLinkText(email) + ""; 1238 | } 1239 | text = text.replace(/<((?:mailto:)?([-.\w]+\@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+))>/gi, email_replacer); 1240 | 1241 | return text; 1242 | } 1243 | 1244 | function _UnescapeSpecialChars(text) { 1245 | // 1246 | // Swap back in all the special characters we've hidden. 1247 | // 1248 | text = text.replace(/~E(\d+)E/g, 1249 | function (wholeMatch, m1) { 1250 | var charCodeToReplace = parseInt(m1); 1251 | return String.fromCharCode(charCodeToReplace); 1252 | } 1253 | ); 1254 | return text; 1255 | } 1256 | 1257 | function _Outdent(text) { 1258 | // 1259 | // Remove one level of line-leading tabs or spaces 1260 | // 1261 | 1262 | // attacklab: hack around Konqueror 3.5.4 bug: 1263 | // "----------bug".replace(/^-/g,"") == "bug" 1264 | 1265 | text = text.replace(/^(\t|[ ]{1,4})/gm, "~0"); // attacklab: g_tab_width 1266 | 1267 | // attacklab: clean up hack 1268 | text = text.replace(/~0/g, "") 1269 | 1270 | return text; 1271 | } 1272 | 1273 | function _Detab(text) { 1274 | if (!/\t/.test(text)) 1275 | return text; 1276 | 1277 | var spaces = [" ", " ", " ", " "], 1278 | skew = 0, 1279 | v; 1280 | 1281 | return text.replace(/[\n\t]/g, function (match, offset) { 1282 | if (match === "\n") { 1283 | skew = offset + 1; 1284 | return match; 1285 | } 1286 | v = (offset - skew) % 4; 1287 | skew = offset + 1; 1288 | return spaces[v]; 1289 | }); 1290 | } 1291 | 1292 | // 1293 | // attacklab: Utility functions 1294 | // 1295 | 1296 | var _problemUrlChars = /(?:["'*()[\]:]|~D)/g; 1297 | 1298 | // hex-encodes some unusual "problem" chars in URLs to avoid URL detection problems 1299 | function encodeProblemUrlChars(url) { 1300 | if (!url) 1301 | return ""; 1302 | 1303 | var len = url.length; 1304 | 1305 | return url.replace(_problemUrlChars, function (match, offset) { 1306 | if (match == "~D") // escape for dollar 1307 | return "%24"; 1308 | if (match == ":") { 1309 | if (offset == len - 1 || /[0-9\/]/.test(url.charAt(offset + 1))) 1310 | return ":"; 1311 | if (url.substring(0, 'mailto:'.length) === 'mailto:') 1312 | return ":"; 1313 | if (url.substring(0, 'magnet:'.length) === 'magnet:') 1314 | return ":"; 1315 | } 1316 | return "%" + match.charCodeAt(0).toString(16); 1317 | }); 1318 | } 1319 | 1320 | 1321 | function escapeCharacters(text, charsToEscape, afterBackslash) { 1322 | // First we have to escape the escape characters so that 1323 | // we can build a character class out of them 1324 | var regexString = "([" + charsToEscape.replace(/([\[\]\\])/g, "\\$1") + "])"; 1325 | 1326 | if (afterBackslash) { 1327 | regexString = "\\\\" + regexString; 1328 | } 1329 | 1330 | var regex = new RegExp(regexString, "g"); 1331 | text = text.replace(regex, escapeCharacters_callback); 1332 | 1333 | return text; 1334 | } 1335 | 1336 | 1337 | function escapeCharacters_callback(wholeMatch, m1) { 1338 | var charCodeToEscape = m1.charCodeAt(0); 1339 | return "~E" + charCodeToEscape + "E"; 1340 | } 1341 | 1342 | }; // end of the Markdown.Converter constructor 1343 | 1344 | })(); 1345 | --------------------------------------------------------------------------------