├── .gitignore ├── LICENSE ├── README.md ├── contributors.txt ├── core.py ├── modules ├── __init__.py └── exportgraph.py ├── output └── .keep ├── pandora.py ├── requirements.txt ├── static ├── css │ ├── bootstrap-table.min.css │ ├── bootstrap.css │ ├── bootstrap.min.css │ ├── custom.css │ └── font-awesome.min.css ├── fonts │ ├── FontAwesome.otf │ ├── fontawesome-webfont.eot │ ├── fontawesome-webfont.svg │ ├── fontawesome-webfont.ttf │ ├── fontawesome-webfont.woff │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.svg │ ├── glyphicons-halflings-regular.ttf │ └── glyphicons-halflings-regular.woff ├── images │ └── banner.png └── js │ ├── bootstrap-filestyle.min.js │ ├── bootstrap-table-export.js │ ├── bootstrap-table.min.js │ ├── bootstrap.js │ ├── jquery-1.11.2.min.js │ ├── jspdf │ ├── jspdf.js │ └── libs │ │ ├── base64.js │ │ └── sprintf.js │ ├── npm.js │ └── tableExport.js ├── templates ├── 404.html ├── graph.html ├── home.html ├── partials │ ├── footer.html │ ├── header.html │ └── navbar.html └── popup-links.html └── webserver.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Python template 3 | # Byte-compiled / optimized / DLL files 4 | __pycache__/ 5 | *.py[cod] 6 | *$py.class 7 | 8 | # C extensions 9 | *.so 10 | 11 | # Distribution / packaging 12 | .Python 13 | env/ 14 | build/ 15 | develop-eggs/ 16 | dist/ 17 | downloads/ 18 | eggs/ 19 | .eggs/ 20 | lib/ 21 | lib64/ 22 | parts/ 23 | sdist/ 24 | var/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .coverage 43 | .coverage.* 44 | .cache 45 | nosetests.xml 46 | coverage.xml 47 | *,cover 48 | 49 | # Translations 50 | *.mo 51 | *.pot 52 | 53 | # Django stuff: 54 | *.log 55 | 56 | # Sphinx documentation 57 | docs/_build/ 58 | 59 | # PyBuilder 60 | target/ 61 | 62 | .DS_Store 63 | .idea/ 64 | output/*.json -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 SneakersInc 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Pandora (BETA) 2 | Export Maltego Graphs to JSON format 3 | This means you can import them into Splunk, ElasticSearch or anything else that accepts JSON 4 | 5 | 6 | # Command Line Export 7 | To run a simple export you can use the command line as below 8 | *./pandora ExampleGraph.mtgz* 9 | This will save the new json file to *output/ExampleGraph.json* 10 | 11 | # Web Interface 12 | You can also use the web interface to export and view the output. To start the web server just run: 13 | *./webserver.py* 14 | This will start a small Flask web server on port 5000 15 | 16 | This is just the beginning of the project so more updates will come. 17 | -------------------------------------------------------------------------------- /contributors.txt: -------------------------------------------------------------------------------- 1 | Adam Maxwell (@catalyst256) 2 | Nadeem Douba (@ndouba) Creator of the AWESOME Canari Framework - Original graph export code (before I messed it up) -------------------------------------------------------------------------------- /core.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import json 4 | from modules.exportgraph import mtgx2json 5 | import glob 6 | import os.path 7 | import time 8 | 9 | folder = 'output/' 10 | 11 | 12 | def list_graphs(): 13 | filelist = [] 14 | files = glob.glob('output/*.json') 15 | for i in files: 16 | record = i.split('/')[-1], time.ctime(os.path.getctime(i)) 17 | filelist.append(record) 18 | return filelist 19 | 20 | 21 | def graph_json(graph, filename): 22 | filename = str(filename).split('/')[-1].replace('.mtgx', '.json', 1) 23 | path = '%s%s' % (folder, filename) 24 | g = mtgx2json(graph) 25 | f = open(path, 'a') 26 | f.write(json.dumps(g, indent=4)) 27 | f.close() 28 | -------------------------------------------------------------------------------- /modules/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SneakersInc/Pandora/b09528f9a6f498b9851d7c8d2ba6a125f2f6655c/modules/__init__.py -------------------------------------------------------------------------------- /modules/exportgraph.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Original code was created by Nadeem Douba as part of the Canari Framework 4 | 5 | 6 | from collections import OrderedDict 7 | from xml.etree.cElementTree import XML 8 | from zipfile import ZipFile 9 | 10 | 11 | def mtgx2json(graph): 12 | zipfile = ZipFile(graph) 13 | graphs = filter(lambda x: x.endswith('.graphml'), zipfile.namelist()) 14 | for f in graphs: 15 | multikeys = [] 16 | xml = XML(zipfile.open(f).read()) 17 | links = {} 18 | for edge in xml.findall('{http://graphml.graphdrawing.org/xmlns}graph/' 19 | '{http://graphml.graphdrawing.org/xmlns}edge'): 20 | src = edge.get('source') 21 | dst = edge.get('target') 22 | if src not in links: 23 | links[src] = dict(in_=[], out=[]) 24 | if dst not in links: 25 | links[dst] = dict(in_=[], out=[]) 26 | links[src]['out'].append(dst) 27 | links[dst]['in_'].append(src) 28 | 29 | for node in xml.findall('{http://graphml.graphdrawing.org/xmlns}graph/' 30 | '{http://graphml.graphdrawing.org/xmlns}node'): 31 | 32 | node_id = node.get('id') 33 | node = node.find('{http://graphml.graphdrawing.org/xmlns}data/' 34 | '{http://maltego.paterva.com/xml/mtgx}MaltegoEntity') 35 | 36 | record = OrderedDict({'NodeID': node_id, 'EntityType': node.get('type').strip()}) 37 | props = {'Data': {}} 38 | for prop in node.findall('{http://maltego.paterva.com/xml/mtgx}Properties/' 39 | '{http://maltego.paterva.com/xml/mtgx}Property'): 40 | value = prop.find('{http://maltego.paterva.com/xml/mtgx}Value').text or '' 41 | entity_prop = {prop.get('displayName'): value.strip()} 42 | props['Data'].update(entity_prop) 43 | record.update(props) 44 | s = ' - '.join(['%s: %s' % (key, value) for (key, value) in record['Data'].items()]) 45 | record.pop('Data') 46 | data = {'Data': s} 47 | record.update(data) 48 | link = {'Links': {}} 49 | i_link = {'Incoming': links.get(node_id, {}).get('in_', 0)} 50 | link['Links'].update(i_link) 51 | o_link = {'Outgoing': links.get(node_id, {}).get('out', 0)} 52 | link['Links'].update(o_link) 53 | record.update(link) 54 | multikeys.append(record) 55 | return multikeys 56 | -------------------------------------------------------------------------------- /output/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SneakersInc/Pandora/b09528f9a6f498b9851d7c8d2ba6a125f2f6655c/output/.keep -------------------------------------------------------------------------------- /pandora.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from modules.exportgraph import mtgx2json 4 | import sys 5 | import json 6 | 7 | folder = 'output/' 8 | 9 | if len(sys.argv) != 2: 10 | print 'Usage: ./pandora testgraph.mtgz' 11 | sys.exit(1) 12 | 13 | g = sys.argv[1] 14 | 15 | 16 | def graph_json(graph): 17 | print '[+] Starting Graph export....' 18 | filename = str(graph).split('/')[-1].replace('.mtgx', '.json', 1) 19 | path = '%s%s' % (folder, filename) 20 | print '[-] Saving graph to %s' % path 21 | g = mtgx2json(graph) 22 | f = open(path, 'a') 23 | f.write(json.dumps(g, indent=4)) 24 | f.close() 25 | print '[!] Graph export complete' 26 | 27 | if __name__ == '__main__': 28 | graph_json(g) 29 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | Flask 2 | -------------------------------------------------------------------------------- /static/css/bootstrap-table.min.css: -------------------------------------------------------------------------------- 1 | /* 2 | * bootstrap-table - v1.5.0 - 2014-12-12 3 | * https://github.com/wenzhixin/bootstrap-table 4 | * Copyright (c) 2014 zhixin wen 5 | * Licensed MIT License 6 | */ 7 | 8 | .bootstrap-table .table{margin-bottom:0!important;border-bottom:1px solid #ddd;border-collapse:collapse!important;border-radius:1px}.fixed-table-container{position:relative;clear:both;border:1px solid #ddd;border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px}.fixed-table-header{overflow:hidden;border-radius:4px 4px 0 0;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0}.fixed-table-body{overflow-x:auto;overflow-y:auto;height:100%}.fixed-table-container table{width:100%}.fixed-table-container thead th{height:0;padding:0;margin:0;border-left:1px solid #ddd}.fixed-table-container thead th:first-child{border-left:none;border-top-left-radius:4px;-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px}.fixed-table-container thead th .th-inner{padding:8px;line-height:24px;vertical-align:top;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fixed-table-container thead th .sortable{cursor:pointer}.fixed-table-container tbody td{border-left:1px solid #ddd}.fixed-table-container tbody tr:first-child td{border-top:none}.fixed-table-container tbody td:first-child{border-left:none}.fixed-table-container tbody .selected td{background-color:#f5f5f5}.fixed-table-container .bs-checkbox{text-align:center}.fixed-table-container .bs-checkbox .th-inner{padding:8px 0}.fixed-table-container input[type=checkbox],.fixed-table-container input[type=radio]{margin:0 auto!important}.fixed-table-container .no-records-found{text-align:center}.fixed-table-pagination .pagination,.fixed-table-pagination .pagination-detail{margin-top:10px;margin-bottom:10px}.fixed-table-pagination .pagination a{padding:6px 12px;line-height:1.428571429}.fixed-table-pagination .pagination-info{line-height:34px;margin-right:5px}.fixed-table-pagination .btn-group{position:relative;display:inline-block;vertical-align:middle}.fixed-table-pagination .dropup .dropdown-menu{margin-bottom:0}.fixed-table-pagination .page-list{display:inline-block}.fixed-table-toolbar .columns-left{margin-right:5px}.fixed-table-toolbar .columns-right{margin-left:5px}.fixed-table-toolbar .columns label{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.428571429}.fixed-table-toolbar .bars,.fixed-table-toolbar .columns,.fixed-table-toolbar .search{position:relative;margin-top:10px;margin-bottom:10px;line-height:34px}.fixed-table-pagination li.disabled a{pointer-events:none;cursor:default}.fixed-table-loading{display:none;position:absolute;top:42px;right:0;bottom:0;left:0;z-index:99;background-color:#fff;text-align:center}.fixed-table-body .card-view .title{font-weight:700;display:inline-block;min-width:30%;text-align:left!important}.fixed-table-body thead th .th-inner{box-sizing:border-box}.table td,.table th{vertical-align:middle;box-sizing:border-box}.fixed-table-toolbar .dropdown-menu{text-align:left;max-height:300px;overflow:auto}.fixed-table-toolbar .btn-group>.btn-group{display:inline-block;margin-left:-1px!important}.fixed-table-toolbar .btn-group>.btn-group>.btn{border-radius:0}.fixed-table-toolbar .btn-group>.btn-group:first-child>.btn{border-top-left-radius:4px;border-bottom-left-radius:4px}.fixed-table-toolbar .btn-group>.btn-group:last-child>.btn{border-top-right-radius:4px;border-bottom-right-radius:4px}.bootstrap-table .table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.bootstrap-table .table thead>tr>th{padding:0;margin:0}.pull-right .dropdown-menu{right:0;left:auto}p.fixed-table-scroll-inner{width:100%;height:200px}div.fixed-table-scroll-outer{top:0;left:0;visibility:hidden;width:200px;height:150px;overflow:hidden} -------------------------------------------------------------------------------- /static/css/custom.css: -------------------------------------------------------------------------------- 1 | .masthead{ 2 | height:198px; 3 | background-position: left top; 4 | background-image:url("../images/banner.png"); 5 | background-repeat:no-repeat; 6 | background-color: #4c6275 7 | } 8 | 9 | /* Misc 10 | -------------------------------------------------- */ 11 | .mono { 12 | font-family: monospace; 13 | } 14 | 15 | .top-buffer { margin-top:20px; } 16 | 17 | .btn-file { 18 | position: relative; 19 | overflow: hidden; 20 | } 21 | 22 | .btn-file input[type=file] { 23 | position: absolute; 24 | top: 0; 25 | right: 0; 26 | min-width: 100%; 27 | min-height: 100%; 28 | font-size: 100px; 29 | text-align: right; 30 | filter: alpha(opacity=0); 31 | opacity: 0; 32 | outline: none; 33 | background: white; 34 | cursor: inherit; 35 | display: block; 36 | } 37 | 38 | /* Side Navigation */ 39 | 40 | @media(min-width:768px) { 41 | .side-nav { 42 | position: fixed; 43 | top: 51px; 44 | left: 225px; 45 | width: 225px; 46 | margin-left: -225px; 47 | border: none; 48 | border-radius: 0; 49 | overflow-y: auto; 50 | background-color: #222; 51 | } 52 | 53 | .side-nav>li>a { 54 | width: 225px; 55 | } 56 | 57 | .side-nav li a:hover, 58 | .side-nav li a:focus { 59 | outline: none; 60 | background-color: #000 !important; 61 | } 62 | } 63 | 64 | .side-nav>li>ul { 65 | padding: 0; 66 | } 67 | 68 | .side-nav>li>ul>li>a { 69 | display: block; 70 | padding: 10px 15px 10px 38px; 71 | text-decoration: none; 72 | color: #999; 73 | } 74 | 75 | .side-nav>li>ul>li>a:hover { 76 | color: #fff; 77 | } 78 | 79 | -------------------------------------------------------------------------------- /static/css/font-awesome.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome 4.2.0 by @davegandy - http://fontawesome.io - @fontawesome 3 | * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) 4 | */@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.2.0');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.2.0') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff?v=4.2.0') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.2.0') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.2.0#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1);-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1);-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"} -------------------------------------------------------------------------------- /static/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SneakersInc/Pandora/b09528f9a6f498b9851d7c8d2ba6a125f2f6655c/static/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /static/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SneakersInc/Pandora/b09528f9a6f498b9851d7c8d2ba6a125f2f6655c/static/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /static/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SneakersInc/Pandora/b09528f9a6f498b9851d7c8d2ba6a125f2f6655c/static/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /static/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SneakersInc/Pandora/b09528f9a6f498b9851d7c8d2ba6a125f2f6655c/static/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /static/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SneakersInc/Pandora/b09528f9a6f498b9851d7c8d2ba6a125f2f6655c/static/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /static/fonts/glyphicons-halflings-regular.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 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 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | -------------------------------------------------------------------------------- /static/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SneakersInc/Pandora/b09528f9a6f498b9851d7c8d2ba6a125f2f6655c/static/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /static/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SneakersInc/Pandora/b09528f9a6f498b9851d7c8d2ba6a125f2f6655c/static/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /static/images/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SneakersInc/Pandora/b09528f9a6f498b9851d7c8d2ba6a125f2f6655c/static/images/banner.png -------------------------------------------------------------------------------- /static/js/bootstrap-filestyle.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | * bootstrap-filestyle 3 | * doc: http://markusslima.github.io/bootstrap-filestyle/ 4 | * github: https://github.com/markusslima/bootstrap-filestyle 5 | * 6 | * Copyright (c) 2014 Markus Vinicius da Silva Lima 7 | * Version 1.1.2 8 | * Licensed under the MIT license. 9 | */ 10 | (function($) {"use strict"; 11 | 12 | var Filestyle = function(element, options) { 13 | this.options = options; 14 | this.$elementFilestyle = []; 15 | this.$element = $(element); 16 | }; 17 | 18 | Filestyle.prototype = { 19 | clear : function() { 20 | this.$element.val(''); 21 | this.$elementFilestyle.find(':text').val(''); 22 | this.$elementFilestyle.find('.badge').remove(); 23 | }, 24 | 25 | destroy : function() { 26 | this.$element.removeAttr('style').removeData('filestyle'); 27 | this.$elementFilestyle.remove(); 28 | }, 29 | 30 | disabled : function(value) { 31 | if (value === true) { 32 | if (!this.options.disabled) { 33 | this.$element.attr('disabled', 'true'); 34 | this.$elementFilestyle.find('label').attr('disabled', 'true'); 35 | this.options.disabled = true; 36 | } 37 | } else if (value === false) { 38 | if (this.options.disabled) { 39 | this.$element.removeAttr('disabled'); 40 | this.$elementFilestyle.find('label').removeAttr('disabled'); 41 | this.options.disabled = false; 42 | } 43 | } else { 44 | return this.options.disabled; 45 | } 46 | }, 47 | 48 | buttonBefore : function(value) { 49 | if (value === true) { 50 | if (!this.options.buttonBefore) { 51 | this.options.buttonBefore = true; 52 | if (this.options.input) { 53 | this.$elementFilestyle.remove(); 54 | this.constructor(); 55 | this.pushNameFiles(); 56 | } 57 | } 58 | } else if (value === false) { 59 | if (this.options.buttonBefore) { 60 | this.options.buttonBefore = false; 61 | if (this.options.input) { 62 | this.$elementFilestyle.remove(); 63 | this.constructor(); 64 | this.pushNameFiles(); 65 | } 66 | } 67 | } else { 68 | return this.options.buttonBefore; 69 | } 70 | }, 71 | 72 | icon : function(value) { 73 | if (value === true) { 74 | if (!this.options.icon) { 75 | this.options.icon = true; 76 | this.$elementFilestyle.find('label').prepend(this.htmlIcon()); 77 | } 78 | } else if (value === false) { 79 | if (this.options.icon) { 80 | this.options.icon = false; 81 | this.$elementFilestyle.find('.glyphicon').remove(); 82 | } 83 | } else { 84 | return this.options.icon; 85 | } 86 | }, 87 | 88 | input : function(value) { 89 | if (value === true) { 90 | if (!this.options.input) { 91 | this.options.input = true; 92 | 93 | if (this.options.buttonBefore) { 94 | this.$elementFilestyle.append(this.htmlInput()); 95 | } else { 96 | this.$elementFilestyle.prepend(this.htmlInput()); 97 | } 98 | 99 | this.$elementFilestyle.find('.badge').remove(); 100 | 101 | this.pushNameFiles(); 102 | 103 | this.$elementFilestyle.find('.group-span-filestyle').addClass('input-group-btn'); 104 | } 105 | } else if (value === false) { 106 | if (this.options.input) { 107 | this.options.input = false; 108 | this.$elementFilestyle.find(':text').remove(); 109 | var files = this.pushNameFiles(); 110 | if (files.length > 0 && this.options.badge) { 111 | this.$elementFilestyle.find('label').append(' ' + files.length + ''); 112 | } 113 | this.$elementFilestyle.find('.group-span-filestyle').removeClass('input-group-btn'); 114 | } 115 | } else { 116 | return this.options.input; 117 | } 118 | }, 119 | 120 | size : function(value) { 121 | if (value !== undefined) { 122 | var btn = this.$elementFilestyle.find('label'), input = this.$elementFilestyle.find('input'); 123 | 124 | btn.removeClass('btn-lg btn-sm'); 125 | input.removeClass('input-lg input-sm'); 126 | if (value != 'nr') { 127 | btn.addClass('btn-' + value); 128 | input.addClass('input-' + value); 129 | } 130 | } else { 131 | return this.options.size; 132 | } 133 | }, 134 | 135 | buttonText : function(value) { 136 | if (value !== undefined) { 137 | this.options.buttonText = value; 138 | this.$elementFilestyle.find('label .buttonText').html(this.options.buttonText); 139 | } else { 140 | return this.options.buttonText; 141 | } 142 | }, 143 | 144 | buttonName : function(value) { 145 | if (value !== undefined) { 146 | this.options.buttonName = value; 147 | this.$elementFilestyle.find('label').attr({ 148 | 'class' : 'btn ' + this.options.buttonName 149 | }); 150 | } else { 151 | return this.options.buttonName; 152 | } 153 | }, 154 | 155 | iconName : function(value) { 156 | if (value !== undefined) { 157 | this.$elementFilestyle.find('.glyphicon').attr({ 158 | 'class' : '.glyphicon ' + this.options.iconName 159 | }); 160 | } else { 161 | return this.options.iconName; 162 | } 163 | }, 164 | 165 | htmlIcon : function() { 166 | if (this.options.icon) { 167 | return ' '; 168 | } else { 169 | return ''; 170 | } 171 | }, 172 | 173 | htmlInput : function() { 174 | if (this.options.input) { 175 | return ' '; 176 | } else { 177 | return ''; 178 | } 179 | }, 180 | 181 | // puts the name of the input files 182 | // return files 183 | pushNameFiles : function() { 184 | var content = '', files = []; 185 | if (this.$element[0].files === undefined) { 186 | files[0] = { 187 | 'name' : this.$element[0] && this.$element[0].value 188 | }; 189 | } else { 190 | files = this.$element[0].files; 191 | } 192 | 193 | for (var i = 0; i < files.length; i++) { 194 | content += files[i].name.split("\\").pop() + ', '; 195 | } 196 | 197 | if (content !== '') { 198 | this.$elementFilestyle.find(':text').val(content.replace(/\, $/g, '')); 199 | } else { 200 | this.$elementFilestyle.find(':text').val(''); 201 | } 202 | 203 | return files; 204 | }, 205 | 206 | constructor : function() { 207 | var _self = this, 208 | html = '', 209 | id = _self.$element.attr('id'), 210 | files = [], 211 | btn = '', 212 | $label; 213 | 214 | if (id === '' || !id) { 215 | id = 'filestyle-' + $('.bootstrap-filestyle').length; 216 | _self.$element.attr({ 217 | 'id' : id 218 | }); 219 | } 220 | 221 | btn = '' + 222 | '' + 227 | ''; 228 | 229 | html = _self.options.buttonBefore ? btn + _self.htmlInput() : _self.htmlInput() + btn; 230 | 231 | _self.$elementFilestyle = $('
' + html + '
'); 232 | _self.$elementFilestyle.find('.group-span-filestyle').attr('tabindex', "0").keypress(function(e) { 233 | if (e.keyCode === 13 || e.charCode === 32) { 234 | _self.$elementFilestyle.find('label').click(); 235 | return false; 236 | } 237 | }); 238 | 239 | // hidding input file and add filestyle 240 | _self.$element.css({ 241 | 'position' : 'absolute', 242 | 'clip' : 'rect(0px 0px 0px 0px)' // using 0px for work in IE8 243 | }).attr('tabindex', "-1").after(_self.$elementFilestyle); 244 | 245 | if (_self.options.disabled) { 246 | _self.$element.attr('disabled', 'true'); 247 | } 248 | 249 | // Getting input file value 250 | _self.$element.change(function() { 251 | var files = _self.pushNameFiles(); 252 | 253 | if (_self.options.input == false && _self.options.badge) { 254 | if (_self.$elementFilestyle.find('.badge').length == 0) { 255 | _self.$elementFilestyle.find('label').append(' ' + files.length + ''); 256 | } else if (files.length == 0) { 257 | _self.$elementFilestyle.find('.badge').remove(); 258 | } else { 259 | _self.$elementFilestyle.find('.badge').html(files.length); 260 | } 261 | } else { 262 | _self.$elementFilestyle.find('.badge').remove(); 263 | } 264 | }); 265 | 266 | // Check if browser is Firefox 267 | if (window.navigator.userAgent.search(/firefox/i) > -1) { 268 | // Simulating choose file for firefox 269 | _self.$elementFilestyle.find('label').click(function() { 270 | _self.$element.click(); 271 | return false; 272 | }); 273 | } 274 | } 275 | }; 276 | 277 | var old = $.fn.filestyle; 278 | 279 | $.fn.filestyle = function(option, value) { 280 | var get = '', element = this.each(function() { 281 | if ($(this).attr('type') === 'file') { 282 | var $this = $(this), data = $this.data('filestyle'), options = $.extend({}, $.fn.filestyle.defaults, option, typeof option === 'object' && option); 283 | 284 | if (!data) { 285 | $this.data('filestyle', ( data = new Filestyle(this, options))); 286 | data.constructor(); 287 | } 288 | 289 | if ( typeof option === 'string') { 290 | get = data[option](value); 291 | } 292 | } 293 | }); 294 | 295 | if ( typeof get !== undefined) { 296 | return get; 297 | } else { 298 | return element; 299 | } 300 | }; 301 | 302 | $.fn.filestyle.defaults = { 303 | 'buttonText' : 'Choose file', 304 | 'iconName' : 'glyphicon-folder-open', 305 | 'buttonName' : 'btn-default', 306 | 'size' : 'nr', 307 | 'input' : true, 308 | 'badge' : true, 309 | 'icon' : true, 310 | 'buttonBefore' : false, 311 | 'disabled' : false 312 | }; 313 | 314 | $.fn.filestyle.noConflict = function() { 315 | $.fn.filestyle = old; 316 | return this; 317 | }; 318 | 319 | // Data attributes register 320 | $(function() { 321 | $('.filestyle').each(function() { 322 | var $this = $(this), options = { 323 | 324 | 'input' : $this.attr('data-input') === 'false' ? false : true, 325 | 'icon' : $this.attr('data-icon') === 'false' ? false : true, 326 | 'buttonBefore' : $this.attr('data-buttonBefore') === 'true' ? true : false, 327 | 'disabled' : $this.attr('data-disabled') === 'true' ? true : false, 328 | 'size' : $this.attr('data-size'), 329 | 'buttonText' : $this.attr('data-buttonText'), 330 | 'buttonName' : $this.attr('data-buttonName'), 331 | 'iconName' : $this.attr('data-iconName'), 332 | 'badge' : $this.attr('data-badge') === 'false' ? false : true 333 | }; 334 | 335 | $this.filestyle(options); 336 | }); 337 | }); 338 | })(window.jQuery); -------------------------------------------------------------------------------- /static/js/bootstrap-table-export.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author zhixin wen 3 | * extensions: https://github.com/kayalshri/tableExport.jquery.plugin 4 | */ 5 | 6 | (function ($) { 7 | 'use strict'; 8 | 9 | var TYPE_NAME = { 10 | json: 'JSON', 11 | xml: 'XML', 12 | png: 'PNG', 13 | csv: 'CSV', 14 | txt: 'TXT', 15 | sql: 'SQL', 16 | doc: 'MS-Word', 17 | excel: 'Ms-Excel', 18 | powerpoint: 'Ms-Powerpoint', 19 | pdf: 'PDF' 20 | }; 21 | 22 | $.extend($.fn.bootstrapTable.defaults, { 23 | showExport: false, 24 | // 'json', 'xml', 'png', 'csv', 'txt', 'sql', 'doc', 'excel', 'powerpoint', 'pdf' 25 | exportTypes: ['json', 'xml', 'csv', 'txt', 'sql', 'excel'] 26 | }); 27 | 28 | var BootstrapTable = $.fn.bootstrapTable.Constructor, 29 | _initToolbar = BootstrapTable.prototype.initToolbar; 30 | 31 | BootstrapTable.prototype.initToolbar = function () { 32 | this.showToolbar = true; 33 | 34 | _initToolbar.apply(this, Array.prototype.slice.apply(arguments)); 35 | 36 | if (this.options.showExport) { 37 | var that = this, 38 | $btnGroup = this.$toolbar.find('>.btn-group'), 39 | $export = $btnGroup.find('div.export'); 40 | 41 | if (!$export.length) { 42 | $export = $([ 43 | '
', 44 | '', 49 | '', 51 | '
'].join('')).appendTo($btnGroup); 52 | 53 | var $menu = $export.find('.dropdown-menu'), 54 | exportTypes = this.options.exportTypes; 55 | 56 | if (typeof this.options.exportTypes === 'string') { 57 | var types = this.options.exportTypes.slice(1, -1).replace(/ /g, '').split(','); 58 | 59 | exportTypes = []; 60 | $.each(types, function (i, value) { 61 | exportTypes.push(value.slice(1, -1)); 62 | }); 63 | } 64 | $.each(exportTypes, function (i, type) { 65 | if (TYPE_NAME.hasOwnProperty(type)) { 66 | $menu.append(['
  • ', 67 | '', 68 | TYPE_NAME[type], 69 | '', 70 | '
  • '].join('')); 71 | } 72 | }); 73 | 74 | $menu.find('li').click(function () { 75 | that.$el.tableExport({ 76 | type: $(this).data('type'), 77 | escape: false 78 | }); 79 | }); 80 | } 81 | } 82 | }; 83 | })(jQuery); -------------------------------------------------------------------------------- /static/js/bootstrap-table.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author zhixin wen 3 | * version: 1.6.0 4 | * https://github.com/wenzhixin/bootstrap-table/ 5 | */ 6 | 7 | !function ($) { 8 | 9 | 'use strict'; 10 | 11 | // TOOLS DEFINITION 12 | // ====================== 13 | 14 | // it only does '%s', and return '' when arguments are undefined 15 | var sprintf = function(str) { 16 | var args = arguments, 17 | flag = true, 18 | i = 1; 19 | 20 | str = str.replace(/%s/g, function () { 21 | var arg = args[i++]; 22 | 23 | if (typeof arg === 'undefined') { 24 | flag = false; 25 | return ''; 26 | } 27 | return arg; 28 | }); 29 | return flag ? str : ''; 30 | }; 31 | 32 | var getPropertyFromOther = function (list, from, to, value) { 33 | var result = ''; 34 | $.each(list, function (i, item) { 35 | if (item[from] === value) { 36 | result = item[to]; 37 | return false; 38 | } 39 | return true; 40 | }); 41 | return result; 42 | }; 43 | 44 | var getFieldIndex = function (columns, field) { 45 | var index = -1; 46 | 47 | $.each(columns, function (i, column) { 48 | if (column.field === field) { 49 | index = i; 50 | return false; 51 | } 52 | return true; 53 | }); 54 | return index; 55 | }; 56 | 57 | var getScrollBarWidth = function () { 58 | var inner = $('

    ').addClass('fixed-table-scroll-inner'), 59 | outer = $('

    ').addClass('fixed-table-scroll-outer'), 60 | w1, w2; 61 | 62 | outer.append(inner); 63 | $('body').append(outer); 64 | 65 | w1 = inner[0].offsetWidth; 66 | outer.css('overflow', 'scroll'); 67 | w2 = inner[0].offsetWidth; 68 | 69 | if (w1 === w2) { 70 | w2 = outer[0].clientWidth; 71 | } 72 | 73 | outer.remove(); 74 | return w1 - w2; 75 | }; 76 | 77 | var calculateObjectValue = function (self, name, args, defaultValue) { 78 | if (typeof name === 'string') { 79 | // support obj.func1.func2 80 | var names = name.split('.'); 81 | 82 | if (names.length > 1) { 83 | name = window; 84 | $.each(names, function (i, f) { 85 | name = name[f]; 86 | }); 87 | } else { 88 | name = window[name]; 89 | } 90 | } 91 | if (typeof name === 'object') { 92 | return name; 93 | } 94 | if (typeof name === 'function') { 95 | return name.apply(self, args); 96 | } 97 | return defaultValue; 98 | }; 99 | 100 | var escapeHTML = function (text) { 101 | if (typeof text === 'string') { 102 | return text 103 | .replace(/&/g, "&") 104 | .replace(//g, ">") 106 | .replace(/"/g, """) 107 | .replace(/'/g, "'"); 108 | } 109 | return text; 110 | }; 111 | 112 | // BOOTSTRAP TABLE CLASS DEFINITION 113 | // ====================== 114 | 115 | var BootstrapTable = function (el, options) { 116 | this.options = options; 117 | this.$el = $(el); 118 | this.$el_ = this.$el.clone(); 119 | this.timeoutId_ = 0; 120 | 121 | this.init(); 122 | }; 123 | 124 | BootstrapTable.DEFAULTS = { 125 | classes: 'table table-hover', 126 | height: undefined, 127 | undefinedText: '-', 128 | sortName: undefined, 129 | sortOrder: 'asc', 130 | striped: false, 131 | columns: [], 132 | data: [], 133 | method: 'get', 134 | url: undefined, 135 | cache: true, 136 | contentType: 'application/json', 137 | dataType: 'json', 138 | ajaxOptions: {}, 139 | queryParams: function (params) {return params;}, 140 | queryParamsType: 'limit', // undefined 141 | responseHandler: function (res) {return res;}, 142 | pagination: false, 143 | sidePagination: 'client', // client or server 144 | totalRows: 0, // server side need to set 145 | pageNumber: 1, 146 | pageSize: 10, 147 | pageList: [10, 25, 50, 100], 148 | search: false, 149 | searchAlign: 'right', 150 | selectItemName: 'btSelectItem', 151 | showHeader: true, 152 | showColumns: false, 153 | showPaginationSwitch: false, 154 | showRefresh: false, 155 | showToggle: false, 156 | buttonsAlign: 'right', 157 | smartDisplay: true, 158 | minimumCountColumns: 1, 159 | idField: undefined, 160 | cardView: false, 161 | trimOnSearch: true, 162 | clickToSelect: false, 163 | singleSelect: false, 164 | toolbar: undefined, 165 | toolbarAlign: 'left', 166 | checkboxHeader: true, 167 | sortable: true, 168 | maintainSelected: false, 169 | searchTimeOut: 500, 170 | iconSize: undefined, 171 | iconsPrefix: 'glyphicon', // glyphicon of fa (font awesome) 172 | icons: { 173 | paginationSwitchDown: 'glyphicon-collapse-down icon-chevron-down', 174 | paginationSwitchUp: 'glyphicon-collapse-up icon-chevron-up', 175 | refresh: 'glyphicon-refresh icon-refresh', 176 | toggle: 'glyphicon-list-alt icon-list-alt', 177 | columns: 'glyphicon-th icon-th' 178 | }, 179 | 180 | rowStyle: function (row, index) {return {};}, 181 | 182 | rowAttributes: function (row, index) {return {};}, 183 | 184 | onAll: function (name, args) {return false;}, 185 | onClickRow: function (item, $element) {return false;}, 186 | onDblClickRow: function (item, $element) {return false;}, 187 | onSort: function (name, order) {return false;}, 188 | onCheck: function (row) {return false;}, 189 | onUncheck: function (row) {return false;}, 190 | onCheckAll: function () {return false;}, 191 | onUncheckAll: function () {return false;}, 192 | onLoadSuccess: function (data) {return false;}, 193 | onLoadError: function (status) {return false;}, 194 | onColumnSwitch: function (field, checked) {return false;}, 195 | onPageChange: function (number, size) {return false;}, 196 | onSearch: function (text) {return false;}, 197 | onPreBody: function (data) {return false;}, 198 | onPostBody: function () {return false;}, 199 | onPostHeader: function() {return false;} 200 | }; 201 | 202 | BootstrapTable.LOCALES = []; 203 | 204 | BootstrapTable.LOCALES['en-US'] = { 205 | formatLoadingMessage: function () { 206 | return 'Loading, please wait...'; 207 | }, 208 | formatRecordsPerPage: function (pageNumber) { 209 | return sprintf('%s records per page', pageNumber); 210 | }, 211 | formatShowingRows: function (pageFrom, pageTo, totalRows) { 212 | return sprintf('Showing %s to %s of %s rows', pageFrom, pageTo, totalRows); 213 | }, 214 | formatSearch: function () { 215 | return 'Search'; 216 | }, 217 | formatNoMatches: function () { 218 | return 'No matching records found'; 219 | }, 220 | formatPaginationSwitch: function () { 221 | return 'Hide/Show pagination'; 222 | }, 223 | formatRefresh: function () { 224 | return 'Refresh'; 225 | }, 226 | formatToggle: function () { 227 | return 'Toggle'; 228 | }, 229 | formatColumns: function () { 230 | return 'Columns'; 231 | } 232 | }; 233 | 234 | $.extend(BootstrapTable.DEFAULTS, BootstrapTable.LOCALES['en-US']); 235 | 236 | BootstrapTable.COLUMN_DEFAULTS = { 237 | radio: false, 238 | checkbox: false, 239 | checkboxEnabled: true, 240 | field: undefined, 241 | title: undefined, 242 | 'class': undefined, 243 | align: undefined, // left, right, center 244 | halign: undefined, // left, right, center 245 | valign: undefined, // top, middle, bottom 246 | width: undefined, 247 | sortable: false, 248 | order: 'asc', // asc, desc 249 | visible: true, 250 | switchable: true, 251 | clickToSelect: true, 252 | formatter: undefined, 253 | events: undefined, 254 | sorter: undefined, 255 | cellStyle: undefined, 256 | searchable: true 257 | }; 258 | 259 | BootstrapTable.EVENTS = { 260 | 'all.bs.table': 'onAll', 261 | 'click-row.bs.table': 'onClickRow', 262 | 'dbl-click-row.bs.table': 'onDblClickRow', 263 | 'sort.bs.table': 'onSort', 264 | 'check.bs.table': 'onCheck', 265 | 'uncheck.bs.table': 'onUncheck', 266 | 'check-all.bs.table': 'onCheckAll', 267 | 'uncheck-all.bs.table': 'onUncheckAll', 268 | 'load-success.bs.table': 'onLoadSuccess', 269 | 'load-error.bs.table': 'onLoadError', 270 | 'column-switch.bs.table': 'onColumnSwitch', 271 | 'page-change.bs.table': 'onPageChange', 272 | 'search.bs.table': 'onSearch', 273 | 'pre-body.bs.table': 'onPreBody', 274 | 'post-body.bs.table': 'onPostBody', 275 | 'post-header.bs.table' : 'onPostHeader' 276 | }; 277 | 278 | BootstrapTable.prototype.init = function () { 279 | this.initContainer(); 280 | this.initTable(); 281 | this.initHeader(); 282 | this.initData(); 283 | this.initToolbar(); 284 | this.initPagination(); 285 | this.initBody(); 286 | this.initServer(); 287 | }; 288 | 289 | BootstrapTable.prototype.initContainer = function () { 290 | this.$container = $([ 291 | '
    ', 292 | '
    ', 293 | '
    ', 294 | '
    ', 295 | '
    ', 296 | '
    ', 297 | this.options.formatLoadingMessage(), 298 | '
    ', 299 | '
    ', 300 | '
    ', 301 | '
    ', 302 | '
    '].join('')); 303 | 304 | this.$container.insertAfter(this.$el); 305 | this.$container.find('.fixed-table-body').append(this.$el); 306 | this.$container.after('
    '); 307 | this.$loading = this.$container.find('.fixed-table-loading'); 308 | 309 | this.$el.addClass(this.options.classes); 310 | if (this.options.striped) { 311 | this.$el.addClass('table-striped'); 312 | } 313 | }; 314 | 315 | BootstrapTable.prototype.initTable = function () { 316 | var that = this, 317 | columns = [], 318 | data = []; 319 | 320 | this.$header = this.$el.find('thead'); 321 | if (!this.$header.length) { 322 | this.$header = $('').appendTo(this.$el); 323 | } 324 | if (!this.$header.find('tr').length) { 325 | this.$header.append(''); 326 | } 327 | this.$header.find('th').each(function () { 328 | var column = $.extend({}, { 329 | title: $(this).html(), 330 | 'class': $(this).attr('class') 331 | }, $(this).data()); 332 | 333 | columns.push(column); 334 | }); 335 | this.options.columns = $.extend([], columns, this.options.columns); 336 | $.each(this.options.columns, function (i, column) { 337 | that.options.columns[i] = $.extend({}, BootstrapTable.COLUMN_DEFAULTS, 338 | {field: i}, column); // when field is undefined, use index instead 339 | }); 340 | 341 | // if options.data is setting, do not process tbody data 342 | if (this.options.data.length) { 343 | return; 344 | } 345 | 346 | this.$el.find('tbody tr').each(function () { 347 | var row = {}; 348 | 349 | // save tr's id and class 350 | row._id = $(this).attr('id'); 351 | row._class = $(this).attr('class'); 352 | 353 | $(this).find('td').each(function (i) { 354 | var field = that.options.columns[i].field; 355 | 356 | row[field] = $(this).html(); 357 | // save td's id and class 358 | row['_' + field + '_id'] = $(this).attr('id'); 359 | row['_' + field + '_class'] = $(this).attr('class'); 360 | row['_' + field + '_data'] = $(this).data(); 361 | }); 362 | data.push(row); 363 | }); 364 | this.options.data = data; 365 | }; 366 | 367 | BootstrapTable.prototype.initHeader = function () { 368 | var that = this, 369 | visibleColumns = [], 370 | html = []; 371 | 372 | this.header = { 373 | fields: [], 374 | styles: [], 375 | classes: [], 376 | formatters: [], 377 | events: [], 378 | sorters: [], 379 | cellStyles: [], 380 | clickToSelects: [], 381 | searchables: [] 382 | }; 383 | $.each(this.options.columns, function (i, column) { 384 | var text = '', 385 | halign = '', // header align style 386 | align = '', // body align style 387 | style = '', 388 | class_ = sprintf(' class="%s"', column['class']), 389 | order = that.options.sortOrder || column.order, 390 | searchable = true; 391 | 392 | if (!column.visible) { 393 | return; 394 | } 395 | 396 | halign = sprintf('text-align: %s; ', column.halign ? column.halign : column.align); 397 | align = sprintf('text-align: %s; ', column.align); 398 | style = sprintf('vertical-align: %s; ', column.valign); 399 | style += sprintf('width: %spx; ', column.checkbox || column.radio ? 36 : column.width); 400 | 401 | visibleColumns.push(column); 402 | that.header.fields.push(column.field); 403 | that.header.styles.push(align + style); 404 | that.header.classes.push(class_); 405 | that.header.formatters.push(column.formatter); 406 | that.header.events.push(column.events); 407 | that.header.sorters.push(column.sorter); 408 | that.header.cellStyles.push(column.cellStyle); 409 | that.header.clickToSelects.push(column.clickToSelect); 410 | that.header.searchables.push(column.searchable); 411 | 412 | html.push(''); 418 | html.push(sprintf('
    ', that.options.sortable && column.sortable ? 419 | 'sortable' : '')); 420 | 421 | text = column.title; 422 | if (that.options.sortName === column.field && that.options.sortable && column.sortable) { 423 | text += that.getCaretHtml(); 424 | } 425 | 426 | if (column.checkbox) { 427 | if (!that.options.singleSelect && that.options.checkboxHeader) { 428 | text = ''; 429 | } 430 | that.header.stateField = column.field; 431 | } 432 | if (column.radio) { 433 | text = ''; 434 | that.header.stateField = column.field; 435 | that.options.singleSelect = true; 436 | } 437 | 438 | html.push(text); 439 | html.push('
    '); 440 | html.push('
    '); 441 | html.push(''); 442 | }); 443 | 444 | this.$header.find('tr').html(html.join('')); 445 | this.$header.find('th').each(function (i) { 446 | $(this).data(visibleColumns[i]); 447 | }); 448 | this.$container.off('click', 'th').on('click', 'th', function (event) { 449 | if (that.options.sortable && $(this).data().sortable) { 450 | that.onSort(event); 451 | } 452 | }); 453 | 454 | if (!this.options.showHeader || this.options.cardView) { 455 | this.$header.hide(); 456 | this.$container.find('.fixed-table-header').hide(); 457 | this.$loading.css('top', 0); 458 | } else { 459 | this.$header.show(); 460 | this.$container.find('.fixed-table-header').show(); 461 | this.$loading.css('top', '37px'); 462 | } 463 | 464 | this.$selectAll = this.$header.find('[name="btSelectAll"]'); 465 | this.$container.off('click', '[name="btSelectAll"]') 466 | .on('click', '[name="btSelectAll"]', function () { 467 | var checked = $(this).prop('checked'); 468 | that[checked ? 'checkAll' : 'uncheckAll'](); 469 | }); 470 | }; 471 | 472 | /** 473 | * @param data 474 | * @param type: append / prepend 475 | */ 476 | BootstrapTable.prototype.initData = function (data, type) { 477 | if (type === 'append') { 478 | this.data = this.data.concat(data); 479 | } else if (type === 'prepend') { 480 | this.data = [].concat(data).concat(this.data); 481 | } else { 482 | this.data = data || this.options.data; 483 | } 484 | this.options.data = this.data; 485 | 486 | if (this.options.sidePagination === 'server') { 487 | return; 488 | } 489 | this.initSort(); 490 | }; 491 | 492 | BootstrapTable.prototype.initSort = function () { 493 | var that = this, 494 | name = this.options.sortName, 495 | order = this.options.sortOrder === 'desc' ? -1 : 1, 496 | index = $.inArray(this.options.sortName, this.header.fields); 497 | 498 | if (index !== -1) { 499 | this.data.sort(function (a, b) { 500 | var aa = a[name], 501 | bb = b[name], 502 | value = calculateObjectValue(that.header, that.header.sorters[index], [aa, bb]); 503 | 504 | if (value !== undefined) { 505 | return order * value; 506 | } 507 | 508 | if (value !== undefined) { 509 | return order * value; 510 | } 511 | 512 | // Fix #161: undefined or null string sort bug. 513 | if (aa === undefined || aa === null) { 514 | aa = ''; 515 | } 516 | if (bb === undefined || bb === null) { 517 | bb = ''; 518 | } 519 | 520 | // IF both values are numeric, do a numeric comparison 521 | if ($.isNumeric(aa) && $.isNumeric(bb)) { 522 | // Convert numerical values form string to float. 523 | aa = parseFloat(aa); 524 | bb = parseFloat(bb); 525 | if (aa < bb) { 526 | return order * -1; 527 | } 528 | return order; 529 | } 530 | 531 | if (aa === bb) { 532 | return 0; 533 | } 534 | 535 | // If value is not a string, convert to string 536 | if (typeof aa !== 'string') 537 | { 538 | aa = aa.toString(); 539 | } 540 | 541 | if (aa.localeCompare(bb) === -1) { 542 | return order * -1; 543 | } 544 | 545 | return order; 546 | }); 547 | } 548 | }; 549 | 550 | BootstrapTable.prototype.onSort = function (event) { 551 | var $this = $(event.currentTarget), 552 | $this_ = this.$header.find('th').eq($this.index()); 553 | 554 | this.$header.add(this.$header_).find('span.order').remove(); 555 | 556 | if (this.options.sortName === $this.data('field')) { 557 | this.options.sortOrder = this.options.sortOrder === 'asc' ? 'desc' : 'asc'; 558 | } else { 559 | this.options.sortName = $this.data('field'); 560 | this.options.sortOrder = $this.data('order') === 'asc' ? 'desc' : 'asc'; 561 | } 562 | this.trigger('sort', this.options.sortName, this.options.sortOrder); 563 | 564 | $this.add($this_).data('order', this.options.sortOrder) 565 | .find('.th-inner').append(this.getCaretHtml()); 566 | 567 | if (this.options.sidePagination === 'server') { 568 | this.initServer(); 569 | return; 570 | } 571 | this.initSort(); 572 | this.initBody(); 573 | }; 574 | 575 | BootstrapTable.prototype.initToolbar = function () { 576 | var that = this, 577 | html = [], 578 | timeoutId = 0, 579 | $keepOpen, 580 | $search, 581 | switchableCount = 0; 582 | 583 | this.$toolbar = this.$container.find('.fixed-table-toolbar').html(''); 584 | 585 | if (typeof this.options.toolbar === 'string') { 586 | $(sprintf('
    ', this.options.toolbarAlign)) 587 | .appendTo(this.$toolbar) 588 | .append($(this.options.toolbar)); 589 | } 590 | 591 | // showColumns, showToggle, showRefresh 592 | html = [sprintf('
    ', 593 | this.options.buttonsAlign, this.options.buttonsAlign)]; 594 | 595 | if (typeof this.options.icons === 'string') { 596 | this.options.icons = calculateObjectValue(null, this.options.icons); 597 | } 598 | 599 | if (this.options.showPaginationSwitch) { 600 | html.push(sprintf(''); 604 | } 605 | 606 | if (this.options.showRefresh) { 607 | html.push(sprintf(''); 611 | } 612 | 613 | if (this.options.showToggle) { 614 | html.push(sprintf(''); 618 | } 619 | 620 | if (this.options.showColumns) { 621 | html.push(sprintf('
    ', 622 | this.options.formatColumns()), 623 | '', 627 | '', 643 | '
    '); 644 | } 645 | 646 | html.push('
    '); 647 | 648 | // Fix #188: this.showToolbar is for extentions 649 | if (this.showToolbar || html.length > 2) { 650 | this.$toolbar.append(html.join('')); 651 | } 652 | 653 | if (this.options.showPaginationSwitch) { 654 | this.$toolbar.find('button[name="paginationSwitch"]') 655 | .off('click').on('click', $.proxy(this.togglePagination, this)); 656 | } 657 | 658 | if (this.options.showRefresh) { 659 | this.$toolbar.find('button[name="refresh"]') 660 | .off('click').on('click', $.proxy(this.refresh, this)); 661 | } 662 | 663 | if (this.options.showToggle) { 664 | this.$toolbar.find('button[name="toggle"]') 665 | .off('click').on('click', function () { 666 | that.options.cardView = !that.options.cardView; 667 | that.initHeader(); 668 | that.initBody(); 669 | }); 670 | } 671 | 672 | if (this.options.showColumns) { 673 | $keepOpen = this.$toolbar.find('.keep-open'); 674 | 675 | if (switchableCount <= this.options.minimumCountColumns) { 676 | $keepOpen.find('input').prop('disabled', true); 677 | } 678 | 679 | $keepOpen.find('li').off('click').on('click', function (event) { 680 | event.stopImmediatePropagation(); 681 | }); 682 | $keepOpen.find('input').off('click').on('click', function () { 683 | var $this = $(this); 684 | 685 | that.toggleColumn($this.val(), $this.prop('checked'), false); 686 | that.trigger('column-switch', $(this).data('field'), $this.prop('checked')); 687 | }); 688 | } 689 | 690 | if (this.options.search) { 691 | html = []; 692 | html.push( 693 | ''); 697 | 698 | this.$toolbar.append(html.join('')); 699 | $search = this.$toolbar.find('.search input'); 700 | $search.off('keyup').on('keyup', function (event) { 701 | clearTimeout(timeoutId); // doesn't matter if it's 0 702 | timeoutId = setTimeout(function () { 703 | that.onSearch(event); 704 | }, that.options.searchTimeOut); 705 | }); 706 | } 707 | }; 708 | 709 | BootstrapTable.prototype.onSearch = function (event) { 710 | var text = $.trim($(event.currentTarget).val()); 711 | 712 | // trim search input 713 | if(this.options.trimOnSearch) { 714 | $(event.currentTarget).val(text); 715 | } 716 | 717 | if (text === this.searchText) { 718 | return; 719 | } 720 | this.searchText = text; 721 | 722 | this.options.pageNumber = 1; 723 | this.initSearch(); 724 | this.updatePagination(); 725 | this.trigger('search', text); 726 | }; 727 | 728 | BootstrapTable.prototype.initSearch = function () { 729 | var that = this; 730 | 731 | if (this.options.sidePagination !== 'server') { 732 | var s = this.searchText && this.searchText.toLowerCase(); 733 | var f = $.isEmptyObject(this.filterColumns) ? null: this.filterColumns; 734 | 735 | // Check filter 736 | this.data = f ? $.grep(this.options.data, function (item, i) { 737 | for (var key in f) { 738 | if (item[key] !== f[key]) { 739 | return false; 740 | } 741 | } 742 | return true; 743 | }) : this.options.data; 744 | 745 | this.data = s ? $.grep(this.data, function (item, i) { 746 | for (var key in item) { 747 | key = $.isNumeric(key) ? parseInt(key, 10) : key; 748 | var value = item[key]; 749 | 750 | // Fix #142: search use formated data 751 | value = calculateObjectValue(that.header, 752 | that.header.formatters[$.inArray(key, that.header.fields)], 753 | [value, item, i], value); 754 | 755 | var index = $.inArray(key, that.header.fields); 756 | if (index !== -1 && that.header.searchables[index] && 757 | (typeof value === 'string' || 758 | typeof value === 'number') && 759 | (value + '').toLowerCase().indexOf(s) !== -1) { 760 | return true; 761 | } 762 | } 763 | return false; 764 | }) : this.data; 765 | } 766 | }; 767 | 768 | BootstrapTable.prototype.initPagination = function () { 769 | this.$pagination = this.$container.find('.fixed-table-pagination'); 770 | 771 | if (!this.options.pagination) { 772 | this.$pagination.hide(); 773 | return; 774 | } else { 775 | this.$pagination.show(); 776 | } 777 | 778 | var that = this, 779 | html = [], 780 | i, from, to, 781 | $pageList, 782 | $first, $pre, 783 | $next, $last, 784 | $number, 785 | data = this.getData(); 786 | 787 | if (this.options.sidePagination !== 'server') { 788 | this.options.totalRows = data.length; 789 | } 790 | 791 | this.totalPages = 0; 792 | if (this.options.totalRows) { 793 | this.totalPages = ~~((this.options.totalRows - 1) / this.options.pageSize) + 1; 794 | this.options.totalPages = this.totalPages; 795 | } 796 | if (this.totalPages > 0 && this.options.pageNumber > this.totalPages) { 797 | this.options.pageNumber = this.totalPages; 798 | } 799 | 800 | this.pageFrom = (this.options.pageNumber - 1) * this.options.pageSize + 1; 801 | this.pageTo = this.options.pageNumber * this.options.pageSize; 802 | if (this.pageTo > this.options.totalRows) { 803 | this.pageTo = this.options.totalRows; 804 | } 805 | 806 | html.push( 807 | '
    ', 808 | '', 809 | this.options.formatShowingRows(this.pageFrom, this.pageTo, this.options.totalRows), 810 | ''); 811 | 812 | html.push(''); 813 | 814 | var pageNumber = [ 815 | '', 816 | '', 822 | ''); 841 | 842 | html.push(this.options.formatRecordsPerPage(pageNumber.join(''))); 843 | html.push(''); 844 | 845 | html.push('
    ', 846 | ''); 877 | 878 | this.$pagination.html(html.join('')); 879 | 880 | $pageList = this.$pagination.find('.page-list a'); 881 | $first = this.$pagination.find('.page-first'); 882 | $pre = this.$pagination.find('.page-pre'); 883 | $next = this.$pagination.find('.page-next'); 884 | $last = this.$pagination.find('.page-last'); 885 | $number = this.$pagination.find('.page-number'); 886 | 887 | if (this.options.pageNumber <= 1) { 888 | $first.addClass('disabled'); 889 | $pre.addClass('disabled'); 890 | } 891 | if (this.options.pageNumber >= this.totalPages) { 892 | $next.addClass('disabled'); 893 | $last.addClass('disabled'); 894 | } 895 | if (this.options.smartDisplay) { 896 | if (this.totalPages <= 1) { 897 | this.$pagination.find('div.pagination').hide(); 898 | } 899 | if (this.options.pageList.length < 2 || this.options.totalRows <= this.options.pageList[0]) { 900 | this.$pagination.find('span.page-list').hide(); 901 | } 902 | 903 | // when data is empty, hide the pagination 904 | this.$pagination[this.getData().length ? 'show' : 'hide'](); 905 | } 906 | $pageList.off('click').on('click', $.proxy(this.onPageListChange, this)); 907 | $first.off('click').on('click', $.proxy(this.onPageFirst, this)); 908 | $pre.off('click').on('click', $.proxy(this.onPagePre, this)); 909 | $next.off('click').on('click', $.proxy(this.onPageNext, this)); 910 | $last.off('click').on('click', $.proxy(this.onPageLast, this)); 911 | $number.off('click').on('click', $.proxy(this.onPageNumber, this)); 912 | }; 913 | 914 | BootstrapTable.prototype.updatePagination = function (event) { 915 | // Fix #171: IE disabled button can be clicked bug. 916 | if (event && $(event.currentTarget).hasClass('disabled')) { 917 | return; 918 | } 919 | 920 | if (!this.options.maintainSelected) { 921 | this.resetRows(); 922 | } 923 | 924 | this.initPagination(); 925 | if (this.options.sidePagination === 'server') { 926 | this.initServer(); 927 | } else { 928 | this.initBody(); 929 | } 930 | 931 | this.trigger('page-change', this.options.pageNumber, this.options.pageSize); 932 | }; 933 | 934 | BootstrapTable.prototype.onPageListChange = function (event) { 935 | var $this = $(event.currentTarget); 936 | 937 | $this.parent().addClass('active').siblings().removeClass('active'); 938 | this.options.pageSize = +$this.text(); 939 | this.$toolbar.find('.page-size').text(this.options.pageSize); 940 | this.updatePagination(event); 941 | }; 942 | 943 | BootstrapTable.prototype.onPageFirst = function (event) { 944 | this.options.pageNumber = 1; 945 | this.updatePagination(event); 946 | }; 947 | 948 | BootstrapTable.prototype.onPagePre = function (event) { 949 | this.options.pageNumber--; 950 | this.updatePagination(event); 951 | }; 952 | 953 | BootstrapTable.prototype.onPageNext = function (event) { 954 | this.options.pageNumber++; 955 | this.updatePagination(event); 956 | }; 957 | 958 | BootstrapTable.prototype.onPageLast = function (event) { 959 | this.options.pageNumber = this.totalPages; 960 | this.updatePagination(event); 961 | }; 962 | 963 | BootstrapTable.prototype.onPageNumber = function (event) { 964 | if (this.options.pageNumber === +$(event.currentTarget).text()) { 965 | return; 966 | } 967 | this.options.pageNumber = +$(event.currentTarget).text(); 968 | this.updatePagination(event); 969 | }; 970 | 971 | BootstrapTable.prototype.initBody = function (fixedScroll) { 972 | var that = this, 973 | html = [], 974 | data = this.getData(); 975 | 976 | this.trigger('pre-body', data); 977 | 978 | this.$body = this.$el.find('tbody'); 979 | if (!this.$body.length) { 980 | this.$body = $('').appendTo(this.$el); 981 | } 982 | 983 | //Fix #389 Bootstrap-table-flatJSON is not working 984 | 985 | if (!this.options.pagination || this.options.sidePagination === 'server') { 986 | this.pageFrom = 1; 987 | this.pageTo = data.length; 988 | } 989 | 990 | for (var i = this.pageFrom - 1; i < this.pageTo; i++) { 991 | var item = data[i], 992 | style = {}, 993 | csses = [], 994 | attributes = {}, 995 | htmlAttributes = []; 996 | 997 | style = calculateObjectValue(this.options, this.options.rowStyle, [item, i], style); 998 | 999 | if (style && style.css) { 1000 | for (var key in style.css) { 1001 | csses.push(key + ': ' + style.css[key]); 1002 | } 1003 | } 1004 | 1005 | attributes = calculateObjectValue(this.options, 1006 | this.options.rowAttributes, [item, i], attributes); 1007 | 1008 | if (attributes) { 1009 | for (var key in attributes) { 1010 | htmlAttributes.push(sprintf('%s="%s"', key, escapeHTML(attributes[key]))); 1011 | } 1012 | } 1013 | 1014 | html.push('' 1020 | ); 1021 | 1022 | if (this.options.cardView) { 1023 | html.push(sprintf('', this.header.fields.length)); 1024 | } 1025 | 1026 | $.each(this.header.fields, function (j, field) { 1027 | var text = '', 1028 | value = item[field], 1029 | type = '', 1030 | cellStyle = {}, 1031 | id_ = '', 1032 | class_ = that.header.classes[j], 1033 | data_ = '', 1034 | column = that.options.columns[getFieldIndex(that.options.columns, field)]; 1035 | 1036 | style = sprintf('style="%s"', csses.concat(that.header.styles[j]).join('; ')); 1037 | 1038 | value = calculateObjectValue(that.header, 1039 | that.header.formatters[j], [value, item, i], value); 1040 | 1041 | // handle td's id and class 1042 | if (item['_' + field + '_id']) { 1043 | id_ = sprintf(' id="%s"', item['_' + field + '_id']); 1044 | } 1045 | if (item['_' + field + '_class']) { 1046 | class_ = sprintf(' class="%s"', item['_' + field + '_class']); 1047 | } 1048 | cellStyle = calculateObjectValue(that.header, 1049 | that.header.cellStyles[j], [value, item, i], cellStyle); 1050 | if (cellStyle.classes) { 1051 | class_ = sprintf(' class="%s"', cellStyle.classes); 1052 | } 1053 | if (cellStyle.css) { 1054 | var csses_ = []; 1055 | for (var key in cellStyle.css) { 1056 | csses_.push(key + ': ' + cellStyle.css[key]); 1057 | } 1058 | style = sprintf('style="%s"', csses_.concat(that.header.styles[j]).join('; ')); 1059 | } 1060 | 1061 | if (item['_' + field + '_data'] && !$.isEmptyObject(item['_' + field + '_data'])) { 1062 | $.each(item['_' + field + '_data'], function (k, v) { 1063 | // ignore data-index 1064 | if (k === 'index') { 1065 | return; 1066 | } 1067 | data_ += sprintf(' data-%s="%s"', k, v); 1068 | }); 1069 | } 1070 | 1071 | if (column.checkbox || column.radio) { 1072 | type = column.checkbox ? 'checkbox' : type; 1073 | type = column.radio ? 'radio' : type; 1074 | 1075 | text = [that.options.cardView ? 1076 | '
    ' : '', 1077 | '', 1087 | that.options.cardView ? '
    ' : ''].join(''); 1088 | } else { 1089 | value = typeof value === 'undefined' || value === null ? 1090 | that.options.undefinedText : value; 1091 | 1092 | text = that.options.cardView ? 1093 | ['
    ', 1094 | that.options.showHeader ? sprintf('%s', style, 1095 | getPropertyFromOther(that.options.columns, 'field', 'title', field)) : '', 1096 | sprintf('%s', value), 1097 | '
    '].join('') : 1098 | [sprintf('', id_, class_, style, data_), 1099 | value, 1100 | ''].join(''); 1101 | 1102 | // Hide empty data on Card view when smartDisplay is set to true. 1103 | if (that.options.cardView && that.options.smartDisplay && value === '') { 1104 | text = ''; 1105 | } 1106 | } 1107 | 1108 | html.push(text); 1109 | }); 1110 | 1111 | if (this.options.cardView) { 1112 | html.push(''); 1113 | } 1114 | 1115 | html.push(''); 1116 | } 1117 | 1118 | // show no records 1119 | if (!html.length) { 1120 | html.push('', 1121 | sprintf('%s', this.header.fields.length, this.options.formatNoMatches()), 1122 | ''); 1123 | } 1124 | 1125 | this.$body.html(html.join('')); 1126 | 1127 | if (!fixedScroll) { 1128 | this.scrollTo(0); 1129 | } 1130 | 1131 | // click to select by column 1132 | this.$body.find('> tr > td').off('click').on('click', function () { 1133 | var $tr = $(this).parent(); 1134 | that.trigger('click-row', that.data[$tr.data('index')], $tr); 1135 | // if click to select - then trigger the checkbox/radio click 1136 | if (that.options.clickToSelect) { 1137 | if (that.header.clickToSelects[$tr.children().index($(this))]) { 1138 | $tr.find(sprintf('[name="%s"]', 1139 | that.options.selectItemName))[0].click(); // #144: .trigger('click') bug 1140 | } 1141 | } 1142 | }); 1143 | this.$body.find('tr').off('dblclick').on('dblclick', function () { 1144 | that.trigger('dbl-click-row', that.data[$(this).data('index')], $(this)); 1145 | }); 1146 | 1147 | this.$selectItem = this.$body.find(sprintf('[name="%s"]', this.options.selectItemName)); 1148 | this.$selectItem.off('click').on('click', function (event) { 1149 | event.stopImmediatePropagation(); 1150 | 1151 | var checked = $(this).prop('checked'), 1152 | row = that.data[$(this).data('index')]; 1153 | 1154 | row[that.header.stateField] = checked; 1155 | that.trigger(checked ? 'check' : 'uncheck', row); 1156 | 1157 | if (that.options.singleSelect) { 1158 | that.$selectItem.not(this).each(function () { 1159 | that.data[$(this).data('index')][that.header.stateField] = false; 1160 | }); 1161 | that.$selectItem.filter(':checked').not(this).prop('checked', false); 1162 | } 1163 | 1164 | that.updateSelected(); 1165 | }); 1166 | 1167 | $.each(this.header.events, function (i, events) { 1168 | if (!events) { 1169 | return; 1170 | } 1171 | // fix bug, if events is defined with namespace 1172 | if (typeof events === 'string') { 1173 | events = calculateObjectValue(null, events); 1174 | } 1175 | for (var key in events) { 1176 | that.$body.find('tr').each(function () { 1177 | var $tr = $(this), 1178 | $td = $tr.find(that.options.cardView ? '.card-view' : 'td').eq(i), 1179 | index = key.indexOf(' '), 1180 | name = key.substring(0, index), 1181 | el = key.substring(index + 1), 1182 | func = events[key]; 1183 | 1184 | $td.find(el).off(name).on(name, function (e) { 1185 | var index = $tr.data('index'), 1186 | row = that.data[index], 1187 | value = row[that.header.fields[i]]; 1188 | 1189 | func.apply(this, [e, value, row, index]); 1190 | }); 1191 | }); 1192 | } 1193 | }); 1194 | 1195 | this.updateSelected(); 1196 | this.resetView(); 1197 | 1198 | this.trigger('post-body'); 1199 | }; 1200 | 1201 | BootstrapTable.prototype.initServer = function (silent, query) { 1202 | var that = this, 1203 | data = {}, 1204 | params = { 1205 | pageSize: this.options.pageSize, 1206 | pageNumber: this.options.pageNumber, 1207 | searchText: this.searchText, 1208 | sortName: this.options.sortName, 1209 | sortOrder: this.options.sortOrder 1210 | }; 1211 | 1212 | if (!this.options.url) { 1213 | return; 1214 | } 1215 | 1216 | if (this.options.queryParamsType === 'limit') { 1217 | params = { 1218 | search: params.searchText, 1219 | sort: params.sortName, 1220 | order: params.sortOrder 1221 | }; 1222 | if (this.options.pagination) { 1223 | params.limit = this.options.pageSize; 1224 | params.offset = this.options.pageSize * (this.options.pageNumber - 1); 1225 | } 1226 | } 1227 | data = calculateObjectValue(this.options, this.options.queryParams, [params], data); 1228 | 1229 | $.extend(data, query || {}); 1230 | 1231 | // false to stop request 1232 | if (data === false) { 1233 | return; 1234 | } 1235 | 1236 | if (!silent) { 1237 | this.$loading.show(); 1238 | } 1239 | 1240 | $.ajax($.extend({}, calculateObjectValue(null, this.options.ajaxOptions), { 1241 | type: this.options.method, 1242 | url: this.options.url, 1243 | data: this.options.contentType === 'application/json' && this.options.method === 'post' ? 1244 | JSON.stringify(data): data, 1245 | cache: this.options.cache, 1246 | contentType: this.options.contentType, 1247 | dataType: this.options.dataType, 1248 | success: function (res) { 1249 | res = calculateObjectValue(that.options, that.options.responseHandler, [res], res); 1250 | 1251 | that.load(res); 1252 | that.trigger('load-success', res); 1253 | }, 1254 | error: function (res) { 1255 | that.trigger('load-error', res.status); 1256 | }, 1257 | complete: function () { 1258 | if (!silent) { 1259 | that.$loading.hide(); 1260 | } 1261 | } 1262 | })); 1263 | }; 1264 | 1265 | BootstrapTable.prototype.getCaretHtml = function () { 1266 | return ['', 1267 | '', 1268 | ''].join(''); 1269 | }; 1270 | 1271 | BootstrapTable.prototype.updateSelected = function () { 1272 | var checkAll = this.$selectItem.filter(':enabled').length === 1273 | this.$selectItem.filter(':enabled').filter(':checked').length; 1274 | 1275 | this.$selectAll.add(this.$selectAll_).prop('checked', checkAll); 1276 | 1277 | this.$selectItem.each(function () { 1278 | $(this).parents('tr')[$(this).prop('checked') ? 'addClass' : 'removeClass']('selected'); 1279 | }); 1280 | }; 1281 | 1282 | BootstrapTable.prototype.updateRows = function (checked) { 1283 | var that = this; 1284 | 1285 | this.$selectItem.each(function () { 1286 | that.data[$(this).data('index')][that.header.stateField] = checked; 1287 | }); 1288 | }; 1289 | 1290 | BootstrapTable.prototype.resetRows = function () { 1291 | var that = this; 1292 | 1293 | $.each(this.data, function (i, row) { 1294 | that.$selectAll.prop('checked', false); 1295 | that.$selectItem.prop('checked', false); 1296 | row[that.header.stateField] = false; 1297 | }); 1298 | }; 1299 | 1300 | BootstrapTable.prototype.trigger = function (name) { 1301 | var args = Array.prototype.slice.call(arguments, 1); 1302 | 1303 | name += '.bs.table'; 1304 | this.options[BootstrapTable.EVENTS[name]].apply(this.options, args); 1305 | this.$el.trigger($.Event(name), args); 1306 | 1307 | this.options.onAll(name, args); 1308 | this.$el.trigger($.Event('all.bs.table'), [name, args]); 1309 | }; 1310 | 1311 | BootstrapTable.prototype.resetHeader = function () { 1312 | var that = this, 1313 | $fixedHeader = this.$container.find('.fixed-table-header'), 1314 | $fixedBody = this.$container.find('.fixed-table-body'), 1315 | scrollWidth = this.$el.width() > $fixedBody.width() ? getScrollBarWidth() : 0; 1316 | 1317 | // fix #61: the hidden table reset header bug. 1318 | if (this.$el.is(':hidden')) { 1319 | clearTimeout(this.timeoutId_); // doesn't matter if it's 0 1320 | this.timeoutId_ = setTimeout($.proxy(this.resetHeader, this), 100); // 100ms 1321 | return; 1322 | } 1323 | 1324 | this.$header_ = this.$header.clone(true, true); 1325 | this.$selectAll_ = this.$header_.find('[name="btSelectAll"]'); 1326 | 1327 | // fix bug: get $el.css('width') error sometime (height = 500) 1328 | setTimeout(function () { 1329 | $fixedHeader.css({ 1330 | 'height': '37px', 1331 | 'border-bottom': '1px solid #dddddd', 1332 | 'margin-right': scrollWidth 1333 | }).find('table').css('width', that.$el.css('width')) 1334 | .html('').attr('class', that.$el.attr('class')) 1335 | .append(that.$header_); 1336 | 1337 | // fix bug: $.data() is not working as expected after $.append() 1338 | that.$header.find('th').each(function (i) { 1339 | that.$header_.find('th').eq(i).data($(this).data()); 1340 | }); 1341 | 1342 | that.$body.find('tr:first-child:not(.no-records-found) > *').each(function(i) { 1343 | that.$header_.find('div.fht-cell').eq(i).width($(this).innerWidth()); 1344 | }); 1345 | 1346 | that.$el.css('margin-top', -that.$header.height()); 1347 | 1348 | // horizontal scroll event 1349 | $fixedBody.off('scroll').on('scroll', function () { 1350 | $fixedHeader.scrollLeft($(this).scrollLeft()); 1351 | }); 1352 | 1353 | that.trigger('post-header'); 1354 | }); 1355 | }; 1356 | 1357 | BootstrapTable.prototype.toggleColumn = function (index, checked, needUpdate) { 1358 | if (index === -1) { 1359 | return; 1360 | } 1361 | this.options.columns[index].visible = checked; 1362 | this.initHeader(); 1363 | this.initSearch(); 1364 | this.initPagination(); 1365 | this.initBody(); 1366 | 1367 | if (this.options.showColumns) { 1368 | var $items = this.$toolbar.find('.keep-open input').prop('disabled', false); 1369 | 1370 | if (needUpdate) { 1371 | $items.filter(sprintf('[value="%s"]', index)).prop('checked', checked); 1372 | } 1373 | 1374 | if ($items.filter(':checked').length <= this.options.minimumCountColumns) { 1375 | $items.filter(':checked').prop('disabled', true); 1376 | } 1377 | } 1378 | }; 1379 | 1380 | // PUBLIC FUNCTION DEFINITION 1381 | // ======================= 1382 | 1383 | BootstrapTable.prototype.resetView = function (params) { 1384 | var that = this, 1385 | header = this.header; 1386 | 1387 | if (params && params.height) { 1388 | this.options.height = params.height; 1389 | } 1390 | 1391 | this.$selectAll.prop('checked', this.$selectItem.length > 0 && 1392 | this.$selectItem.length === this.$selectItem.filter(':checked').length); 1393 | 1394 | if (this.options.height) { 1395 | var toolbarHeight = +this.$toolbar.children().outerHeight(true), 1396 | paginationHeight = +this.$pagination.children().outerHeight(true), 1397 | height = this.options.height - toolbarHeight - paginationHeight; 1398 | 1399 | this.$container.find('.fixed-table-container').css('height', height + 'px'); 1400 | } 1401 | 1402 | if (this.options.cardView) { 1403 | // remove the element css 1404 | that.$el.css('margin-top', '0'); 1405 | that.$container.find('.fixed-table-container').css('padding-bottom', '0'); 1406 | return; 1407 | } 1408 | 1409 | if (this.options.showHeader && this.options.height) { 1410 | this.resetHeader(); 1411 | } else { 1412 | this.trigger('post-header'); 1413 | } 1414 | 1415 | if (this.options.height && this.options.showHeader) { 1416 | this.$container.find('.fixed-table-container').css('padding-bottom', '37px'); 1417 | } 1418 | }; 1419 | 1420 | BootstrapTable.prototype.getData = function () { 1421 | return (this.searchText || !$.isEmptyObject(this.filterColumns)) ? this.data : this.options.data; 1422 | }; 1423 | 1424 | BootstrapTable.prototype.load = function (data) { 1425 | var fixedScroll = false; 1426 | 1427 | // #431: support pagination 1428 | if (this.options.sidePagination === 'server') { 1429 | this.options.totalRows = data.total; 1430 | fixedScroll = data.fixedScroll; 1431 | data = data.rows; 1432 | } else if (!$.isArray(data)) { // support fixedScroll 1433 | fixedScroll = data.fixedScroll; 1434 | data = data.data; 1435 | } 1436 | 1437 | this.initData(data); 1438 | this.initSearch(); 1439 | this.initPagination(); 1440 | this.initBody(fixedScroll); 1441 | }; 1442 | 1443 | BootstrapTable.prototype.append = function (data) { 1444 | this.initData(data, 'append'); 1445 | this.initSearch(); 1446 | this.initPagination(); 1447 | this.initBody(true); 1448 | }; 1449 | 1450 | BootstrapTable.prototype.prepend = function (data) { 1451 | this.initData(data, 'prepend'); 1452 | this.initSearch(); 1453 | this.initPagination(); 1454 | this.initBody(true); 1455 | }; 1456 | 1457 | BootstrapTable.prototype.remove = function (params) { 1458 | var len = this.options.data.length, 1459 | i, row; 1460 | 1461 | if (!params.hasOwnProperty('field') || !params.hasOwnProperty('values')) { 1462 | return; 1463 | } 1464 | 1465 | for (i = len - 1; i >= 0; i--) { 1466 | row = this.options.data[i]; 1467 | 1468 | if (!row.hasOwnProperty(params.field)) { 1469 | continue; 1470 | } 1471 | if ($.inArray(row[params.field], params.values) !== -1) { 1472 | this.options.data.splice(i, 1); 1473 | } 1474 | } 1475 | 1476 | if (len === this.options.data.length) { 1477 | return; 1478 | } 1479 | 1480 | this.initSearch(); 1481 | this.initPagination(); 1482 | this.initBody(true); 1483 | }; 1484 | 1485 | BootstrapTable.prototype.insertRow = function (params) { 1486 | if (!params.hasOwnProperty('index') || !params.hasOwnProperty('row')) { 1487 | return; 1488 | } 1489 | this.data.splice(params.index, 0, params.row); 1490 | this.initBody(true); 1491 | }; 1492 | 1493 | BootstrapTable.prototype.updateRow = function (params) { 1494 | if (!params.hasOwnProperty('index') || !params.hasOwnProperty('row')) { 1495 | return; 1496 | } 1497 | $.extend(this.data[params.index], params.row); 1498 | this.initBody(true); 1499 | }; 1500 | 1501 | BootstrapTable.prototype.mergeCells = function (options) { 1502 | var row = options.index, 1503 | col = $.inArray(options.field, this.header.fields), 1504 | rowspan = options.rowspan || 1, 1505 | colspan = options.colspan || 1, 1506 | i, j, 1507 | $tr = this.$body.find('tr'), 1508 | $td = $tr.eq(row).find('td').eq(col); 1509 | 1510 | if (row < 0 || col < 0 || row >= this.data.length) { 1511 | return; 1512 | } 1513 | 1514 | for (i = row; i < row + rowspan; i++) { 1515 | for (j = col; j < col + colspan; j++) { 1516 | $tr.eq(i).find('td').eq(j).hide(); 1517 | } 1518 | } 1519 | 1520 | $td.attr('rowspan', rowspan).attr('colspan', colspan).show(); 1521 | }; 1522 | 1523 | BootstrapTable.prototype.getOptions = function () { 1524 | return this.options; 1525 | }; 1526 | 1527 | BootstrapTable.prototype.getSelections = function () { 1528 | var that = this; 1529 | 1530 | return $.grep(this.data, function (row) { 1531 | return row[that.header.stateField]; 1532 | }); 1533 | }; 1534 | 1535 | BootstrapTable.prototype.checkAll = function () { 1536 | this.checkAll_(true); 1537 | }; 1538 | 1539 | BootstrapTable.prototype.uncheckAll = function () { 1540 | this.checkAll_(false); 1541 | }; 1542 | 1543 | BootstrapTable.prototype.checkAll_ = function (checked) { 1544 | var rows; 1545 | if(!checked) { 1546 | rows = this.getSelections(); 1547 | } 1548 | this.$selectItem.filter(':enabled').prop('checked', checked); 1549 | this.updateRows(checked); 1550 | this.updateSelected(); 1551 | if(checked) { 1552 | rows = this.getSelections(); 1553 | } 1554 | this.trigger(checked ? 'check-all' : 'uncheck-all', rows); 1555 | }; 1556 | 1557 | BootstrapTable.prototype.check = function (index) { 1558 | this.check_(true, index); 1559 | }; 1560 | 1561 | BootstrapTable.prototype.uncheck = function (index) { 1562 | this.check_(false, index); 1563 | }; 1564 | 1565 | BootstrapTable.prototype.check_ = function (checked, index) { 1566 | this.$selectItem.filter(sprintf('[data-index="%s"]', index)).prop('checked', checked); 1567 | this.data[index][this.header.stateField] = checked; 1568 | this.updateSelected(); 1569 | this.trigger(checked ? 'check' : 'uncheck', this.data[index]); 1570 | }; 1571 | 1572 | BootstrapTable.prototype.checkBy = function (obj) { 1573 | this.checkBy_(true, obj); 1574 | }; 1575 | 1576 | BootstrapTable.prototype.uncheckBy = function (obj) { 1577 | this.checkBy_(false, obj); 1578 | }; 1579 | 1580 | BootstrapTable.prototype.checkBy_ = function (checked, obj) { 1581 | if(!obj.hasOwnProperty('field') || !obj.hasOwnProperty('values')) { 1582 | return; 1583 | } 1584 | 1585 | var that = this; 1586 | $.each(this.options.data, function (index, row) { 1587 | if (!row.hasOwnProperty(obj.field)) { 1588 | return false; 1589 | } 1590 | if ($.inArray(row[obj.field], obj.values) !== -1) { 1591 | that.$selectItem.filter(sprintf('[data-index="%s"]', index)).prop('checked', checked); 1592 | row[that.header.stateField] = checked; 1593 | that.trigger(checked ? 'check' : 'uncheck', row); 1594 | } 1595 | }); 1596 | this.updateSelected(); 1597 | }; 1598 | 1599 | BootstrapTable.prototype.destroy = function () { 1600 | this.$el.insertBefore(this.$container); 1601 | $(this.options.toolbar).insertBefore(this.$el); 1602 | this.$container.next().remove(); 1603 | this.$container.remove(); 1604 | this.$el.html(this.$el_.html()) 1605 | .css('margin-top', '0') 1606 | .attr('class', this.$el_.attr('class') || ''); // reset the class 1607 | }; 1608 | 1609 | BootstrapTable.prototype.showLoading = function () { 1610 | this.$loading.show(); 1611 | }; 1612 | 1613 | BootstrapTable.prototype.hideLoading = function () { 1614 | this.$loading.hide(); 1615 | }; 1616 | 1617 | BootstrapTable.prototype.togglePagination = function () { 1618 | this.options.pagination = !this.options.pagination; 1619 | var button = this.$toolbar.find('button[name="paginationSwitch"] i'); 1620 | if (this.options.pagination) { 1621 | button.attr("class", this.options.iconsPrefix + " " + this.options.icons.paginationSwitchDown); 1622 | } else { 1623 | button.attr("class", this.options.iconsPrefix + " " + this.options.icons.paginationSwitchUp); 1624 | } 1625 | this.updatePagination(); 1626 | }; 1627 | 1628 | BootstrapTable.prototype.refresh = function (params) { 1629 | if (params && params.url) { 1630 | this.options.url = params.url; 1631 | this.options.pageNumber = 1; 1632 | } 1633 | this.initServer(params && params.silent, params && params.query); 1634 | }; 1635 | 1636 | BootstrapTable.prototype.showColumn = function (field) { 1637 | this.toggleColumn(getFieldIndex(this.options.columns, field), true, true); 1638 | }; 1639 | 1640 | BootstrapTable.prototype.hideColumn = function (field) { 1641 | this.toggleColumn(getFieldIndex(this.options.columns, field), false, true); 1642 | }; 1643 | 1644 | BootstrapTable.prototype.filterBy = function (columns) { 1645 | this.filterColumns = $.isEmptyObject(columns) ? {}: columns; 1646 | this.options.pageNumber = 1; 1647 | this.initSearch(); 1648 | this.updatePagination(); 1649 | }; 1650 | 1651 | BootstrapTable.prototype.scrollTo = function (value) { 1652 | var $tbody = this.$container.find('.fixed-table-body'); 1653 | if (typeof value === 'string') { 1654 | value = value === 'bottom' ? $tbody[0].scrollHeight : 0; 1655 | } 1656 | if (typeof value === 'number') { 1657 | $tbody.scrollTop(value); 1658 | } 1659 | }; 1660 | 1661 | BootstrapTable.prototype.selectPage = function (page) { 1662 | if (page > 0 && page <= this.options.totalPages) { 1663 | this.options.pageNumber = page; 1664 | this.updatePagination(); 1665 | } 1666 | }; 1667 | 1668 | BootstrapTable.prototype.prevPage = function () { 1669 | if (this.options.pageNumber > 1) { 1670 | this.options.pageNumber--; 1671 | this.updatePagination(); 1672 | } 1673 | }; 1674 | 1675 | BootstrapTable.prototype.nextPage = function () { 1676 | if (this.options.pageNumber < this.options.totalPages) { 1677 | this.options.pageNumber++; 1678 | this.updatePagination(); 1679 | } 1680 | }; 1681 | 1682 | BootstrapTable.prototype.toggleView = function () { 1683 | this.options.cardView = !this.options.cardView; 1684 | this.initHeader(); 1685 | this.initBody(); 1686 | }; 1687 | 1688 | // BOOTSTRAP TABLE PLUGIN DEFINITION 1689 | // ======================= 1690 | 1691 | var allowedMethods = [ 1692 | 'getOptions', 1693 | 'getSelections', 'getData', 1694 | 'load', 'append', 'prepend', 'remove', 1695 | 'insertRow', 'updateRow', 1696 | 'mergeCells', 1697 | 'checkAll', 'uncheckAll', 1698 | 'check', 'uncheck', 1699 | 'checkBy', 'uncheckBy', 1700 | 'refresh', 1701 | 'resetView', 1702 | 'destroy', 1703 | 'showLoading', 'hideLoading', 1704 | 'showColumn', 'hideColumn', 1705 | 'filterBy', 1706 | 'scrollTo', 1707 | 'selectPage', 'prevPage', 'nextPage', 1708 | 'togglePagination', 1709 | 'toggleView' 1710 | ]; 1711 | 1712 | $.fn.bootstrapTable = function (option, _relatedTarget) { 1713 | var value; 1714 | 1715 | this.each(function () { 1716 | var $this = $(this), 1717 | data = $this.data('bootstrap.table'), 1718 | options = $.extend({}, BootstrapTable.DEFAULTS, $this.data(), 1719 | typeof option === 'object' && option); 1720 | 1721 | if (typeof option === 'string') { 1722 | if ($.inArray(option, allowedMethods) < 0) { 1723 | throw "Unknown method: " + option; 1724 | } 1725 | 1726 | if (!data) { 1727 | return; 1728 | } 1729 | 1730 | value = data[option](_relatedTarget); 1731 | 1732 | if (option === 'destroy') { 1733 | $this.removeData('bootstrap.table'); 1734 | } 1735 | } 1736 | 1737 | if (!data) { 1738 | $this.data('bootstrap.table', (data = new BootstrapTable(this, options))); 1739 | } 1740 | }); 1741 | 1742 | return typeof value === 'undefined' ? this : value; 1743 | }; 1744 | 1745 | $.fn.bootstrapTable.Constructor = BootstrapTable; 1746 | $.fn.bootstrapTable.defaults = BootstrapTable.DEFAULTS; 1747 | $.fn.bootstrapTable.columnDefaults = BootstrapTable.COLUMN_DEFAULTS; 1748 | $.fn.bootstrapTable.locales = BootstrapTable.LOCALES; 1749 | $.fn.bootstrapTable.methods = allowedMethods; 1750 | 1751 | // BOOTSTRAP TABLE INIT 1752 | // ======================= 1753 | 1754 | $(function () { 1755 | $('[data-toggle="table"]').bootstrapTable(); 1756 | }); 1757 | 1758 | }(jQuery); -------------------------------------------------------------------------------- /static/js/jspdf/jspdf.js: -------------------------------------------------------------------------------- 1 | /** 2 | * jsPDF 3 | * (c) 2009 James Hall 4 | * 5 | * Some parts based on FPDF. 6 | */ 7 | 8 | var jsPDF = function(){ 9 | 10 | // Private properties 11 | var version = '20090504'; 12 | var buffer = ''; 13 | 14 | var pdfVersion = '1.3'; // PDF Version 15 | var defaultPageFormat = 'a4'; 16 | var pageFormats = { // Size in mm of various paper formats 17 | 'a3': [841.89, 1190.55], 18 | 'a4': [595.28, 841.89], 19 | 'a5': [420.94, 595.28], 20 | 'letter': [612, 792], 21 | 'legal': [612, 1008] 22 | }; 23 | var textColor = '0 g'; 24 | var page = 0; 25 | var objectNumber = 2; // 'n' Current object number 26 | var state = 0; // Current document state 27 | var pages = new Array(); 28 | var offsets = new Array(); // List of offsets 29 | var lineWidth = 0.200025; // 2mm 30 | var pageHeight; 31 | var k; // Scale factor 32 | var unit = 'mm'; // Default to mm for units 33 | var fontNumber; // TODO: This is temp, replace with real font handling 34 | var documentProperties = {}; 35 | var fontSize = 16; // Default font size 36 | var pageFontSize = 16; 37 | 38 | // Initilisation 39 | if (unit == 'pt') { 40 | k = 1; 41 | } else if(unit == 'mm') { 42 | k = 72/25.4; 43 | } else if(unit == 'cm') { 44 | k = 72/2.54; 45 | } else if(unit == 'in') { 46 | k = 72; 47 | } 48 | 49 | // Private functions 50 | var newObject = function() { 51 | //Begin a new object 52 | objectNumber ++; 53 | offsets[objectNumber] = buffer.length; 54 | out(objectNumber + ' 0 obj'); 55 | } 56 | 57 | 58 | var putHeader = function() { 59 | out('%PDF-' + pdfVersion); 60 | } 61 | 62 | var putPages = function() { 63 | 64 | // TODO: Fix, hardcoded to a4 portrait 65 | var wPt = pageWidth * k; 66 | var hPt = pageHeight * k; 67 | 68 | for(n=1; n <= page; n++) { 69 | newObject(); 70 | out('<>'); 74 | out('endobj'); 75 | 76 | //Page content 77 | p = pages[n]; 78 | newObject(); 79 | out('<>'); 80 | putStream(p); 81 | out('endobj'); 82 | } 83 | offsets[1] = buffer.length; 84 | out('1 0 obj'); 85 | out('<>'); 94 | out('endobj'); 95 | } 96 | 97 | var putStream = function(str) { 98 | out('stream'); 99 | out(str); 100 | out('endstream'); 101 | } 102 | 103 | var putResources = function() { 104 | putFonts(); 105 | putImages(); 106 | 107 | //Resource dictionary 108 | offsets[2] = buffer.length; 109 | out('2 0 obj'); 110 | out('<<'); 111 | putResourceDictionary(); 112 | out('>>'); 113 | out('endobj'); 114 | } 115 | 116 | var putFonts = function() { 117 | // TODO: Only supports core font hardcoded to Helvetica 118 | newObject(); 119 | fontNumber = objectNumber; 120 | name = 'Helvetica'; 121 | out('<>'); 126 | out('endobj'); 127 | } 128 | 129 | var putImages = function() { 130 | // TODO 131 | } 132 | 133 | var putResourceDictionary = function() { 134 | out('/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]'); 135 | out('/Font <<'); 136 | // Do this for each font, the '1' bit is the index of the font 137 | // fontNumber is currently the object number related to 'putFonts' 138 | out('/F1 ' + fontNumber + ' 0 R'); 139 | out('>>'); 140 | out('/XObject <<'); 141 | putXobjectDict(); 142 | out('>>'); 143 | } 144 | 145 | var putXobjectDict = function() { 146 | // TODO 147 | // Loop through images 148 | } 149 | 150 | 151 | var putInfo = function() { 152 | out('/Producer (jsPDF ' + version + ')'); 153 | if(documentProperties.title != undefined) { 154 | out('/Title (' + pdfEscape(documentProperties.title) + ')'); 155 | } 156 | if(documentProperties.subject != undefined) { 157 | out('/Subject (' + pdfEscape(documentProperties.subject) + ')'); 158 | } 159 | if(documentProperties.author != undefined) { 160 | out('/Author (' + pdfEscape(documentProperties.author) + ')'); 161 | } 162 | if(documentProperties.keywords != undefined) { 163 | out('/Keywords (' + pdfEscape(documentProperties.keywords) + ')'); 164 | } 165 | if(documentProperties.creator != undefined) { 166 | out('/Creator (' + pdfEscape(documentProperties.creator) + ')'); 167 | } 168 | var created = new Date(); 169 | var year = created.getFullYear(); 170 | var month = (created.getMonth() + 1); 171 | var day = created.getDate(); 172 | var hour = created.getHours(); 173 | var minute = created.getMinutes(); 174 | var second = created.getSeconds(); 175 | out('/CreationDate (D:' + sprintf('%02d%02d%02d%02d%02d%02d', year, month, day, hour, minute, second) + ')'); 176 | } 177 | 178 | var putCatalog = function () { 179 | out('/Type /Catalog'); 180 | out('/Pages 1 0 R'); 181 | // TODO: Add zoom and layout modes 182 | out('/OpenAction [3 0 R /FitH null]'); 183 | out('/PageLayout /OneColumn'); 184 | } 185 | 186 | function putTrailer() { 187 | out('/Size ' + (objectNumber + 1)); 188 | out('/Root ' + objectNumber + ' 0 R'); 189 | out('/Info ' + (objectNumber - 1) + ' 0 R'); 190 | } 191 | 192 | var endDocument = function() { 193 | state = 1; 194 | putHeader(); 195 | putPages(); 196 | 197 | putResources(); 198 | //Info 199 | newObject(); 200 | out('<<'); 201 | putInfo(); 202 | out('>>'); 203 | out('endobj'); 204 | 205 | //Catalog 206 | newObject(); 207 | out('<<'); 208 | putCatalog(); 209 | out('>>'); 210 | out('endobj'); 211 | 212 | //Cross-ref 213 | var o = buffer.length; 214 | out('xref'); 215 | out('0 ' + (objectNumber + 1)); 216 | out('0000000000 65535 f '); 217 | for (var i=1; i <= objectNumber; i++) { 218 | out(sprintf('%010d 00000 n ', offsets[i])); 219 | } 220 | //Trailer 221 | out('trailer'); 222 | out('<<'); 223 | putTrailer(); 224 | out('>>'); 225 | out('startxref'); 226 | out(o); 227 | out('%%EOF'); 228 | state = 3; 229 | } 230 | 231 | var beginPage = function() { 232 | page ++; 233 | // Do dimension stuff 234 | state = 2; 235 | pages[page] = ''; 236 | 237 | // TODO: Hardcoded at A4 and portrait 238 | pageHeight = pageFormats['a4'][1] / k; 239 | pageWidth = pageFormats['a4'][0] / k; 240 | } 241 | 242 | var out = function(string) { 243 | if(state == 2) { 244 | pages[page] += string + '\n'; 245 | } else { 246 | buffer += string + '\n'; 247 | } 248 | } 249 | 250 | var _addPage = function() { 251 | beginPage(); 252 | // Set line width 253 | out(sprintf('%.2f w', (lineWidth * k))); 254 | 255 | // Set font - TODO 256 | // 16 is the font size 257 | pageFontSize = fontSize; 258 | out('BT /F1 ' + parseInt(fontSize) + '.00 Tf ET'); 259 | } 260 | 261 | // Add the first page automatically 262 | _addPage(); 263 | 264 | // Escape text 265 | var pdfEscape = function(text) { 266 | return text.replace(/\\/g, '\\\\').replace(/\(/g, '\\(').replace(/\)/g, '\\)'); 267 | } 268 | 269 | return { 270 | addPage: function() { 271 | _addPage(); 272 | }, 273 | text: function(x, y, text) { 274 | // need page height 275 | if(pageFontSize != fontSize) { 276 | out('BT /F1 ' + parseInt(fontSize) + '.00 Tf ET'); 277 | pageFontSize = fontSize; 278 | } 279 | var str = sprintf('BT %.2f %.2f Td (%s) Tj ET', x * k, (pageHeight - y) * k, pdfEscape(text)); 280 | out(str); 281 | }, 282 | setProperties: function(properties) { 283 | documentProperties = properties; 284 | }, 285 | addImage: function(imageData, format, x, y, w, h) { 286 | 287 | }, 288 | output: function(type, options) { 289 | endDocument(); 290 | if(type == undefined) { 291 | return buffer; 292 | } 293 | if(type == 'datauri') { 294 | document.location.href = 'data:application/pdf;base64,' + Base64.encode(buffer); 295 | } 296 | // @TODO: Add different output options 297 | }, 298 | setFontSize: function(size) { 299 | fontSize = size; 300 | } 301 | } 302 | 303 | }; 304 | -------------------------------------------------------------------------------- /static/js/jspdf/libs/base64.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * 4 | * Base64 encode / decode 5 | * http://www.webtoolkit.info/ 6 | * 7 | **/ 8 | 9 | var Base64 = { 10 | 11 | // private property 12 | _keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=", 13 | 14 | // public method for encoding 15 | encode : function (input) { 16 | var output = ""; 17 | var chr1, chr2, chr3, enc1, enc2, enc3, enc4; 18 | var i = 0; 19 | 20 | input = Base64._utf8_encode(input); 21 | 22 | while (i < input.length) { 23 | 24 | chr1 = input.charCodeAt(i++); 25 | chr2 = input.charCodeAt(i++); 26 | chr3 = input.charCodeAt(i++); 27 | 28 | enc1 = chr1 >> 2; 29 | enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); 30 | enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); 31 | enc4 = chr3 & 63; 32 | 33 | if (isNaN(chr2)) { 34 | enc3 = enc4 = 64; 35 | } else if (isNaN(chr3)) { 36 | enc4 = 64; 37 | } 38 | 39 | output = output + 40 | this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) + 41 | this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4); 42 | 43 | } 44 | 45 | return output; 46 | }, 47 | 48 | // public method for decoding 49 | decode : function (input) { 50 | var output = ""; 51 | var chr1, chr2, chr3; 52 | var enc1, enc2, enc3, enc4; 53 | var i = 0; 54 | 55 | input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ""); 56 | 57 | while (i < input.length) { 58 | 59 | enc1 = this._keyStr.indexOf(input.charAt(i++)); 60 | enc2 = this._keyStr.indexOf(input.charAt(i++)); 61 | enc3 = this._keyStr.indexOf(input.charAt(i++)); 62 | enc4 = this._keyStr.indexOf(input.charAt(i++)); 63 | 64 | chr1 = (enc1 << 2) | (enc2 >> 4); 65 | chr2 = ((enc2 & 15) << 4) | (enc3 >> 2); 66 | chr3 = ((enc3 & 3) << 6) | enc4; 67 | 68 | output = output + String.fromCharCode(chr1); 69 | 70 | if (enc3 != 64) { 71 | output = output + String.fromCharCode(chr2); 72 | } 73 | if (enc4 != 64) { 74 | output = output + String.fromCharCode(chr3); 75 | } 76 | 77 | } 78 | 79 | output = Base64._utf8_decode(output); 80 | 81 | return output; 82 | 83 | }, 84 | 85 | // private method for UTF-8 encoding 86 | _utf8_encode : function (string) { 87 | string = string.replace(/\r\n/g,"\n"); 88 | var utftext = ""; 89 | 90 | for (var n = 0; n < string.length; n++) { 91 | 92 | var c = string.charCodeAt(n); 93 | 94 | if (c < 128) { 95 | utftext += String.fromCharCode(c); 96 | } 97 | else if((c > 127) && (c < 2048)) { 98 | utftext += String.fromCharCode((c >> 6) | 192); 99 | utftext += String.fromCharCode((c & 63) | 128); 100 | } 101 | else { 102 | utftext += String.fromCharCode((c >> 12) | 224); 103 | utftext += String.fromCharCode(((c >> 6) & 63) | 128); 104 | utftext += String.fromCharCode((c & 63) | 128); 105 | } 106 | 107 | } 108 | 109 | return utftext; 110 | }, 111 | 112 | // private method for UTF-8 decoding 113 | _utf8_decode : function (utftext) { 114 | var string = ""; 115 | var i = 0; 116 | var c = c1 = c2 = 0; 117 | 118 | while ( i < utftext.length ) { 119 | 120 | c = utftext.charCodeAt(i); 121 | 122 | if (c < 128) { 123 | string += String.fromCharCode(c); 124 | i++; 125 | } 126 | else if((c > 191) && (c < 224)) { 127 | c2 = utftext.charCodeAt(i+1); 128 | string += String.fromCharCode(((c & 31) << 6) | (c2 & 63)); 129 | i += 2; 130 | } 131 | else { 132 | c2 = utftext.charCodeAt(i+1); 133 | c3 = utftext.charCodeAt(i+2); 134 | string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63)); 135 | i += 3; 136 | } 137 | 138 | } 139 | 140 | return string; 141 | } 142 | 143 | } 144 | -------------------------------------------------------------------------------- /static/js/jspdf/libs/sprintf.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | function sprintf( ) { 4 | // Return a formatted string 5 | // 6 | // version: 903.3016 7 | // discuss at: http://phpjs.org/functions/sprintf 8 | // + original by: Ash Searle (http://hexmen.com/blog/) 9 | // + namespaced by: Michael White (http://getsprink.com) 10 | // + tweaked by: Jack 11 | // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) 12 | // + input by: Paulo Ricardo F. Santos 13 | // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) 14 | // + input by: Brett Zamir (http://brettz9.blogspot.com) 15 | // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) 16 | // * example 1: sprintf("%01.2f", 123.1); 17 | // * returns 1: 123.10 18 | // * example 2: sprintf("[%10s]", 'monkey'); 19 | // * returns 2: '[ monkey]' 20 | // * example 3: sprintf("[%'#10s]", 'monkey'); 21 | // * returns 3: '[####monkey]' 22 | var regex = /%%|%(\d+\$)?([-+\'#0 ]*)(\*\d+\$|\*|\d+)?(\.(\*\d+\$|\*|\d+))?([scboxXuidfegEG])/g; 23 | var a = arguments, i = 0, format = a[i++]; 24 | 25 | // pad() 26 | var pad = function(str, len, chr, leftJustify) { 27 | if (!chr) chr = ' '; 28 | var padding = (str.length >= len) ? '' : Array(1 + len - str.length >>> 0).join(chr); 29 | return leftJustify ? str + padding : padding + str; 30 | }; 31 | 32 | // justify() 33 | var justify = function(value, prefix, leftJustify, minWidth, zeroPad, customPadChar) { 34 | var diff = minWidth - value.length; 35 | if (diff > 0) { 36 | if (leftJustify || !zeroPad) { 37 | value = pad(value, minWidth, customPadChar, leftJustify); 38 | } else { 39 | value = value.slice(0, prefix.length) + pad('', diff, '0', true) + value.slice(prefix.length); 40 | } 41 | } 42 | return value; 43 | }; 44 | 45 | // formatBaseX() 46 | var formatBaseX = function(value, base, prefix, leftJustify, minWidth, precision, zeroPad) { 47 | // Note: casts negative numbers to positive ones 48 | var number = value >>> 0; 49 | prefix = prefix && number && {'2': '0b', '8': '0', '16': '0x'}[base] || ''; 50 | value = prefix + pad(number.toString(base), precision || 0, '0', false); 51 | return justify(value, prefix, leftJustify, minWidth, zeroPad); 52 | }; 53 | 54 | // formatString() 55 | var formatString = function(value, leftJustify, minWidth, precision, zeroPad, customPadChar) { 56 | if (precision != null) { 57 | value = value.slice(0, precision); 58 | } 59 | return justify(value, '', leftJustify, minWidth, zeroPad, customPadChar); 60 | }; 61 | 62 | // doFormat() 63 | var doFormat = function(substring, valueIndex, flags, minWidth, _, precision, type) { 64 | var number; 65 | var prefix; 66 | var method; 67 | var textTransform; 68 | var value; 69 | 70 | if (substring == '%%') return '%'; 71 | 72 | // parse flags 73 | var leftJustify = false, positivePrefix = '', zeroPad = false, prefixBaseX = false, customPadChar = ' '; 74 | var flagsl = flags.length; 75 | for (var j = 0; flags && j < flagsl; j++) switch (flags.charAt(j)) { 76 | case ' ': positivePrefix = ' '; break; 77 | case '+': positivePrefix = '+'; break; 78 | case '-': leftJustify = true; break; 79 | case "'": customPadChar = flags.charAt(j+1); break; 80 | case '0': zeroPad = true; break; 81 | case '#': prefixBaseX = true; break; 82 | } 83 | 84 | // parameters may be null, undefined, empty-string or real valued 85 | // we want to ignore null, undefined and empty-string values 86 | if (!minWidth) { 87 | minWidth = 0; 88 | } else if (minWidth == '*') { 89 | minWidth = +a[i++]; 90 | } else if (minWidth.charAt(0) == '*') { 91 | minWidth = +a[minWidth.slice(1, -1)]; 92 | } else { 93 | minWidth = +minWidth; 94 | } 95 | 96 | // Note: undocumented perl feature: 97 | if (minWidth < 0) { 98 | minWidth = -minWidth; 99 | leftJustify = true; 100 | } 101 | 102 | if (!isFinite(minWidth)) { 103 | throw new Error('sprintf: (minimum-)width must be finite'); 104 | } 105 | 106 | if (!precision) { 107 | precision = 'fFeE'.indexOf(type) > -1 ? 6 : (type == 'd') ? 0 : void(0); 108 | } else if (precision == '*') { 109 | precision = +a[i++]; 110 | } else if (precision.charAt(0) == '*') { 111 | precision = +a[precision.slice(1, -1)]; 112 | } else { 113 | precision = +precision; 114 | } 115 | 116 | // grab value using valueIndex if required? 117 | value = valueIndex ? a[valueIndex.slice(0, -1)] : a[i++]; 118 | 119 | switch (type) { 120 | case 's': return formatString(String(value), leftJustify, minWidth, precision, zeroPad, customPadChar); 121 | case 'c': return formatString(String.fromCharCode(+value), leftJustify, minWidth, precision, zeroPad); 122 | case 'b': return formatBaseX(value, 2, prefixBaseX, leftJustify, minWidth, precision, zeroPad); 123 | case 'o': return formatBaseX(value, 8, prefixBaseX, leftJustify, minWidth, precision, zeroPad); 124 | case 'x': return formatBaseX(value, 16, prefixBaseX, leftJustify, minWidth, precision, zeroPad); 125 | case 'X': return formatBaseX(value, 16, prefixBaseX, leftJustify, minWidth, precision, zeroPad).toUpperCase(); 126 | case 'u': return formatBaseX(value, 10, prefixBaseX, leftJustify, minWidth, precision, zeroPad); 127 | case 'i': 128 | case 'd': { 129 | number = parseInt(+value); 130 | prefix = number < 0 ? '-' : positivePrefix; 131 | value = prefix + pad(String(Math.abs(number)), precision, '0', false); 132 | return justify(value, prefix, leftJustify, minWidth, zeroPad); 133 | } 134 | case 'e': 135 | case 'E': 136 | case 'f': 137 | case 'F': 138 | case 'g': 139 | case 'G': { 140 | number = +value; 141 | prefix = number < 0 ? '-' : positivePrefix; 142 | method = ['toExponential', 'toFixed', 'toPrecision']['efg'.indexOf(type.toLowerCase())]; 143 | textTransform = ['toString', 'toUpperCase']['eEfFgG'.indexOf(type) % 2]; 144 | value = prefix + Math.abs(number)[method](precision); 145 | return justify(value, prefix, leftJustify, minWidth, zeroPad)[textTransform](); 146 | } 147 | default: return substring; 148 | } 149 | }; 150 | 151 | return format.replace(regex, doFormat); 152 | } 153 | -------------------------------------------------------------------------------- /static/js/npm.js: -------------------------------------------------------------------------------- 1 | // This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment. 2 | require('./umd/util.js') 3 | require('./umd/alert.js') 4 | require('./umd/button.js') 5 | require('./umd/carousel.js') 6 | require('./umd/collapse.js') 7 | require('./umd/dropdown.js') 8 | require('./umd/modal.js') 9 | require('./umd/scrollspy.js') 10 | require('./umd/tab.js') 11 | require('./umd/tooltip.js') 12 | require('./umd/popover.js') -------------------------------------------------------------------------------- /static/js/tableExport.js: -------------------------------------------------------------------------------- 1 | /*The MIT License (MIT) 2 | 3 | Copyright (c) 2014 https://github.com/kayalshri/ 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE.*/ 22 | 23 | (function($){ 24 | $.fn.extend({ 25 | tableExport: function(options) { 26 | var defaults = { 27 | separator: ',', 28 | ignoreColumn: [], 29 | tableName:'yourTableName', 30 | type:'csv', 31 | pdfFontSize:14, 32 | pdfLeftMargin:20, 33 | escape:'true', 34 | htmlContent:'false', 35 | consoleLog:'false' 36 | }; 37 | 38 | var options = $.extend(defaults, options); 39 | var el = this; 40 | 41 | if(defaults.type == 'csv' || defaults.type == 'txt'){ 42 | 43 | // Header 44 | var tdData =""; 45 | $(el).find('thead').find('tr').each(function() { 46 | tdData += "\n"; 47 | $(this).filter(':visible').find('th').each(function(index,data) { 48 | if ($(this).css('display') != 'none'){ 49 | if(defaults.ignoreColumn.indexOf(index) == -1){ 50 | tdData += '"' + parseString($(this)) + '"' + defaults.separator; 51 | } 52 | } 53 | 54 | }); 55 | tdData = $.trim(tdData); 56 | tdData = $.trim(tdData).substring(0, tdData.length -1); 57 | }); 58 | 59 | // Row vs Column 60 | $(el).find('tbody').find('tr').each(function() { 61 | tdData += "\n"; 62 | $(this).filter(':visible').find('td').each(function(index,data) { 63 | if ($(this).css('display') != 'none'){ 64 | if(defaults.ignoreColumn.indexOf(index) == -1){ 65 | tdData += '"'+ parseString($(this)) + '"'+ defaults.separator; 66 | } 67 | } 68 | }); 69 | //tdData = $.trim(tdData); 70 | tdData = $.trim(tdData).substring(0, tdData.length -1); 71 | }); 72 | 73 | //output 74 | if(defaults.consoleLog == 'true'){ 75 | console.log(tdData); 76 | } 77 | var base64data = "base64," + $.base64.encode(tdData); 78 | window.open('data:application/'+defaults.type+';filename=exportData;' + base64data); 79 | }else if(defaults.type == 'sql'){ 80 | 81 | // Header 82 | var tdData ="INSERT INTO `"+defaults.tableName+"` ("; 83 | $(el).find('thead').find('tr').each(function() { 84 | 85 | $(this).filter(':visible').find('th').each(function(index,data) { 86 | if ($(this).css('display') != 'none'){ 87 | if(defaults.ignoreColumn.indexOf(index) == -1){ 88 | tdData += '`' + parseString($(this)) + '`,' ; 89 | } 90 | } 91 | 92 | }); 93 | tdData = $.trim(tdData); 94 | tdData = $.trim(tdData).substring(0, tdData.length -1); 95 | }); 96 | tdData += ") VALUES "; 97 | // Row vs Column 98 | $(el).find('tbody').find('tr').each(function() { 99 | tdData += "("; 100 | $(this).filter(':visible').find('td').each(function(index,data) { 101 | if ($(this).css('display') != 'none'){ 102 | if(defaults.ignoreColumn.indexOf(index) == -1){ 103 | tdData += '"'+ parseString($(this)) + '",'; 104 | } 105 | } 106 | }); 107 | 108 | tdData = $.trim(tdData).substring(0, tdData.length -1); 109 | tdData += "),"; 110 | }); 111 | tdData = $.trim(tdData).substring(0, tdData.length -1); 112 | tdData += ";"; 113 | 114 | //output 115 | //console.log(tdData); 116 | 117 | if(defaults.consoleLog == 'true'){ 118 | console.log(tdData); 119 | } 120 | 121 | var base64data = "base64," + $.base64.encode(tdData); 122 | window.open('data:application/sql;filename=exportData;' + base64data); 123 | 124 | 125 | }else if(defaults.type == 'json'){ 126 | 127 | var jsonHeaderArray = []; 128 | $(el).find('thead').find('tr').each(function() { 129 | var tdData =""; 130 | var jsonArrayTd = []; 131 | 132 | $(this).filter(':visible').find('th').each(function(index,data) { 133 | if ($(this).css('display') != 'none'){ 134 | if(defaults.ignoreColumn.indexOf(index) == -1){ 135 | jsonArrayTd.push(parseString($(this))); 136 | } 137 | } 138 | }); 139 | jsonHeaderArray.push(jsonArrayTd); 140 | 141 | }); 142 | 143 | var jsonArray = []; 144 | $(el).find('tbody').find('tr').each(function() { 145 | var tdData =""; 146 | var jsonArrayTd = []; 147 | 148 | $(this).filter(':visible').find('td').each(function(index,data) { 149 | if ($(this).css('display') != 'none'){ 150 | if(defaults.ignoreColumn.indexOf(index) == -1){ 151 | jsonArrayTd.push(parseString($(this))); 152 | } 153 | } 154 | }); 155 | jsonArray.push(jsonArrayTd); 156 | 157 | }); 158 | 159 | var jsonExportArray =[]; 160 | jsonExportArray.push({header:jsonHeaderArray,data:jsonArray}); 161 | 162 | //Return as JSON 163 | //console.log(JSON.stringify(jsonExportArray)); 164 | 165 | //Return as Array 166 | //console.log(jsonExportArray); 167 | if(defaults.consoleLog == 'true'){ 168 | console.log(JSON.stringify(jsonExportArray)); 169 | } 170 | var base64data = "base64," + $.base64.encode(JSON.stringify(jsonExportArray)); 171 | window.open('data:application/json;filename=exportData;' + base64data); 172 | }else if(defaults.type == 'xml'){ 173 | 174 | var xml = ''; 175 | xml += ''; 176 | 177 | // Header 178 | $(el).find('thead').find('tr').each(function() { 179 | $(this).filter(':visible').find('th').each(function(index,data) { 180 | if ($(this).css('display') != 'none'){ 181 | if(defaults.ignoreColumn.indexOf(index) == -1){ 182 | xml += "" + parseString($(this)) + ""; 183 | } 184 | } 185 | }); 186 | }); 187 | xml += ''; 188 | 189 | // Row Vs Column 190 | var rowCount=1; 191 | $(el).find('tbody').find('tr').each(function() { 192 | xml += ''; 193 | var colCount=0; 194 | $(this).filter(':visible').find('td').each(function(index,data) { 195 | if ($(this).css('display') != 'none'){ 196 | if(defaults.ignoreColumn.indexOf(index) == -1){ 197 | xml += ""+parseString($(this))+""; 198 | } 199 | } 200 | colCount++; 201 | }); 202 | rowCount++; 203 | xml += ''; 204 | }); 205 | xml += '' 206 | 207 | if(defaults.consoleLog == 'true'){ 208 | console.log(xml); 209 | } 210 | 211 | var base64data = "base64," + $.base64.encode(xml); 212 | window.open('data:application/xml;filename=exportData;' + base64data); 213 | 214 | }else if(defaults.type == 'excel' || defaults.type == 'doc'|| defaults.type == 'powerpoint' ){ 215 | //console.log($(this).html()); 216 | var excel=""; 217 | // Header 218 | $(el).find('thead').find('tr').each(function() { 219 | excel += ""; 220 | $(this).filter(':visible').find('th').each(function(index,data) { 221 | if ($(this).css('display') != 'none'){ 222 | if(defaults.ignoreColumn.indexOf(index) == -1){ 223 | excel += ""; 224 | } 225 | } 226 | }); 227 | excel += ''; 228 | 229 | }); 230 | 231 | 232 | // Row Vs Column 233 | var rowCount=1; 234 | $(el).find('tbody').find('tr').each(function() { 235 | excel += ""; 236 | var colCount=0; 237 | $(this).filter(':visible').find('td').each(function(index,data) { 238 | if ($(this).css('display') != 'none'){ 239 | if(defaults.ignoreColumn.indexOf(index) == -1){ 240 | excel += ""; 241 | } 242 | } 243 | colCount++; 244 | }); 245 | rowCount++; 246 | excel += ''; 247 | }); 248 | excel += '
    " + parseString($(this))+ "
    "+parseString($(this))+"
    ' 249 | 250 | if(defaults.consoleLog == 'true'){ 251 | console.log(excel); 252 | } 253 | 254 | var excelFile = ""; 255 | excelFile += ""; 256 | excelFile += ""; 272 | excelFile += ""; 273 | excelFile += ""; 274 | excelFile += excel; 275 | excelFile += ""; 276 | excelFile += ""; 277 | 278 | var base64data = "base64," + $.base64.encode(excelFile); 279 | window.open('data:application/vnd.ms-'+defaults.type+';filename=exportData.doc;' + base64data); 280 | 281 | }else if(defaults.type == 'png'){ 282 | html2canvas($(el), { 283 | onrendered: function(canvas) { 284 | var img = canvas.toDataURL("image/png"); 285 | window.open(img); 286 | 287 | 288 | } 289 | }); 290 | }else if(defaults.type == 'pdf'){ 291 | 292 | var doc = new jsPDF('p','pt', 'a4', true); 293 | doc.setFontSize(defaults.pdfFontSize); 294 | 295 | // Header 296 | var startColPosition=defaults.pdfLeftMargin; 297 | $(el).find('thead').find('tr').each(function() { 298 | $(this).filter(':visible').find('th').each(function(index,data) { 299 | if ($(this).css('display') != 'none'){ 300 | if(defaults.ignoreColumn.indexOf(index) == -1){ 301 | var colPosition = startColPosition+ (index * 50); 302 | doc.text(colPosition,20, parseString($(this))); 303 | } 304 | } 305 | }); 306 | }); 307 | 308 | 309 | // Row Vs Column 310 | var startRowPosition = 20; var page =1;var rowPosition=0; 311 | $(el).find('tbody').find('tr').each(function(index,data) { 312 | rowCalc = index+1; 313 | 314 | if (rowCalc % 26 == 0){ 315 | doc.addPage(); 316 | page++; 317 | startRowPosition=startRowPosition+10; 318 | } 319 | rowPosition=(startRowPosition + (rowCalc * 10)) - ((page -1) * 280); 320 | 321 | $(this).filter(':visible').find('td').each(function(index,data) { 322 | if ($(this).css('display') != 'none'){ 323 | if(defaults.ignoreColumn.indexOf(index) == -1){ 324 | var colPosition = startColPosition+ (index * 50); 325 | doc.text(colPosition,rowPosition, parseString($(this))); 326 | } 327 | } 328 | 329 | }); 330 | 331 | }); 332 | 333 | // Output as Data URI 334 | doc.output('datauri'); 335 | 336 | } 337 | 338 | 339 | function parseString(data){ 340 | 341 | if(defaults.htmlContent == 'true'){ 342 | content_data = data.html().trim(); 343 | }else{ 344 | content_data = data.text().trim(); 345 | } 346 | 347 | if(defaults.escape == 'true'){ 348 | content_data = escape(content_data); 349 | } 350 | 351 | 352 | 353 | return content_data; 354 | } 355 | 356 | } 357 | }); 358 | })(jQuery); 359 | 360 | -------------------------------------------------------------------------------- /templates/404.html: -------------------------------------------------------------------------------- 1 | {% include "partials/header.html" %} 2 | {% block content %} 3 |
    4 |
    5 |

    Error Message

    6 |
    7 |
    8 | {{ error }} 9 |
    10 |
    11 | {% endblock %} 12 | {% include "partials/footer.html" %} -------------------------------------------------------------------------------- /templates/graph.html: -------------------------------------------------------------------------------- 1 | {% include "partials/header.html" %} 2 | {% include "partials/navbar.html" %} 3 |
    4 |
    5 |
    6 |
    7 |
    8 |
    9 |

    Entity Information - {{ filename }}

    10 |
    11 |
    12 | {% block content %} 13 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | {% for i in output %} 34 | 35 | 36 | 37 | 38 | 39 | 40 | {% endfor %} 41 | 42 |
    Entity TypeDataIncoming LinksOutgoing Links
    {{ i['EntityType'] }}{{ i['Data']|wordwrap }}{{ i['Links']['Incoming']|length}}{{ i['Links']['Outgoing']|length}}
    43 |
    44 |
    45 |
    46 | {% endblock %} 47 | 48 | 49 | {% include "partials/footer.html" %} -------------------------------------------------------------------------------- /templates/home.html: -------------------------------------------------------------------------------- 1 | {% include "partials/header.html" %} 2 | {% include "partials/navbar.html" %} 3 |
    4 |
    5 |
    6 |
    7 |
    8 |
    9 |

    Upload Maltego Graph

    10 |
    11 |
    12 | 19 |
    20 |
    21 |
    22 |
    23 |
    24 |
    25 |

    List of exported graphs

    26 |
    27 |
    28 | {% block content %} 29 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | {% for s in list %} 46 | 47 | 48 | 49 | 50 | {% endfor %} 51 | 52 |
    NameCreated
    {{ s[0] }}{{ s[1] }}
    53 | 54 | {% endblock %} 55 |
    56 |
    57 |
    58 |
    59 | 60 |
    61 | {% include "partials/footer.html" %} -------------------------------------------------------------------------------- /templates/partials/footer.html: -------------------------------------------------------------------------------- 1 |
    2 | 3 | 4 | 5 | 6 | 7 | 8 | 16 | 24 | 32 |
    33 |
    34 | 35 | -------------------------------------------------------------------------------- /templates/partials/header.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Pandora - Maltego Graph Exporter 5 |
    6 | 7 | 8 | 9 | 10 | 11 |
    -------------------------------------------------------------------------------- /templates/partials/navbar.html: -------------------------------------------------------------------------------- 1 |
    15 | -------------------------------------------------------------------------------- /templates/popup-links.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Pandora - Maltego Graph Exporter 5 | 6 | 7 | 8 | 9 | 10 |
    11 |
    12 |
    13 |
    14 |
    15 |
    16 |
    17 |

    {{ direction }} Links - {{ nodeid }}

    18 |
    19 |
    20 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | {% for r in records %} 39 | 40 | 41 | 42 | 43 | {% endfor %} 44 | 45 |
    Entity TypeData
    {{ r[0] }}{{ r[1]|wordwrap }}
    46 |
    47 |
    48 |
    49 | 50 | 51 |
    52 | 53 | 54 | 55 | 56 | 57 | 58 | 66 | 74 | 82 |
    83 |
    84 | 85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /webserver.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | 4 | from flask import Flask, render_template, request, redirect 5 | from werkzeug import secure_filename 6 | from core import * 7 | 8 | app = Flask(__name__) 9 | 10 | 11 | @app.route('/', methods=['GET']) 12 | def home(): 13 | l = list_graphs() 14 | return render_template('home.html', list=l) 15 | 16 | 17 | @app.route('/graph/', methods=['GET']) 18 | def graph(filename): 19 | g = 'output/%s' % filename 20 | in_file = open(g, 'r') 21 | new_dict = json.load(in_file) 22 | in_file.close() 23 | return render_template('graph.html', filename=filename, output=new_dict) 24 | 25 | 26 | @app.route('/upload', methods=['GET', 'POST']) 27 | def upload(): 28 | try: 29 | f = request.files['file'] 30 | filename = secure_filename(f.filename) 31 | graph_json(f, filename) 32 | return redirect('/', code=302) 33 | except Exception as e: 34 | return render_template('404.html', error=e) 35 | 36 | 37 | @app.route('/graph///', methods=['GET']) 38 | def get_links(filename, direction, nodeid): 39 | links = [] 40 | records = [] 41 | d = direction.capitalize() 42 | g = 'output/%s' % filename 43 | in_file = open(g, 'r') 44 | data = json.load(in_file) 45 | for x in data: 46 | if nodeid == x['NodeID']: 47 | for s in x['Links'][d]: 48 | if s not in links: 49 | links.append(s) 50 | for l in links: 51 | for t in data: 52 | if l == t['NodeID']: 53 | rec = t['EntityType'], t['Data'] 54 | if rec not in records: 55 | records.append(rec) 56 | return render_template('popup-links.html', filename=filename, direction=d, nodeid=nodeid, records=records) 57 | 58 | 59 | @app.errorhandler(404) 60 | def not_found(error): 61 | e = 'Whoops, page not found!!!..try again' 62 | return render_template('404.html', error=e) 63 | 64 | 65 | if __name__ == '__main__': 66 | app.run(debug=True) 67 | --------------------------------------------------------------------------------