├── test ├── .empty ├── angles.html └── angles_test.js ├── .git-ref ├── demo ├── img │ ├── readme_start.png │ ├── readme_context.png │ ├── readme_loadsave.png │ ├── glyphicons-halflings.png │ ├── readme_notification.png │ ├── angles_logo_red-trans.eps │ ├── angles_logo_red-trans.png │ └── glyphicons-halflings-white.png ├── GoogleDriveStorage.js ├── README.md ├── index.html ├── srvValidation.html ├── css │ ├── bootstrap-responsive.min.css │ ├── jasny-bootstrap.min.css │ └── bootstrap-responsive.css └── js │ └── jasny-bootstrap.min.js ├── .gitmodules ├── version.js ├── .gitignore ├── deps ├── config.js └── client.js ├── bower.json ├── src ├── contextHelp.coffee ├── notificationCenter.coffee ├── validator.coffee ├── fileUploader.coffee ├── validatorSRV.coffee ├── validatorSAX.coffee └── angles-editor-view.coffee ├── package.json ├── COPYING.md ├── resources ├── rng2js.xsl └── tei_all.odd ├── Gruntfile.js ├── README.md └── dist └── angles.min.js /test/.empty: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.git-ref: -------------------------------------------------------------------------------- 1 | 5b36385234833c51e2bc01e3fe8feb85918cf68a 2 | -------------------------------------------------------------------------------- /demo/img/readme_start.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/umd-mith/angles/HEAD/demo/img/readme_start.png -------------------------------------------------------------------------------- /demo/img/readme_context.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/umd-mith/angles/HEAD/demo/img/readme_context.png -------------------------------------------------------------------------------- /demo/img/readme_loadsave.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/umd-mith/angles/HEAD/demo/img/readme_loadsave.png -------------------------------------------------------------------------------- /demo/img/glyphicons-halflings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/umd-mith/angles/HEAD/demo/img/glyphicons-halflings.png -------------------------------------------------------------------------------- /demo/img/readme_notification.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/umd-mith/angles/HEAD/demo/img/readme_notification.png -------------------------------------------------------------------------------- /demo/img/angles_logo_red-trans.eps: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/umd-mith/angles/HEAD/demo/img/angles_logo_red-trans.eps -------------------------------------------------------------------------------- /demo/img/angles_logo_red-trans.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/umd-mith/angles/HEAD/demo/img/angles_logo_red-trans.png -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "vendor/isaacs/sax-js"] 2 | path = vendor/isaacs/sax-js 3 | url = https://github.com/isaacs/sax-js.git 4 | -------------------------------------------------------------------------------- /demo/img/glyphicons-halflings-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/umd-mith/angles/HEAD/demo/img/glyphicons-halflings-white.png -------------------------------------------------------------------------------- /version.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | var x; 3 | eval("x= " + require("fs").readFileSync(__dirname + "/package.json")) 4 | console.log(x.version) 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Junk that could exist anywhere: 2 | .DS_Store 3 | *.swp 4 | *.tmp 5 | 6 | node_modules/ 7 | bower_components/ 8 | app/ 9 | .grunt 10 | -------------------------------------------------------------------------------- /deps/config.js: -------------------------------------------------------------------------------- 1 | var config = { 2 | 'client_id': '{PUT YOUR ID HERE}.apps.googleusercontent.com', 3 | 'scope': ['https://www.googleapis.com/auth/drive',"https://www.googleapis.com/auth/drive.file"] 4 | }; -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angles", 3 | "version": "0.1.0", 4 | "dependencies": { 5 | "jquery": "~2.0.3", 6 | "ace-builds": "1.1.1", 7 | "underscore": "~1.5.1", 8 | "backbone": "1.0.0" 9 | }, 10 | "main": "dist/angles.js", 11 | "devDependencies": { 12 | "qunit": "~1.11.0" 13 | }, 14 | "ignore": [ 15 | "**/.*", 16 | "node_modules", 17 | "components", 18 | "bower_components", 19 | "test", 20 | "tests" 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /src/contextHelp.coffee: -------------------------------------------------------------------------------- 1 | # --- ContextHelp --- 2 | 3 | class Angles.ContextHelp 4 | constructor: (options) -> 5 | dispatcher = @dispatcher = options.dispatcher 6 | @$odd = {} 7 | @$angles = options.anglesView 8 | 9 | setODD: (o) -> @$odd = o 10 | 11 | getODDfor: (e) -> 12 | elements = @$odd.members 13 | for item in elements 14 | if item.ident == e 15 | return item 16 | null 17 | 18 | getDescOf: (e) -> @getODDfor(e)?.desc 19 | 20 | getChildrenOf: (e) -> 21 | @getODDfor(e)?.children -------------------------------------------------------------------------------- /src/notificationCenter.coffee: -------------------------------------------------------------------------------- 1 | # --- NotificationCenter --- 2 | 3 | class Angles.NotificationCenter 4 | constructor: (options) -> 5 | dispatcher = @dispatcher = options.dispatcher 6 | 7 | @$angles = options.anglesView 8 | @$notifications = new Angles.NotificationList() 9 | 10 | #console.log(@$notifications) 11 | 12 | dispatcher.on "notification:push", (e) => @push e 13 | 14 | dispatcher.on "notification:clear", (e) => @clear() 15 | 16 | push: (m) -> 17 | @$notifications.add m 18 | 19 | clear: -> 20 | m.destroy() while m = @$notifications.first() 21 | null -------------------------------------------------------------------------------- /src/validator.coffee: -------------------------------------------------------------------------------- 1 | # --- Validator --- 2 | 3 | class Angles.Validator 4 | constructor: (options) -> 5 | dispatcher = @dispatcher = options.dispatcher 6 | @$schema = {} 7 | @$errors = [] 8 | @$angles = options.anglesView 9 | 10 | displayErrors: -> 11 | for e in @errors() 12 | @dispatcher.trigger "validation:error", e 13 | @endValidation() 14 | 15 | addError: (e) -> 16 | @$errors.push e 17 | 18 | clearErrors: -> @$errors = [] 19 | 20 | endValidation: -> 21 | @dispatcher.trigger "validation:end" 22 | 23 | setSchema: (s) -> 24 | @$schema = s 25 | @dispatcher.trigger "validation" 26 | 27 | errors: -> @$errors 28 | 29 | hasErrors: -> @$errors.length != 0 -------------------------------------------------------------------------------- /src/fileUploader.coffee: -------------------------------------------------------------------------------- 1 | # --- FileUploader --- 2 | 3 | class Angles.FileUploader 4 | constructor: (options) -> 5 | dispatcher = @dispatcher = options.dispatcher 6 | @$angles = options.anglesView 7 | @storedFiles = options.storedFiles 8 | 9 | _handleFileSelect: (evt) => 10 | file = evt.target.files[0] 11 | 12 | reader = new FileReader() 13 | 14 | reader.onload = (e) => 15 | 16 | same_name = @storedFiles.find (model) -> 17 | return model.get('name') == file.name 18 | 19 | # Overwrite if already in Local Storage 20 | if same_name? 21 | same_name.destroy() 22 | 23 | # Save new document on Local Storage 24 | newModel = @storedFiles.create 25 | name: file.name, 26 | content: e.target.result 27 | @dispatcher.trigger "document:switch", newModel 28 | 29 | reader.readAsText(file,"UTF-8") 30 | 31 | bind: (el) -> 32 | $(el).change @_handleFileSelect -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angles", 3 | "description": "XML editing mode for the Ajax.org Code Editor with support for TEI", 4 | "version": "0.1.0", 5 | "homepage": "https://github.com/umd-mith/angles", 6 | "engines": {"node": ">= 0.6.0"}, 7 | "main": "dist/angles.js", 8 | "repository": { 9 | "type": "git", 10 | "url" : "https://github.com/umd-mith/angles.git" 11 | }, 12 | "dependencies": { 13 | }, 14 | "devDependencies": { 15 | "grunt": "0.4.1", 16 | "grunt-cli": "latest", 17 | "grunt-contrib-uglify": "~0.2.2", 18 | "grunt-contrib-clean": "latest", 19 | "grunt-contrib-qunit": "~0.2.2", 20 | "grunt-contrib-coffee": "latest", 21 | "shelljs": "latest", 22 | "rimraf": "~2.2.1", 23 | "bower": "latest" 24 | }, 25 | "scripts": { 26 | "test": "grunt test" 27 | }, 28 | "mappings": { 29 | "angles": "." 30 | }, 31 | "licenses": [{ 32 | "type": "BSD New", 33 | "url": "http://opensource.org/licenses/BSD-3-Clause" 34 | }], 35 | "directories": { 36 | "lib": "dist/angles" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /COPYING.md: -------------------------------------------------------------------------------- 1 | Except as noted in individual files, files in this project are distributed under the BSD license: 2 | 3 | Copyright (c) 2010, Ajax.org B.V. Copyright (c) 2012-2013, University of Maryland. All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or withoutmodification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 9 | * Neither the name of University of Maryland nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF MARYLAND BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 12 | -------------------------------------------------------------------------------- /test/angles.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Test Test Suite 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 24 | 25 | 26 | 27 | 30 | 31 | 32 | 33 |
34 |
35 | subpar test markup 36 | normal test markup 37 | awesome test markup 38 |
39 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /src/validatorSRV.coffee: -------------------------------------------------------------------------------- 1 | # --- ValidatorSRV - Extends Validator --- 2 | 3 | class Angles.ValidatorSRV extends Angles.Validator 4 | constructor: (options) -> 5 | super(options) 6 | @$validatorUrl = options.validator 7 | 8 | # If an ajax request to a server and a request handler are provided, set them here. 9 | # Otherwise use example handlers below. 10 | @$requestHandler = if options.requestHandler? then options.requestHandler else requestHandler 11 | @$validationHandler = if options.validationHandler? then options.validationHandler else validationHandler 12 | 13 | @dispatcher.on "validation", => 14 | @dispatcher.trigger "validation:start" 15 | @$requestHandler @ 16 | 17 | # Override this, or provide your own validation handler if your validator returns a different response 18 | requestHandler = (validator) -> 19 | doc = validator.$angles.getDocument() 20 | xmlDocument = escape(doc.getValue()) 21 | $.ajax 22 | url: validator.$validatorUrl 23 | type: "POST" 24 | crossDomain: true 25 | processData: false 26 | data: "schema="+validator.$schema+"&document="+xmlDocument 27 | dataType: "json", 28 | success: (data) -> 29 | validator.$validationHandler validator, data 30 | error: (xhr, textStatus, thrownError, data) => 31 | @dispatcher.trigger 'notification:clear' 32 | thrownError = if xhr.status == 0 then "Cannot reach server" else thrownError 33 | n = 34 | type: "Server" 35 | info: "Status: " + xhr.status 36 | message: thrownError 37 | location: 38 | row: -1 39 | column: -1 40 | @dispatcher.trigger 'notification:push', n 41 | 42 | # Override this, or provide your own validation handler if your validator returns a different response 43 | validationHandler = (validator, data) -> 44 | validator.$errors = [] 45 | for datum in data 46 | validator.$errors.push 47 | text: datum.message 48 | row: datum.line-1 49 | column: datum.column 50 | type: datum.type 51 | validator.displayErrors() -------------------------------------------------------------------------------- /resources/rng2js.xsl: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | xml: 11 | 12 | 13 | 14 | 15 | schema({ 16 | , 17 | 18 | , 19 | 20 | 21 | }) 22 | 23 | _start: "" 24 | 25 | 26 | 27 | 28 | 29 | "", 30 | 31 | 32 | : { 33 | model: "", 34 | children: [], 35 | attributes: {, }} 36 | 37 | "": {optional: truefalse, value: ""} 38 | 39 | (,) 40 | 41 | (|) 42 | 43 | * 44 | 45 | 46 | 47 | ()* 48 | 49 | ()+ 50 | 51 | () 52 | 53 | \s? 54 | 55 | _empty_ 56 | 57 | _text_ 58 | -------------------------------------------------------------------------------- /resources/tei_all.odd: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | TEI with maximal setup 9 | Sebastian Rahtz 10 | 11 | 12 | 13 |

This template file is freely available and you are 14 | hereby authorised to copy, modify, and redistribute it in 15 | any way without further reference or permissions.

16 |

When making such modifications, you are strongly 17 | recommended to change the present text to include an 18 | accurate statement of the licencing conditions applicable 19 | to your modified text.

20 |
21 |
22 | 23 |

Written from scratch.

24 |
25 |
26 |
27 | 28 | 29 | TEI Complete 30 |

This TEI customization describes a schema that includes 31 | all of the TEI (P5) modules. This is a very useful 32 | starting place for manually creating your own customizations 33 | — it is much easier to delete the modules you do not 34 | want than to add the modules you do. Furthermore this 35 | customization often proves helpful for testing TEI 36 | software.

37 |

However, this particular TEI customization is not 38 | recommended for actual use for encoding documents. It 39 | produces schemas and reference documentation that will be much 40 | larger, and include many more elements, than almost anyone could 41 | conceivably ever need. Tempting though it may be simply to have 42 | absolutely everything, and just ignore elements not 43 | required, experience has shown that their presence makes the 44 | documentation harder to read and use, and makes a schema that is 45 | far more lax than desired.

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 | -------------------------------------------------------------------------------- /demo/GoogleDriveStorage.js: -------------------------------------------------------------------------------- 1 | 2 | function loadFile(fileid){ 3 | console.log(fileid); 4 | var request = gapi.client.request({ 5 | 'path': '/drive/v2/files/'+fileid, 6 | 'method': 'GET'}); 7 | 8 | request.execute(function(resp) { 9 | console.log('Title: ' + resp.title); 10 | console.log('Description: ' + resp.description); 11 | console.log('MIME type: ' + resp.mimeType); 12 | if (resp.downloadUrl) { 13 | var accessToken = gapi.auth.getToken().access_token; 14 | var xhr = new XMLHttpRequest(); 15 | xhr.open('GET', resp.downloadUrl); 16 | xhr.setRequestHeader('Authorization', 'Bearer ' + accessToken); 17 | xhr.onload = function() { 18 | console.log("RESPONSE: "+JSON.stringify(xhr.responseText)); 19 | editor.setValue(xhr.responseText); 20 | }; 21 | xhr.onerror = function() { 22 | alert("ERROR"); 23 | }; 24 | xhr.send(); 25 | } else { 26 | alert("ERROR"); 27 | } 28 | }); 29 | } 30 | $("#login").click(function(){ 31 | 32 | 33 | gapi.auth.authorize(config, function() { 34 | $("#login").replaceWith("Save|Load|Logout"); 35 | $("#load").click(function(){ 36 | 37 | fn = prompt("Filename: "); 38 | gapi.client.load('drive', 'v2', function() { 39 | var request = gapi.client.drive.files.list({ 40 | 'q': "title='"+fn+"'" 41 | }); 42 | request.execute(function(resp) { 43 | loadFile(resp.items[0].id); 44 | 45 | }); 46 | }); 47 | fileid="0Bw7PrlWT3aWaVWQyLU5KZ1I1RVU"; 48 | 49 | 50 | }); 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | $("#save").click(function(){ 61 | txt = editor.getValue(); 62 | filename = prompt("Enter a filename: ") 63 | var metadata = { 64 | 'title': filename, 65 | 'mimeType': "text/plain" 66 | }; 67 | 68 | const boundary = '-------314159265358979323846'; 69 | const delimiter = "\r\n--" + boundary + "\r\n"; 70 | const close_delim = "\r\n--" + boundary + "--"; 71 | 72 | var multipartRequestBody = 73 | delimiter + 74 | 'Content-Type: application/json\r\n\r\n' + 75 | JSON.stringify(metadata) + 76 | delimiter + 77 | 'Content-Type: text/plain\r\n' + 78 | 'Content-Transfer-Encoding: utf8\r\n' + 79 | '\r\n' + 80 | txt + 81 | close_delim; 82 | 83 | 84 | 85 | var request = gapi.client.request({ 86 | 'path': '/upload/drive/v2/files', 87 | 'method': 'POST', 88 | 'params': {'uploadType': 'multipart'}, 89 | 'headers': { 90 | 'Content-Type': 'multipart/mixed; boundary="' + boundary + '"' 91 | }, 92 | 'body': multipartRequestBody}); 93 | 94 | 95 | 96 | request.execute(); 97 | 98 | 99 | 100 | 101 | 102 | 103 | }); 104 | 105 | }); 106 | 107 | 108 | }); 109 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | 3 | 'use strict'; 4 | 5 | // catch these here so they don't bite us later when we try to run tasks 6 | var shell = require('shelljs'), 7 | rimraf = require('rimraf'), 8 | bower_cmd = require('bower/lib/util/cmd'); 9 | 10 | grunt.initConfig({ 11 | pkg: grunt.file.readJSON('package.json'), 12 | 13 | coffee: { 14 | compile: { 15 | files: { 16 | 'dist/angles.js': ['src/*.coffee'] 17 | } 18 | } 19 | }, 20 | 21 | clean: [ 'dist', 'bower_components' ], 22 | 23 | uglify: { 24 | options: { 25 | banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\n' 26 | }, 27 | my_target: { 28 | files: { 29 | 'dist/angles.min.js': 'dist/angles.js' 30 | } 31 | } 32 | }, 33 | 34 | qunit: { 35 | all: ['test/*.html'] 36 | }, 37 | }); 38 | 39 | grunt.registerTask('default', ['coffee', 'uglify', 'install-deps']); 40 | grunt.registerTask('test', ['default', 'qunit']); 41 | grunt.registerTask('real-clean', [ 'clean', 'clean:node_modules']); 42 | 43 | grunt.registerTask('clean:node_modules', 'Remove locally installed node modules.', function() { 44 | var filepath = './node_modules'; 45 | if(!grunt.file.exists(filepath)) { 46 | return false; 47 | } 48 | if(grunt.file.isPathCwd(filepath)) { 49 | grunt.verbose.error(); 50 | grunt.fail.warn('Cannot delete the current working directory.'); 51 | return false; 52 | } 53 | else if(!grunt.file.isPathInCwd(filepath)) { 54 | grunt.verbose.error(); 55 | grunt.fail.warn('Cannot delete files outside the current working directory.'); 56 | return false; 57 | } 58 | try { 59 | rimraf.sync(filepath); 60 | grunt.log.ok(); 61 | } 62 | catch(e) { 63 | grunt.log.error(); 64 | grunt.fail.warn('Unable to delete "' + filepath + '" file (' + e.message + ').', e); 65 | } 66 | }); 67 | 68 | grunt.registerTask('install-deps', 'Install all JavaScript dependencies using bower, including optional libraries.', function() { 69 | var done = this.async(); 70 | if(!shell.which("bower")) { 71 | console.log("Sorry, this script requires bower."); 72 | exit(1); 73 | } 74 | console.log("Running 'bower install'"); 75 | bower_cmd('bower',['install']).then(function() { 76 | console.log("running 'bower install Backbone.localStorage'"); 77 | return bower_cmd('bower', ['install', 'Backbone.localStorage']); 78 | }).then(function() { 79 | console.log("running 'bower install FileSaver'"); 80 | return bower_cmd('bower', ['install', 'FileSaver']); 81 | }).then(function() { 82 | console.log("Finished installing dependencies"); 83 | done(); 84 | }).fail(function() { 85 | console.log("Unable to install dependencies"); 86 | done(); 87 | }).done(); 88 | }); 89 | 90 | grunt.registerTask('demo', 'Install all dependencies and provide a list of demo files', ['default', 'install-deps', 'demo:files' ]); 91 | grunt.registerTask('demo:files', "List available demonstration files.", function() { 92 | console.log("demo/index.html"); 93 | console.log("demo/srvValidation.html"); 94 | }); 95 | 96 | grunt.event.on('qunit.spawn', function(url) { 97 | grunt.log.ok("Running test: " + url); 98 | }); 99 | 100 | grunt.loadNpmTasks('grunt-contrib-uglify'); 101 | grunt.loadNpmTasks('grunt-contrib-clean'); 102 | grunt.loadNpmTasks('grunt-contrib-qunit'); 103 | grunt.loadNpmTasks('grunt-contrib-coffee'); 104 | 105 | }; -------------------------------------------------------------------------------- /deps/client.js: -------------------------------------------------------------------------------- 1 | var gapi=window.gapi=window.gapi||{};gapi._bs=new Date().getTime();(function(){var e=void 0,f=window,h="push",i="replace",j="length";var l=f,o=document,p=l.location,t=function(){},u=/\[native code\]/,w=function(a,b,d){return a[b]=a[b]||d},x=function(a){for(var b=0;bx.call(b,c)&&d[h](c)}return d},W=/[@"'<>]|%2F/,X=/^https?:\/\/[^\/]+\.google\.com(:\d+)?\/[^\?]+$/,Y=function(a){var b=o.createElement(T);b.setAttribute("src",a);b.async="true";a=o.getElementsByTagName(T)[0];a.parentNode.insertBefore(b,a)},$=function(a,b){var d=b||{};"function"==typeof b&&(d={},d[R.a]=b);var g=d,c=g&&g[R.c];if(c)for(var k=0;k0&&m[n-1])m[n]=b;else for(b();b=m[++n];)if(!b())break};if(!s[j])return m[n](t);var H="loaded_"+A.I++;z[H]=function(a){m[n](a);z[H]=null};c=r.split(";");c=(k=M[c.shift()])&&k(c);if(!c)throw"Bad hint:"+ 5 | r;c=c[i]("__features__",U(s))[i](/\/$/,"")+(g[j]?"/ed=1/exm="+U(g):"")+("/cb=gapi."+H);if(!X.test(c)||W.test(c))throw"Bad URL "+c;g[h].apply(g,s);d[R.f]||l.___gapisync?(d=c,"loading"!=o.readyState?Y(d):o.write("<"+T+' src="'+encodeURI(d)+'">")):Y(c)};var Z=function(a){if(A.hee&&0 18 | @reset = -> 19 | parser = sax.parser true, 20 | xmlns: true 21 | noscript: true 22 | position: true 23 | 24 | 25 | 26 | if callbacks.error? 27 | parser.onerror = (e) => 28 | if e.message.split(/\n/)[0] != "Text data outside of root node." 29 | callbacks.error.call @, e 30 | parser.resume() 31 | else 32 | parser.onerror = (e) => 33 | if e.message.split(/\n/)[0] != "Text data outside of root node." 34 | @validationError (e.message.split(/\n/))[0] 35 | parser.resume() 36 | 37 | if callbacks.characters? 38 | parser.ontext = (t) => callbacks.characters.call @, t 39 | 40 | if callbacks.startElement? 41 | parser.onopentag = (node) => callbacks.startElement.call @, node 42 | 43 | if callbacks.endElement? 44 | parser.onclosetag = (name) => callbacks.endElement.call @, name 45 | 46 | if callbacks.comment? 47 | parser.oncomment = (comment) => callbacks.comment.call @, comment 48 | 49 | if callbacks.startCdata? 50 | parser.onopencdata = => callbacks.startCdata.call @ 51 | 52 | if callbacks.cdata? 53 | parser.oncdata = (cdata) => callbacks.cdata.call @, cdata 54 | 55 | if callbacks.endCdata? 56 | parser.onclosecdata = => callbacks.endCdata.call @ 57 | 58 | if callbacks.endDocument? 59 | parser.onend = => callbacks.endDocument.call @ 60 | 61 | if callbacks.startDocument? 62 | parser.onstart = => callbacks.startDocument.call @ 63 | else 64 | parser.onstart = -> 65 | 66 | @$parser = parser 67 | @$errors = [] 68 | 69 | parse: (doc) -> 70 | @reset() 71 | parser = @$parser 72 | n = doc.getLength() 73 | 74 | parser.onstart() 75 | 76 | for i in [0..n] 77 | parser.write doc.getLine(i)+"\n" 78 | parser.close() 79 | 80 | if @validated() 81 | true 82 | else 83 | false 84 | 85 | validationError: (text, type) -> 86 | parser = @$parser 87 | @$errors.push 88 | text: text 89 | row: parser.line 90 | column: parser.column 91 | type: if type? then type else "error" 92 | 93 | validated: -> @$errors.length == 0 94 | 95 | 96 | # --- ValidatorSAX - Extends Validator --- 97 | class Angles.ValidatorSAX extends Angles.Validator 98 | constructor: (options) -> 99 | super(options) 100 | @dispatcher.on "validation", => 101 | doc = @$angles?.getDocument() 102 | if doc? 103 | @dispatcher.trigger "validation:start" 104 | @validate @$angles.getDocument() 105 | 106 | checkSchema: (parser, els) -> 107 | return unless @$schema? 108 | 109 | if els?.length == 1 110 | if not @$schema.hasOwnProperty els[0]?.name 111 | parser.validationError "Invalid root element: " + els[0].name + "." 112 | else 113 | rexp = new RegExp @$schema._start, "ig" 114 | if rexp.exec(els[0].name+",") == null 115 | parser.validationError "Invalid root element: " + els[0].name + "." 116 | return 117 | 118 | currentEl = els[0].name 119 | parentEl = els[1].name 120 | 121 | if not @$schema[parentEl]? 122 | parser.validationError "The #{currentEl} element is not allowed as a child of the #{parentEl} element." 123 | else if currentEl not in @$schema[parentEl]?.children 124 | parser.validationError "The #{currentEl} element is not allowed as a child of the #{parentEl} element." 125 | return 126 | 127 | checkChildren: (parser, els) -> 128 | return unless @$schema? 129 | 130 | return unless els.length > 0 131 | 132 | currentEl = els[0] 133 | childNames = currentEl.children.join(',') 134 | childNames += "," if childNames != "" 135 | 136 | return unless @$schema.hasOwnProperty(currentEl?.name) 137 | return unless @$schema[currentEl.name].hasOwnProperty("model") 138 | 139 | rexp = new RegExp @$schema[currentEl.name].model, "ig" 140 | if rexp.exec(childNames) == null 141 | parser.validationError currentEl.name + " is invalid: one or more required children are missing or its child elements are in the wrong order." 142 | 143 | validate: (editor) -> 144 | els = [] 145 | parser = new Angles.SAXParser 146 | startDocument: => els = [] 147 | endDocument: => 148 | if els.length > 0 149 | names = (e.name for e in els) 150 | parser.validationError "Unclosed elements at end of document: #{names.join(", ")}" 151 | startElement: (node) => 152 | if els.length > 0 153 | els[0].children.push node.local 154 | els.unshift 155 | name: node.local 156 | children: [] 157 | @checkSchema parser, els 158 | characters: (t) => 159 | if els.length > 0 160 | if t.match(/^[\s\r\n]*$/) == null 161 | els[0].children.push '_text_' 162 | endElement: (name) => 163 | @checkChildren parser, els 164 | els.shift() 165 | parser.parse(editor) 166 | @$errors = parser.$errors 167 | @displayErrors() -------------------------------------------------------------------------------- /demo/README.md: -------------------------------------------------------------------------------- 1 | # Angles - Demonstration and Examples 2 | 3 | The HTML pages in this directory demonstrate how to use Angles with a number of optional components. 4 | 5 | To install all of the dependencies and build the ANGLES library, you can install the required node libraries and then run the 'demo' grunt task: 6 | 7 | ``` bash 8 | $ npm install -g grunt-cli 9 | $ npm install 10 | $ grunt demo 11 | ``` 12 | 13 | This will run through various installation procedures and end by printing out a list of available demonstration files. 14 | 15 | See the [top-level README](../README.md) for more information on installing grunt and associated dependencies. 16 | 17 | ## `index.html` 18 | 19 | This basic demonstration shows all features of Angles that do no need any server-side component. With this kind of set up, one could use Angles offline, or embed it into a website as a TEI editor. Angles will perform basic TEI-Lite validation, allow users to save their work in the browser, and save and load files from disk. The following sections will guide you through each component. 20 | 21 | ### The Demo Interface 22 | 23 | If the installation was completed correctly, the page will show an editable basic TEI file, a group of buttons on the left for saving and loading documents, and a validation button on top. 24 | 25 | ![Image of Angles demo interface][start] 26 | 27 | ### Contextual help 28 | 29 | When typing a new XML element (with `<`) a pop up will appear showing the TEI elements allowed in a given context (TEI-all only). 30 | This uses the JSON file `p5subset.js`, taken from [TEI's vault](http://www.tei-c.org/Vault/P5/current/xml/tei/odd/). 31 | 32 | A description of a selected element from the pop up will appear below the editor in the notification area. Click or press `Enter` on the desired element and it will be inserted at the position of the cursor. 33 | 34 | ![Example of context help interface][context] 35 | 36 | **N.B.** You can generate your own JSON for contextual help from any TEI ODD. Use [odd2json.xslt](https://github.com/TEIC/Stylesheets/blob/master/odds/odd2json.xsl) from the TEI GitHub Stylesheet repository - *make sure to set the paramenter showChildren to "true"*. 37 | 38 | ### Notifications 39 | 40 | Notifications can be used to display any type of message to the user. The demo shows how they can be used to drive the validation status indicator (green/red box in top right corner), validation errors, and element descriptions from the contextual help. 41 | 42 | ![Usage of notifications in the UI][notifications] 43 | 44 | ### Local storage operations 45 | 46 | Save and load current document to the user's browser's HTML5 Local Storage. The user can store multiple files and will be shown the latest open file when visiting the page again. 47 | 48 | ![Local Storage operations][loadsave] 49 | 50 | :warning: The demo does not include a way of removing any file stored in the Local Storage. The Local Storage can be cleared manually in a browser's settings. 51 | 52 | ### Save and Upload files 53 | 54 | The user can also save (download) or upload a file. Once a file is uploaded, it also gets stored in the HTML5 Local Storage. 55 | 56 | ### Validation 57 | 58 | This demonstration uses the [`rng.js`](https://github.com/umd-mith/angles/blob/master/demo/rng.js) JSON file as the JavaScript-friendly representation of a light-weight TEI schema for simple validation of the TEI without requiring a separate server process. 59 | 60 | The file is validated when it is loaded, at other times the user has to click on "Validate" to validate the file. 61 | 62 | ## `srvValidation.html` 63 | 64 | ## Validation 65 | 66 | When a more sophisticated validation is needed, Angles must be hooked up to a local or online validation service. This page demonstrates how to hook to an online validation service. During development we used [a simple Scalatra service](https://github.com/travisbrown/validation-demo). 67 | 68 | The validation server is able to fetch RelaxNG schemata from the web, so the interface links to several schemata on the web and allows the user to choose one. URLs to other schemata can be included in `srvValidation.html` by adding a new ` 72 | ``` 73 | 74 | If you want to use a different service or implement your own, you might need to override `Angles.ValidatorSRV.requestHandler` and `Angles.ValidatorSRV.validationHandler` to send the right request to your service and handle the response. 75 | 76 | `Angles.ValidatorSRV.requestHandler` handles the request to the service. We POST two parameters: `schema` (the URL to an RelaxNG document) and `document` (the content of the editor). Another service is likely to expect different paramenters and a different negotiation process. 77 | 78 | ``` coffeescript 79 | $.ajax 80 | url: validator.$validatorUrl 81 | type: "POST" 82 | crossDomain: true 83 | processData: false 84 | data: "schema="+validator.$schema+"&document="+xmlDocument 85 | dataType: "json", 86 | ``` 87 | 88 | `Angles.ValidatorSRV.validationHandler` handles the service's response and passes it on to flag errors in the editor and to show error notifications. All you will have to change here is where to find each piece of information in your service's response. 89 | 90 | ``` coffeescript 91 | for datum in data 92 | validator.$errors.push 93 | text: datum.message 94 | row: datum.line-1 95 | column: datum.column 96 | type: datum.type 97 | ``` 98 | 99 | [start]: img/readme_start.png "Angles demo interface" 100 | [context]: img/readme_context.png "Context help" 101 | [notifications]: img/readme_notification.png "Notifications" 102 | [loadsave]: img/readme_loadsave.png "Local Storage operations" -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ANGLES 2 | 3 | The ANGLES Project is a research project aimed at developing a 4 | lightweight, online XML code editor, which can support teaching of 5 | text encoding as well as text encoding research projects, either by 6 | distributed research teams or at institutions without resources to 7 | purchase expensive software licenses. By combining the model of 8 | intensive code development (a.k.a. the "code sprint") with testing 9 | and feedback by domain experts gathered at nationally-recognized 10 | disciplinary conferences, the project proposes a bridge between 11 | humanities centers who have greater resources to program scholarly 12 | software and the scholars who form the core user community for such 13 | software through their teaching and research. 14 | 15 | ## Repository Structure 16 | 17 | This repository has the following directories: 18 | 19 | * demo: simple demonstration page incorporating the ANGLES mode plugin. This demo assumes that you have installed the needed dependencies using `bower`. 20 | * dist: the built plugin ready for distribution. 21 | * src: the source code for non-ACE components that work with the ACE editor. 22 | * test: any unit tests. 23 | * vendor: dependencies not available through `bower` 24 | 25 | **N.B.**: You will need to clone this repository recursively to capture the dependencies in `vendor/`: 26 | 27 | ``` bash 28 | $ git clone --recursive https://github.com/umd-mith/angles.git 29 | ``` 30 | 31 | If you've already cloned the repository without the `--recursive` flag, or if you are using a client 32 | that does not allow you to specify the flag, you can manually check out these dependencies with the following commands: 33 | 34 | ``` bash 35 | $ git submodule init 36 | $ git submodule update 37 | ``` 38 | 39 | 40 | ## Development Toolchain 41 | 42 | ANGLES is based on the [Ace Editor](http://ace.ajax.org/) and uses `grunt` 43 | to manage its build and testing process. This means that 44 | you need the following installed before you can work on the CoffeeScript 45 | source code: 46 | 47 | * node.js (see [the guide to installing Node.js via package manager](https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager); you will need a recent version of node.js) 48 | * grunt (see [the `grunt` getting started guide](http://gruntjs.com/getting-started)) 49 | * bower 50 | 51 | ``` bash 52 | $ npm install -g grunt-cli 53 | $ npm install -g bower 54 | ``` 55 | 56 | You also need the following Node packages intalled via `npm`: 57 | 58 | * grunt-contrib-uglify 59 | * grunt-contrib-clean 60 | * grunt-contrib-qunit 61 | * grunt-contrib-coffee 62 | * rimraf 63 | * shelljs 64 | 65 | ``` bash 66 | $ npm install grunt-contrib-uglify 67 | $ npm install grunt-contrib-clean 68 | $ npm install grunt-contrib-qunit 69 | $ npm install grunt-contrib-coffee 70 | $ npm install rimraf 71 | $ npm install shelljs 72 | ``` 73 | 74 | You can also install these dependencies by running 75 | 76 | ``` bash 77 | $ npm install 78 | ``` 79 | 80 | in your clone of the repository. 81 | 82 | ### Building 83 | 84 | To build the plugins for ACE, run the following command: 85 | 86 | ``` bash 87 | $ grunt 88 | ``` 89 | 90 | This will build everything and leave the new files in `dist/`. In addition, all required and optional JavaScript dependencies managed through `bower` will be downloaded and placed in the `bower_components/` directory. 91 | 92 | ### Testing 93 | 94 | The tests assume that you have installed the required dependencies using `bower`. 95 | 96 | #### Headless Testing 97 | 98 | You may run tests without a browser using `grunt` if you have [PhantomJS](http://phantomjs.org/) installed. 99 | 100 | ``` bash 101 | $ grunt test 102 | ``` 103 | 104 | #### In-Browser Testing 105 | 106 | You may also run the tests in your browser by loading the `test/angles.html` page. Any errors will be highlighted in the web page. You may also want to view the browser's console log for additional error messages or stack traces if there are errors. 107 | ## Using ANGLES in your Project 108 | 109 | Refer to the demos for examples to set up the various components. A minimal installation of ANGLES would include the ANGLES plugin and the required dependencies listed below. 110 | 111 | ### The ANGLES plugin 112 | 113 | When built, the main plugin will be in `dist/angles.js`. You may also install the most recent distribution using `bower`. (See [bower.io](http://bower.io/#installing-bower) for information on installing and using `bower`.) 114 | 115 | ``` bash 116 | $ bower install angles-tei 117 | ``` 118 | 119 | The plugin will be in `bower_components/angles/dist/angles.js`. The required dependencies (see below) will also be installed. However, optional dependencies will need to be installed separately. 120 | 121 | ### Dependencies 122 | 123 | ANGLES has a number of JavaScript libraries on which it depends. These may be installed using `bower` or using `grunt`, though `grunt` will require that `bower` be installed. 124 | 125 | To use `grunt` to manage `bower` and install all dependencies, both required and optional, run: 126 | 127 | ``` bash 128 | $ grunt install-deps 129 | ``` 130 | 131 | #### Required Dependencies 132 | 133 | You may download the primary dependencies using `bower` or download your own. (See [bower.io](http://bower.io/#installing-bower) for information on installing and using `bower`.) 134 | 135 | From the top directory of the repository, you may run `bower`: 136 | 137 | ``` bash 138 | $ bower install 139 | ``` 140 | 141 | or 142 | 143 | ``` bash 144 | $ bower install jQuery 145 | $ bower install ace-builds 146 | $ bower install underscore 147 | $ bower install backbone 148 | ``` 149 | 150 | This will install the dependencies into `bower_components`. 151 | 152 | * [jQuery](https://jquery.com/) 153 | * [ACE editor](http://ace.c9.io/) 154 | * [underscore.js](http://underscorejs.org/) 155 | * [backbone.js](http://backbonejs.org/) 156 | 157 | #### Optional Dependencies 158 | 159 | The following dependencies are optional and are not included in the `bower` configuration: 160 | 161 | ``` bash 162 | $ bower install Backbone.localStorage 163 | $ bower install FileSaver 164 | ``` 165 | 166 | * [Backbone.localStorage](https://github.com/jeromegn/Backbone.localStorage) (optional for save/load component) 167 | * [FileSaver](https://github.com/eligrey/FileSaver.js) (optional for saving file to disk) 168 | 169 | ### Demo 170 | 171 | A number of demonstrations are available in the `demo/` directory. See [the README](./demo/README.md) in that directory for more information. 172 | 173 | You can ensure everything is built and dependencies are downloaded by running 174 | 175 | ``` bash 176 | $ grunt demo 177 | ``` 178 | 179 | This will also print out a list of demonstration files that you may open in your browser. 180 | 181 | ### Cleaning Files 182 | 183 | After building ANGLES or installing JavaScript libraries with `bower`, you can clean the `dist/` and `bower_components/` directories by running: 184 | 185 | ``` bash 186 | $ grunt clean 187 | ``` 188 | 189 | To remove any locally installed node modules, you may run: 190 | 191 | ``` bash 192 | $ grunt real-clean 193 | ``` 194 | 195 | -------------------------------------------------------------------------------- /src/angles-editor-view.coffee: -------------------------------------------------------------------------------- 1 | # 2 | # Events managed in the ACEEditorView.dispather: 3 | # 4 | # editor:change - an editor change event 5 | # editor:reload - force the editor to reload content from the model 6 | # editor:error - an error reported by the editor or wrapper 7 | # 8 | # document:switch - a request to change the document the editor is editing 9 | # document:save - a request to save the document currently in the editor 10 | # 11 | # validation:start - notice that validation is beginning 12 | # validation:end - notice that validation has finished 13 | # validation:error - the report of a validation error 14 | # 15 | # If you replace the Angles.ACEEditorView with a different view to wrap 16 | # a different editor, you will need to implement a getDocument() function 17 | # that returns the same properties as the one here, but with data from 18 | # your editor instance. This lets the validator not depend on the ACE 19 | # API. 20 | # 21 | # To provide different storage for the collection, replace 22 | # Angles.XMLDocumentList (here, we're using local storage): 23 | # 24 | # Angles.XMLDocumentList = Backbone.Collection.extend({ 25 | # mode: Angles.XMLDocument, 26 | # localStorage: new Backbone.LocalStorage("SomeCollection") 27 | # }); 28 | # 29 | 30 | window.Angles = {} 31 | ((Angles,_,Backbone,ace) -> 32 | ACEEditor = null 33 | 34 | # XMLDocument 35 | class Angles.XMLDocument extends Backbone.Model 36 | defaults: 37 | "name" : "untitled" 38 | "content": "" 39 | 40 | validate: (attrs) -> 41 | # console.log(attrs); 42 | #if(attrs.name === undefined) { 43 | # return "document must have a name"; 44 | #} 45 | #if(attrs.name =~ /^\s*$/) { 46 | # return "document must have a name"; 47 | #} 48 | 49 | # XMLDocument List 50 | class Angles.XMLDocumentList extends Backbone.Collection 51 | model: Angles.XMLDocument 52 | 53 | # Notification 54 | class Angles.Notification extends Backbone.Model 55 | defaults: 56 | "type" : "" 57 | "info" : "" 58 | "message" : "" 59 | "resource": "" 60 | "location": 61 | "column": -1 62 | "row" : -1 63 | 64 | # Notification List 65 | class Angles.NotificationList extends Backbone.Collection 66 | model: Angles.Notification 67 | 68 | # 69 | # This file selector will list the documents in the Angles.XMLDocumentList 70 | # collection and allow selection of a document. 71 | # 72 | # Fires a document:change event when the selected file is to be loaded 73 | # into the editor. The event's data parameter is the model object from 74 | # which to get the content. 75 | # 76 | # options: 77 | # 78 | # * el: element into which this view should be rendered 79 | # * dispatcher: dispatcher object to use for events 80 | # * collection: collection of models from which a model should be selected 81 | # 82 | # template classes: 83 | # .file-list - list of files - new files are appended to the end 84 | # .new-file - element that triggers a new file dialog 85 | # 86 | # 87 | # _.templateSettings = 88 | # interpolate: /\{\{(.+?)\}\}/g 89 | # escape: /\{\{-(.+?)\}\}/g 90 | 91 | class Angles.FileSelector extends Backbone.View 92 | 93 | initialize: -> 94 | @template = _.template $('#file-list-template').html() 95 | 96 | render: -> 97 | @$el.html @template {} 98 | @collection.each @addOne, @ 99 | @ 100 | 101 | addOne: (model) -> 102 | view = new Angles.FileSelectorRow 103 | model: model 104 | @$("form").append view.render().$el 105 | 106 | class Angles.FileSelectorRow extends Backbone.View 107 | 108 | initialize: -> 109 | @template = _.template $('#file-item-template').html() 110 | @listenTo @model, 'change', @render 111 | @listenTo @model, 'destroy', @remove 112 | 113 | render: -> 114 | @$el.html @template @model.toJSON() 115 | @ 116 | 117 | class Angles.NotificationTable extends Backbone.View 118 | 119 | initialize: -> 120 | @template = _.template $('#notification-list-template').html() 121 | 122 | render: -> 123 | @$el.html @template {} 124 | @listenTo @collection, 'add', @addOne 125 | @ 126 | 127 | addOne: (model) -> 128 | view = new Angles.NotificationRow 129 | model: model 130 | @$(".notifications").append view.render().$el 131 | 132 | class Angles.NotificationRow extends Backbone.View 133 | 134 | initialize: -> 135 | @template = _.template $('#notification-template').html() 136 | @listenTo @model, 'change', @render 137 | @listenTo @model, 'destroy', @remove 138 | 139 | render: -> 140 | @$el.html @template @model.toJSON() 141 | @ 142 | 143 | # 144 | # We intend ACEEditorView to be a singleton class for a particular area 145 | # on the page - not to be instantiated for each document in the collection. 146 | # 147 | # You may pass a dispatcher object into the initializer if you want to 148 | # use one from another application to allow integration. 149 | # 150 | 151 | class Angles.ACEEditorView extends Backbone.View 152 | tagName: "div" 153 | className: "ace-editor" 154 | 155 | initialize: -> 156 | annotations = [] 157 | dispatcher = @options.dispatcher or _.clone Backbone.Events 158 | @dispatcher = dispatcher 159 | 160 | dispatcher.on "editor:reload", => 161 | @clearAnnotations() 162 | @setContent() 163 | 164 | dispatcher.on "document:save", => @saveModel() 165 | 166 | dispatcher.on "validation:start", => 167 | annotations = []; 168 | @dispatcher.trigger 'notification:clear' 169 | 170 | dispatcher.on "validation:error", (e) => 171 | annotations.push(e) 172 | n = 173 | type: "validation" 174 | info: e.type 175 | message: e.text 176 | location: 177 | row: e.row 178 | column: e.column 179 | @dispatcher.trigger 'notification:push', n 180 | 181 | dispatcher.on "validation:end", => 182 | select = @$editor.getSelection() 183 | 184 | @clearAnnotations() 185 | @$editor.focus() 186 | if annotations.length > 0 187 | @$editor.gotoLine annotations[0].row+1, annotations[0].column, true 188 | select.selectWordLeft() 189 | select.selectWordLeft() 190 | 191 | @$editor.session.setAnnotations(annotations) 192 | 193 | dispatcher.on "document:switch", (e) => @setModel(e) 194 | 195 | render: -> 196 | @$editor = ace.edit(@el); 197 | @$editor.getSession().on 'change', (e) => @dispatcher.trigger 'editor:change', e 198 | @$editor.getSession().setMode "ace/mode/xml" 199 | 200 | # Load ace modules # 201 | 202 | #ace.config.set("basePath", "../deps/") 203 | ace.config.loadModule 'ext/angles', => 204 | 205 | @$editor.setOptions 206 | enableODDAutocompletion: true 207 | 208 | completer = 209 | getCompletions: (editor, session, pos, prefix, callback) => 210 | if @$context? 211 | context = this.$context 212 | 213 | _findParent = (row, column) -> 214 | openTags = [] 215 | closedTags = [] 216 | allTags = [] 217 | isOpeningTag = false 218 | isClosingTag = false 219 | 220 | finalTag = '' 221 | maxRow = editor.getSession().getLength() 222 | 223 | _scanRow = (row, column) -> 224 | return if row > maxRow 225 | curColumn = 0 226 | tokens = editor.getSession().getTokens(row) 227 | lastTag = null 228 | for token in tokens 229 | curColumn += token.value.length 230 | 231 | isfinal = -> 232 | switch 233 | when openTags.length == 0 234 | true 235 | when openTags.length == closedTags.length 236 | openTags.pop() 237 | closedTags.pop() 238 | false 239 | when openTags[openTags.length-1] == closedTags[closedTags.length-1] 240 | openTags.pop() 241 | closedTags.pop() 242 | false 243 | else 244 | false 245 | 246 | latestTag = token.value if token.type == "meta.tag.tag-name" 247 | 248 | if curColumn > column 249 | switch 250 | when token.type == "meta.tag" and token.value == "<" 251 | isOpeningTag = true 252 | when token.type == "meta.tag.r" and token.value == ">" and (isOpeningTag or isClosingTag) 253 | isOpeningTag = false 254 | isClosingTag = false 255 | when token.type == "meta.tag.r" and token.value == ">" and openTags.length == 0 256 | # The cursor must be on a closing tag, 257 | # return element value 258 | return latestTag 259 | when token.type == "meta.tag" and token.value == "" 262 | isOpeningTag = false 263 | isClosingTag = false 264 | milestone = openTags[openTags.length-1] 265 | milestone = latestTag if !milestone? 266 | closedTags.push milestone 267 | return milestone if isfinal() 268 | when token.type == "meta.tag.tag-name" and isOpeningTag 269 | allTags.push "<#{token.value}>" 270 | openTags.push token.value 271 | return token.value if isfinal() 272 | when token.type == "meta.tag.tag-name" and isClosingTag 273 | allTags.push "" 274 | closedTags.push token.value 275 | return token.value if isfinal() 276 | 277 | _scanRow(row+1, 0) 278 | 279 | _scanRow(row, column) 280 | 281 | pos = editor.getCursorPosition() 282 | ident = _findParent(pos.row, pos.column) 283 | completions = [] 284 | 285 | children = context.getChildrenOf(ident); 286 | 287 | if children? 288 | for c in children 289 | completions.push 290 | caption: c.ident, 291 | snippet: "#{c.ident}>", 292 | meta: "element" 293 | else 294 | completions.push 295 | caption: "unknown parent" 296 | snippet: "" 297 | meta: "element" 298 | 299 | if completions.length > 0 300 | callback null, completions 301 | else 302 | 0 #console.log 'Context Help component not loaded' 303 | @$editor.completers = [completer] 304 | 305 | ace.config.on "desc", (e) => 306 | @dispatcher.trigger("editor:context", e.ident) 307 | 308 | ace.config.on "desc:clear", (e) => 309 | @dispatcher.trigger 'notification:clear' 310 | 311 | @ 312 | 313 | setContent: -> @$editor.setValue @model.get('content') 314 | 315 | 316 | getContent: -> @$editor.getValue() 317 | 318 | getDocument: -> 319 | getValue: => @$editor.getValue() 320 | getLength: => @$editor.session.getDocument().getLength() 321 | getLine: (n) => @$editor.session.getDocument().getLine(n) 322 | 323 | saveModel: -> 324 | @model.set 'content', @getContent() 325 | @model.save 326 | success: => @dispatcher.trigger "editor:reload" 327 | error: => @dispatcher.trigger "editor:error", "Unable to change document" 328 | 329 | setModel: (m) -> 330 | @model = m; 331 | @dispatcher.trigger "editor:reload" 332 | 333 | clearAnnotations: -> @$editor.session.clearAnnotations() 334 | 335 | setMode: (m) -> @$editor.getSession().setMode(m) 336 | 337 | )(window.Angles,_,Backbone,ace) 338 | -------------------------------------------------------------------------------- /demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Angles Editor Demo 5 | 6 | 7 | 30 | 31 | 32 | 39 | 46 | 47 |
48 |
49 |
50 |   51 |
<?xml version="1.0" encoding="UTF-8"?> 52 | <TEI xmlns="http://www.tei-c.org/ns/1.0"> 53 | <teiHeader> 54 | <fileDesc> 55 | <titleStmt> 56 | <title>Title</title> 57 | </titleStmt> 58 | <publicationStmt> 59 | <p>Publication Information</p> 60 | </publicationStmt> 61 | <sourceDesc> 62 | <p>Information about the source</p> 63 | </sourceDesc> 64 | </fileDesc> 65 | </teiHeader> 66 | <text> 67 | <body> 68 | <p>Some text here.</p> 69 | </body> 70 | </text> 71 | </TEI>
72 |
73 |
74 |

Local Storage

75 | 81 |
82 | Load from DiskChange 83 | 84 | x 85 |
86 |
87 |
88 |
89 |
90 | 110 | 122 | 123 | 127 | 132 | 136 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 349 | 351 | 352 | 353 | 354 | 355 | 356 | -------------------------------------------------------------------------------- /demo/srvValidation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Angles Editor Demo 5 | 6 | 7 | 30 | 31 | 32 | 39 | 46 | 47 | 48 | 49 |
50 |
Validate with: 51 |
52 | 54 | 56 | 58 | 60 | 62 | 64 | 66 | 68 |
69 |
70 | 71 |
72 |
73 |   74 |
<?xml version="1.0" encoding="UTF-8"?> 75 | <TEI xmlns="http://www.tei-c.org/ns/1.0"> 76 | <teiHeader> 77 | <fileDesc> 78 | <titleStmt> 79 | <title>Title</title> 80 | </titleStmt> 81 | <publicationStmt> 82 | <p>Publication Information</p> 83 | </publicationStmt> 84 | <sourceDesc> 85 | <p>Information about the source</p> 86 | </sourceDesc> 87 | </fileDesc> 88 | </teiHeader> 89 | <text> 90 | <body> 91 | <p>Some text here.</p> 92 | </body> 93 | </text> 94 | </TEI>
95 |
96 |
97 |

Local Storage

98 | 104 |
105 | Load from DiskChange 106 | 107 | x 108 |
109 |
110 |
111 |
112 |
113 | 133 | 145 | 146 | 150 | 155 | 159 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 368 | 369 | 372 | 373 | 374 | 375 | -------------------------------------------------------------------------------- /demo/css/bootstrap-responsive.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Responsive v2.2.1 3 | * 4 | * Copyright 2012 Twitter, Inc 5 | * Licensed under the Apache License v2.0 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Designed and built with all the love in the world @twitter by @mdo and @fat. 9 | */.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;line-height:0;content:""}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.hidden{display:none;visibility:hidden}.visible-phone{display:none!important}.visible-tablet{display:none!important}.hidden-desktop{display:none!important}.visible-desktop{display:inherit!important}@media(min-width:768px) and (max-width:979px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-tablet{display:inherit!important}.hidden-tablet{display:none!important}}@media(max-width:767px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-phone{display:inherit!important}.hidden-phone{display:none!important}}@media(min-width:1200px){.row{margin-left:-30px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:30px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:1170px}.span12{width:1170px}.span11{width:1070px}.span10{width:970px}.span9{width:870px}.span8{width:770px}.span7{width:670px}.span6{width:570px}.span5{width:470px}.span4{width:370px}.span3{width:270px}.span2{width:170px}.span1{width:70px}.offset12{margin-left:1230px}.offset11{margin-left:1130px}.offset10{margin-left:1030px}.offset9{margin-left:930px}.offset8{margin-left:830px}.offset7{margin-left:730px}.offset6{margin-left:630px}.offset5{margin-left:530px}.offset4{margin-left:430px}.offset3{margin-left:330px}.offset2{margin-left:230px}.offset1{margin-left:130px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.564102564102564%;*margin-left:2.5109110747408616%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.564102564102564%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.45299145299145%;*width:91.39979996362975%}.row-fluid .span10{width:82.90598290598291%;*width:82.8527914166212%}.row-fluid .span9{width:74.35897435897436%;*width:74.30578286961266%}.row-fluid .span8{width:65.81196581196582%;*width:65.75877432260411%}.row-fluid .span7{width:57.26495726495726%;*width:57.21176577559556%}.row-fluid .span6{width:48.717948717948715%;*width:48.664757228587014%}.row-fluid .span5{width:40.17094017094017%;*width:40.11774868157847%}.row-fluid .span4{width:31.623931623931625%;*width:31.570740134569924%}.row-fluid .span3{width:23.076923076923077%;*width:23.023731587561375%}.row-fluid .span2{width:14.52991452991453%;*width:14.476723040552828%}.row-fluid .span1{width:5.982905982905983%;*width:5.929714493544281%}.row-fluid .offset12{margin-left:105.12820512820512%;*margin-left:105.02182214948171%}.row-fluid .offset12:first-child{margin-left:102.56410256410257%;*margin-left:102.45771958537915%}.row-fluid .offset11{margin-left:96.58119658119658%;*margin-left:96.47481360247316%}.row-fluid .offset11:first-child{margin-left:94.01709401709402%;*margin-left:93.91071103837061%}.row-fluid .offset10{margin-left:88.03418803418803%;*margin-left:87.92780505546462%}.row-fluid .offset10:first-child{margin-left:85.47008547008548%;*margin-left:85.36370249136206%}.row-fluid .offset9{margin-left:79.48717948717949%;*margin-left:79.38079650845607%}.row-fluid .offset9:first-child{margin-left:76.92307692307693%;*margin-left:76.81669394435352%}.row-fluid .offset8{margin-left:70.94017094017094%;*margin-left:70.83378796144753%}.row-fluid .offset8:first-child{margin-left:68.37606837606839%;*margin-left:68.26968539734497%}.row-fluid .offset7{margin-left:62.393162393162385%;*margin-left:62.28677941443899%}.row-fluid .offset7:first-child{margin-left:59.82905982905982%;*margin-left:59.72267685033642%}.row-fluid .offset6{margin-left:53.84615384615384%;*margin-left:53.739770867430444%}.row-fluid .offset6:first-child{margin-left:51.28205128205128%;*margin-left:51.175668303327875%}.row-fluid .offset5{margin-left:45.299145299145295%;*margin-left:45.1927623204219%}.row-fluid .offset5:first-child{margin-left:42.73504273504273%;*margin-left:42.62865975631933%}.row-fluid .offset4{margin-left:36.75213675213675%;*margin-left:36.645753773413354%}.row-fluid .offset4:first-child{margin-left:34.18803418803419%;*margin-left:34.081651209310785%}.row-fluid .offset3{margin-left:28.205128205128204%;*margin-left:28.0987452264048%}.row-fluid .offset3:first-child{margin-left:25.641025641025642%;*margin-left:25.53464266230224%}.row-fluid .offset2{margin-left:19.65811965811966%;*margin-left:19.551736679396257%}.row-fluid .offset2:first-child{margin-left:17.094017094017094%;*margin-left:16.98763411529369%}.row-fluid .offset1{margin-left:11.11111111111111%;*margin-left:11.004728132387708%}.row-fluid .offset1:first-child{margin-left:8.547008547008547%;*margin-left:8.440625568285142%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:30px}input.span12,textarea.span12,.uneditable-input.span12{width:1156px}input.span11,textarea.span11,.uneditable-input.span11{width:1056px}input.span10,textarea.span10,.uneditable-input.span10{width:956px}input.span9,textarea.span9,.uneditable-input.span9{width:856px}input.span8,textarea.span8,.uneditable-input.span8{width:756px}input.span7,textarea.span7,.uneditable-input.span7{width:656px}input.span6,textarea.span6,.uneditable-input.span6{width:556px}input.span5,textarea.span5,.uneditable-input.span5{width:456px}input.span4,textarea.span4,.uneditable-input.span4{width:356px}input.span3,textarea.span3,.uneditable-input.span3{width:256px}input.span2,textarea.span2,.uneditable-input.span2{width:156px}input.span1,textarea.span1,.uneditable-input.span1{width:56px}.thumbnails{margin-left:-30px}.thumbnails>li{margin-left:30px}.row-fluid .thumbnails{margin-left:0}}@media(min-width:768px) and (max-width:979px){.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:20px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:724px}.span12{width:724px}.span11{width:662px}.span10{width:600px}.span9{width:538px}.span8{width:476px}.span7{width:414px}.span6{width:352px}.span5{width:290px}.span4{width:228px}.span3{width:166px}.span2{width:104px}.span1{width:42px}.offset12{margin-left:764px}.offset11{margin-left:702px}.offset10{margin-left:640px}.offset9{margin-left:578px}.offset8{margin-left:516px}.offset7{margin-left:454px}.offset6{margin-left:392px}.offset5{margin-left:330px}.offset4{margin-left:268px}.offset3{margin-left:206px}.offset2{margin-left:144px}.offset1{margin-left:82px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.7624309392265194%;*margin-left:2.709239449864817%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.7624309392265194%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.43646408839778%;*width:91.38327259903608%}.row-fluid .span10{width:82.87292817679558%;*width:82.81973668743387%}.row-fluid .span9{width:74.30939226519337%;*width:74.25620077583166%}.row-fluid .span8{width:65.74585635359117%;*width:65.69266486422946%}.row-fluid .span7{width:57.18232044198895%;*width:57.12912895262725%}.row-fluid .span6{width:48.61878453038674%;*width:48.56559304102504%}.row-fluid .span5{width:40.05524861878453%;*width:40.00205712942283%}.row-fluid .span4{width:31.491712707182323%;*width:31.43852121782062%}.row-fluid .span3{width:22.92817679558011%;*width:22.87498530621841%}.row-fluid .span2{width:14.3646408839779%;*width:14.311449394616199%}.row-fluid .span1{width:5.801104972375691%;*width:5.747913483013988%}.row-fluid .offset12{margin-left:105.52486187845304%;*margin-left:105.41847889972962%}.row-fluid .offset12:first-child{margin-left:102.76243093922652%;*margin-left:102.6560479605031%}.row-fluid .offset11{margin-left:96.96132596685082%;*margin-left:96.8549429881274%}.row-fluid .offset11:first-child{margin-left:94.1988950276243%;*margin-left:94.09251204890089%}.row-fluid .offset10{margin-left:88.39779005524862%;*margin-left:88.2914070765252%}.row-fluid .offset10:first-child{margin-left:85.6353591160221%;*margin-left:85.52897613729868%}.row-fluid .offset9{margin-left:79.8342541436464%;*margin-left:79.72787116492299%}.row-fluid .offset9:first-child{margin-left:77.07182320441989%;*margin-left:76.96544022569647%}.row-fluid .offset8{margin-left:71.2707182320442%;*margin-left:71.16433525332079%}.row-fluid .offset8:first-child{margin-left:68.50828729281768%;*margin-left:68.40190431409427%}.row-fluid .offset7{margin-left:62.70718232044199%;*margin-left:62.600799341718584%}.row-fluid .offset7:first-child{margin-left:59.94475138121547%;*margin-left:59.838368402492065%}.row-fluid .offset6{margin-left:54.14364640883978%;*margin-left:54.037263430116376%}.row-fluid .offset6:first-child{margin-left:51.38121546961326%;*margin-left:51.27483249088986%}.row-fluid .offset5{margin-left:45.58011049723757%;*margin-left:45.47372751851417%}.row-fluid .offset5:first-child{margin-left:42.81767955801105%;*margin-left:42.71129657928765%}.row-fluid .offset4{margin-left:37.01657458563536%;*margin-left:36.91019160691196%}.row-fluid .offset4:first-child{margin-left:34.25414364640884%;*margin-left:34.14776066768544%}.row-fluid .offset3{margin-left:28.45303867403315%;*margin-left:28.346655695309746%}.row-fluid .offset3:first-child{margin-left:25.69060773480663%;*margin-left:25.584224756083227%}.row-fluid .offset2{margin-left:19.88950276243094%;*margin-left:19.783119783707537%}.row-fluid .offset2:first-child{margin-left:17.12707182320442%;*margin-left:17.02068884448102%}.row-fluid .offset1{margin-left:11.32596685082873%;*margin-left:11.219583872105325%}.row-fluid .offset1:first-child{margin-left:8.56353591160221%;*margin-left:8.457152932878806%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:20px}input.span12,textarea.span12,.uneditable-input.span12{width:710px}input.span11,textarea.span11,.uneditable-input.span11{width:648px}input.span10,textarea.span10,.uneditable-input.span10{width:586px}input.span9,textarea.span9,.uneditable-input.span9{width:524px}input.span8,textarea.span8,.uneditable-input.span8{width:462px}input.span7,textarea.span7,.uneditable-input.span7{width:400px}input.span6,textarea.span6,.uneditable-input.span6{width:338px}input.span5,textarea.span5,.uneditable-input.span5{width:276px}input.span4,textarea.span4,.uneditable-input.span4{width:214px}input.span3,textarea.span3,.uneditable-input.span3{width:152px}input.span2,textarea.span2,.uneditable-input.span2{width:90px}input.span1,textarea.span1,.uneditable-input.span1{width:28px}}@media(max-width:767px){body{padding-right:20px;padding-left:20px}.navbar-fixed-top,.navbar-fixed-bottom,.navbar-static-top{margin-right:-20px;margin-left:-20px}.container-fluid{padding:0}.dl-horizontal dt{float:none;width:auto;clear:none;text-align:left}.dl-horizontal dd{margin-left:0}.container{width:auto}.row-fluid{width:100%}.row,.thumbnails{margin-left:0}.thumbnails>li{float:none;margin-left:0}[class*="span"],.uneditable-input[class*="span"],.row-fluid [class*="span"]{display:block;float:none;width:100%;margin-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.span12,.row-fluid .span12{width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="offset"]:first-child{margin-left:0}.input-large,.input-xlarge,.input-xxlarge,input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.input-prepend input,.input-append input,.input-prepend input[class*="span"],.input-append input[class*="span"]{display:inline-block;width:auto}.controls-row [class*="span"]+[class*="span"]{margin-left:0}.modal{position:fixed;top:20px;right:20px;left:20px;width:auto;margin:0}.modal.fade{top:-100px}.modal.fade.in{top:20px}}@media(max-width:480px){.nav-collapse{-webkit-transform:translate3d(0,0,0)}.page-header h1 small{display:block;line-height:20px}input[type="checkbox"],input[type="radio"]{border:1px solid #ccc}.form-horizontal .control-label{float:none;width:auto;padding-top:0;text-align:left}.form-horizontal .controls{margin-left:0}.form-horizontal .control-list{padding-top:0}.form-horizontal .form-actions{padding-right:10px;padding-left:10px}.media .pull-left,.media .pull-right{display:block;float:none;margin-bottom:10px}.media-object{margin-right:0;margin-left:0}.modal{top:10px;right:10px;left:10px}.modal-header .close{padding:10px;margin:-10px}.carousel-caption{position:static}}@media(max-width:979px){body{padding-top:0}.navbar-fixed-top,.navbar-fixed-bottom{position:static}.navbar-fixed-top{margin-bottom:20px}.navbar-fixed-bottom{margin-top:20px}.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding:5px}.navbar .container{width:auto;padding:0}.navbar .brand{padding-right:10px;padding-left:10px;margin:0 0 0 -5px}.nav-collapse{clear:both}.nav-collapse .nav{float:none;margin:0 0 10px}.nav-collapse .nav>li{float:none}.nav-collapse .nav>li>a{margin-bottom:2px}.nav-collapse .nav>.divider-vertical{display:none}.nav-collapse .nav .nav-header{color:#777;text-shadow:none}.nav-collapse .nav>li>a,.nav-collapse .dropdown-menu a{padding:9px 15px;font-weight:bold;color:#777;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.nav-collapse .btn{padding:4px 10px 4px;font-weight:normal;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.nav-collapse .dropdown-menu li+li a{margin-bottom:2px}.nav-collapse .nav>li>a:hover,.nav-collapse .dropdown-menu a:hover{background-color:#f2f2f2}.navbar-inverse .nav-collapse .nav>li>a,.navbar-inverse .nav-collapse .dropdown-menu a{color:#999}.navbar-inverse .nav-collapse .nav>li>a:hover,.navbar-inverse .nav-collapse .dropdown-menu a:hover{background-color:#111}.nav-collapse.in .btn-group{padding:0;margin-top:5px}.nav-collapse .dropdown-menu{position:static;top:auto;left:auto;display:none;float:none;max-width:none;padding:0;margin:0 15px;background-color:transparent;border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.nav-collapse .open>.dropdown-menu{display:block}.nav-collapse .dropdown-menu:before,.nav-collapse .dropdown-menu:after{display:none}.nav-collapse .dropdown-menu .divider{display:none}.nav-collapse .nav>li>.dropdown-menu:before,.nav-collapse .nav>li>.dropdown-menu:after{display:none}.nav-collapse .navbar-form,.nav-collapse .navbar-search{float:none;padding:10px 15px;margin:10px 0;border-top:1px solid #f2f2f2;border-bottom:1px solid #f2f2f2;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1)}.navbar-inverse .nav-collapse .navbar-form,.navbar-inverse .nav-collapse .navbar-search{border-top-color:#111;border-bottom-color:#111}.navbar .nav-collapse .nav.pull-right{float:none;margin-left:0}.nav-collapse,.nav-collapse.collapse{height:0;overflow:hidden}.navbar .btn-navbar{display:block}.navbar-static .navbar-inner{padding-right:10px;padding-left:10px}}@media(min-width:980px){.nav-collapse.collapse{height:auto!important;overflow:visible!important}} 10 | -------------------------------------------------------------------------------- /demo/js/jasny-bootstrap.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Jasny-bootstrap.js by @ArnoldDaniels 3 | * Copyright 2012 Arnold Daniels 4 | * http://www.apache.org/licenses/LICENSE-2.0.txt 5 | */ 6 | !function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.typeahead.defaults,n),this.options.target&&(this.$target=e(this.options.target)),this.matcher=this.options.matcher||this.matcher,this.sorter=this.options.sorter||this.sorter,this.highlighter=this.options.highlighter||this.highlighter,this.updater=this.options.updater||this.updater,this.source=this.options.source,this.strict=this.options.strict,this.$menu=e(this.options.menu),this.shown=!1,typeof this.source=="string"&&(this.url=this.source,this.source=this.searchAjax),t.nodeName=="SELECT"&&this.replaceSelect(),this.text=this.$element.val(),this.$element.attr("data-text",this.value).attr("autocomplete","off"),typeof this.$target!="undefined"?this.$element.attr("data-value",this.$target.val()):typeof this.$element.attr("data-value")=="undefined"&&this.$element.attr("data-value",this.strict?"":this.value),this.$menu.css("min-width",this.$element.width()+12),this.listen()};t.prototype={constructor:t,replaceSelect:function(){this.$target=this.$element,this.$element=e(''),this.source={},this.strict=!0;var t=this.$target.find("option"),n;for(var r=0;r0?e.find(".item-text").text():e.text();return t=this.updater(t,"value"),n=this.updater(n,"text"),this.$element.val(n).attr("data-value",t),this.text=n,typeof this.$target!="undefined"&&this.$target.val(t).trigger("change"),this.$element.trigger("change"),this.hide()},updater:function(e,t){return e},show:function(){var t=e.extend({},this.$element.position(),{height:this.$element[0].offsetHeight});return this.$menu.insertAfter(this.$element).css({top:t.top+t.height,left:t.left}).show(),this.shown=!0,this},hide:function(){return this.$menu.hide(),this.shown=!1,this},lookup:function(t){var n;return this.query=this.$element.val(),!this.query||this.query.length=n.options.items&&delete r[e]}),this.render(r).show())},searchAjax:function(t,n){var r=this;this.ajaxTimeout&&clearTimeout(this.ajaxTimeout),this.ajaxTimeout=setTimeout(function(){r.ajaxTimeout&&clearTimeout(r.ajaxTimeout);if(t===""){r.hide();return}e.get(r.url,{q:t,limit:r.options.items},function(e){typeof e=="string"&&(e=JSON.parse(e)),n(e)})},this.options.ajaxdelay)},matcher:function(e){return~e.toLowerCase().indexOf(this.query.toLowerCase())},sorter:function(t){return e.isArray(t)?this.sortArray(t):this.sortObject(t)},sortArray:function(e){var t=[],n=[],r=[],i;while(i=e.shift())i.toLowerCase().indexOf(this.query.toLowerCase())?~i.indexOf(this.query)?n.push(i):r.push(i):t.push(i);return t.concat(n,r)},sortObject:function(e){var t={},n;for(n in e)e[n].toLowerCase().indexOf(this.query.toLowerCase())||(t[n]=e[n],delete e[n]);for(n in e)~e[n].indexOf(this.query)&&(t[n]=e[n],delete e[n]);for(n in e)t[n]=e[n];return t},highlighter:function(e){var t=this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&");return e.replace(new RegExp("("+t+")","ig"),function(e,t){return""+t+""})},render:function(t){var n=this,r=e([]);return e.map(t,function(i,s){if(r.length>=n.options.items)return;var o,u;e.isArray(t)&&(s=i),o=e(n.options.item),u=o.find("a").length?o.find("a"):o,u.html(n.highlighter(i)),o.attr("data-value",s),o.find("a").length===0&&o.addClass("dropdown-header"),r.push(o[0])}),r.not(".dropdown-header").first().addClass("active"),this.$menu.html(r),this},next:function(t){var n=this.$menu.find(".active").removeClass("active"),r=n.nextAll("li:not(.dropdown-header)").first();r.length||(r=e(this.$menu.find("li:not(.dropdown-header)")[0])),r.addClass("active")},prev:function(e){var t=this.$menu.find(".active").removeClass("active"),n=t.prevAll("li:not(.dropdown-header)").first();n.length||(n=this.$menu.find("li:not(.dropdown-header)").last()),n.addClass("active")},listen:function(){this.$element.on("focus",e.proxy(this.focus,this)).on("blur",e.proxy(this.blur,this)).on("change",e.proxy(this.change,this)).on("keypress",e.proxy(this.keypress,this)).on("keyup",e.proxy(this.keyup,this)),this.eventSupported("keydown")&&this.$element.on("keydown",e.proxy(this.keydown,this)),this.$menu.on("click",e.proxy(this.click,this)).on("mouseenter","li",e.proxy(this.mouseenter,this)).on("mouseleave","li",e.proxy(this.mouseleave,this)),e(window).on("unload",e.proxy(this.destroyReplacement,this))},eventSupported:function(e){var t=e in this.$element;return t||(this.$element.setAttribute(e,"return;"),t=typeof this.$element[e]=="function"),t},move:function(e){if(!this.shown)return;switch(e.keyCode){case 9:case 13:case 27:e.preventDefault();break;case 38:e.preventDefault(),this.prev();break;case 40:e.preventDefault(),this.next()}e.stopPropagation()},keydown:function(t){this.suppressKeyPressRepeat=~e.inArray(t.keyCode,[40,38,9,13,27]),this.move(t)},keypress:function(e){if(this.suppressKeyPressRepeat)return;this.move(e)},keyup:function(e){switch(e.keyCode){case 40:case 38:case 16:case 17:case 18:break;case 9:case 13:if(!this.shown)return;this.select();break;case 27:if(!this.shown)return;this.hide();break;default:this.lookup()}e.stopPropagation(),e.preventDefault()},change:function(e){var t;this.$element.val()!=this.text&&(t=this.$element.val()===""||this.strict?"":this.$element.val(),this.$element.val(t),this.$element.attr("data-value",t),this.text=t,typeof this.$target!="undefined"&&this.$target.val(t))},focus:function(e){this.focused=!0},blur:function(e){this.focused=!1,!this.mousedover&&this.shown&&this.hide()},click:function(e){e.stopPropagation(),e.preventDefault(),this.select(),this.$element.focus()},mouseenter:function(t){this.mousedover=!0,this.$menu.find(".active").removeClass("active"),e(t.currentTarget).addClass("active")},mouseleave:function(e){this.mousedover=!1,!this.focused&&this.shown&&this.hide()}};var n=e.fn.typeahead;e.fn.typeahead=function(n){return this.each(function(){var r=e(this),i=r.data("typeahead"),s=typeof n=="object"&&n;i||r.data("typeahead",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.typeahead.defaults={source:[],items:8,menu:'',item:'
  • ',ajaxdelay:400,minLength:1},e.fn.typeahead.Constructor=t,e.fn.typeahead.noConflict=function(){return e.fn.typeahead=n,this},e(document).off("focus.typeahead.data-api").on("focus.typeahead.data-api",'[data-provide="typeahead"]',function(t){var n=e(this);if(n.data("typeahead"))return;n.is("select")&&n.attr("autofocus",!0),t.preventDefault(),n.typeahead(n.data())})}(window.jQuery),!function(e){"use strict";var t=window.orientation!==undefined,n=navigator.userAgent.toLowerCase().indexOf("android")>-1,r=function(t,r){if(n)return;this.$element=e(t),this.options=e.extend({},e.fn.inputmask.defaults,r),this.mask=String(r.mask),this.init(),this.listen(),this.checkVal()};r.prototype={init:function(){var t=this.options.definitions,n=this.mask.length;this.tests=[],this.partialPosition=this.mask.length,this.firstNonMaskPos=null,e.each(this.mask.split(""),e.proxy(function(e,r){r=="?"?(n--,this.partialPosition=e):t[r]?(this.tests.push(new RegExp(t[r])),this.firstNonMaskPos===null&&(this.firstNonMaskPos=this.tests.length-1)):this.tests.push(null)},this)),this.buffer=e.map(this.mask.split(""),e.proxy(function(e,n){if(e!="?")return t[e]?this.options.placeholder:e},this)),this.focusText=this.$element.val(),this.$element.data("rawMaskFn",e.proxy(function(){return e.map(this.buffer,function(e,t){return this.tests[t]&&e!=this.options.placeholder?e:null}).join("")},this))},listen:function(){if(this.$element.attr("readonly"))return;var t=(navigator.userAgent.match(/msie/i)?"paste":"input")+".mask";this.$element.on("unmask",e.proxy(this.unmask,this)).on("focus.mask",e.proxy(this.focusEvent,this)).on("blur.mask",e.proxy(this.blurEvent,this)).on("keydown.mask",e.proxy(this.keydownEvent,this)).on("keypress.mask",e.proxy(this.keypressEvent,this)).on(t,e.proxy(this.pasteEvent,this))},caret:function(e,t){if(this.$element.length===0)return;if(typeof e=="number")return t=typeof t=="number"?t:e,this.$element.each(function(){if(this.setSelectionRange)this.setSelectionRange(e,t);else if(this.createTextRange){var n=this.createTextRange();n.collapse(!0),n.moveEnd("character",t),n.moveStart("character",e),n.select()}});if(this.$element[0].setSelectionRange)e=this.$element[0].selectionStart,t=this.$element[0].selectionEnd;else if(document.selection&&document.selection.createRange){var n=document.selection.createRange();e=0-n.duplicate().moveStart("character",-1e5),t=e+n.text.length}return{begin:e,end:t}},seekNext:function(e){var t=this.mask.length;while(++e<=t&&!this.tests[e]);return e},seekPrev:function(e){while(--e>=0&&!this.tests[e]);return e},shiftL:function(e,t){var n=this.mask.length;if(e<0)return;for(var r=e,i=this.seekNext(t);rn.length)break}else this.buffer[i]==n.charAt(s)&&i!=this.partialPosition&&(s++,r=i);if(!e&&r+1=this.partialPosition)this.writeBuffer(),e||this.$element.val(this.$element.val().substring(0,r+1));return this.partialPosition?i:this.firstNonMaskPos}},e.fn.inputmask=function(t){return this.each(function(){var n=e(this),i=n.data("inputmask");i||n.data("inputmask",i=new r(this,t))})},e.fn.inputmask.defaults={mask:"",placeholder:"_",definitions:{9:"[0-9]",a:"[A-Za-z]","?":"[A-Za-z0-9]","*":"."}},e.fn.inputmask.Constructor=r,e(document).on("focus.inputmask.data-api","[data-mask]",function(t){var n=e(this);if(n.data("inputmask"))return;t.preventDefault(),n.inputmask(n.data())})}(window.jQuery),!function(e){"use strict";var t=function(t,n){n=e.extend({},e.fn.rowlink.defaults,n);var r=t.nodeName.toLowerCase()=="tr"?e(t):e(t).find("tr:has(td)");r.each(function(){var t=e(this).find(n.target).first();if(!t.length)return;var r=t.attr("href");e(this).find("td").not(".nolink").click(function(){window.location=r}),e(this).addClass("rowlink"),t.replaceWith(t.html())})};e.fn.rowlink=function(n){return this.each(function(){var r=e(this),i=r.data("rowlink");i||r.data("rowlink",i=new t(this,n))})},e.fn.rowlink.defaults={target:"a"},e.fn.rowlink.Constructor=t,e(function(){e('[data-provide="rowlink"],[data-provides="rowlink"]').each(function(){e(this).rowlink(e(this).data())})})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.type=this.$element.data("uploadtype")||(this.$element.find(".thumbnail").length>0?"image":"file"),this.$input=this.$element.find(":file");if(this.$input.length===0)return;this.name=this.$input.attr("name")||n.name,this.$hidden=this.$element.find('input[type=hidden][name="'+this.name+'"]'),this.$hidden.length===0&&(this.$hidden=e(''),this.$element.prepend(this.$hidden)),this.$preview=this.$element.find(".fileupload-preview");var r=this.$preview.css("height");this.$preview.css("display")!="inline"&&r!="0px"&&r!="none"&&this.$preview.css("line-height",r),this.original={exists:this.$element.hasClass("fileupload-exists"),preview:this.$preview.html(),hiddenVal:this.$hidden.val()},this.$remove=this.$element.find('[data-dismiss="fileupload"]'),this.$element.find('[data-trigger="fileupload"]').on("click.fileupload",e.proxy(this.trigger,this)),this.listen()};t.prototype={listen:function(){this.$input.on("change.fileupload",e.proxy(this.change,this)),e(this.$input[0].form).on("reset.fileupload",e.proxy(this.reset,this)),this.$remove&&this.$remove.on("click.fileupload",e.proxy(this.clear,this))},change:function(e,t){if(t==="clear")return;var n=e.target.files!==undefined?e.target.files[0]:e.target.value?{name:e.target.value.replace(/^.+\\/,"")}:null;if(!n){this.clear();return}this.$hidden.val(""),this.$hidden.attr("name",""),this.$input.attr("name",this.name);if(this.type==="image"&&this.$preview.length>0&&(typeof n.type!="undefined"?n.type.match("image.*"):n.name.match(/\.(gif|png|jpe?g)$/i))&&typeof FileReader!="undefined"){var r=new FileReader,i=this.$preview,s=this.$element;r.onload=function(e){i.html('"),s.addClass("fileupload-exists").removeClass("fileupload-new")},r.readAsDataURL(n)}else this.$preview.text(n.name),this.$element.addClass("fileupload-exists").removeClass("fileupload-new")},clear:function(e){this.$hidden.val(""),this.$hidden.attr("name",this.name),this.$input.attr("name","");if(navigator.userAgent.match(/msie/i)){var t=this.$input.clone(!0);this.$input.after(t),this.$input.remove(),this.$input=t}else this.$input.val("");this.$preview.html(""),this.$element.addClass("fileupload-new").removeClass("fileupload-exists"),e&&(this.$input.trigger("change",["clear"]),e.preventDefault())},reset:function(e){this.clear(),this.$hidden.val(this.original.hiddenVal),this.$preview.html(this.original.preview),this.original.exists?this.$element.addClass("fileupload-exists").removeClass("fileupload-new"):this.$element.addClass("fileupload-new").removeClass("fileupload-exists")},trigger:function(e){this.$input.trigger("click"),e.preventDefault()}},e.fn.fileupload=function(n){return this.each(function(){var r=e(this),i=r.data("fileupload");i||r.data("fileupload",i=new t(this,n)),typeof n=="string"&&i[n]()})},e.fn.fileupload.Constructor=t,e(document).on("click.fileupload.data-api",'[data-provides="fileupload"]',function(t){var n=e(this);if(n.data("fileupload"))return;n.fileupload(n.data());var r=e(t.target).closest('[data-dismiss="fileupload"],[data-trigger="fileupload"]');r.length>0&&(r.trigger("click.fileupload"),t.preventDefault())})}(window.jQuery); -------------------------------------------------------------------------------- /test/angles_test.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | /* 3 | ======== A Handy Little QUnit Reference ======== 4 | http://api.qunitjs.com/ 5 | 6 | Test methods: 7 | module(name, {[setup][ ,teardown]}) 8 | test(name, callback) 9 | expect(numberOfAssertions) 10 | stop(increment) 11 | start(decrement) 12 | Test assertions: 13 | ok(value, [message]) 14 | equal(actual, expected, [message]) 15 | notEqual(actual, expected, [message]) 16 | deepEqual(actual, expected, [message]) 17 | notDeepEqual(actual, expected, [message]) 18 | strictEqual(actual, expected, [message]) 19 | notStrictEqual(actual, expected, [message]) 20 | throws(block, [expected], [message]) 21 | */ 22 | 23 | test("Check namespaces", function() { 24 | expect(4); 25 | ok(typeof ace !== "undefined" && ace !== null, "Ace namespace defined"); 26 | ok(typeof _ !== "undefined" && _ !== null, "Underscore namespace defined"); 27 | ok(typeof Backbone !== "undefined" && Backbone !== null, "Backbone namepsace defined"); 28 | ok(typeof Angles !== "undefined" && Angles !== null, "Angles namespace defined"); 29 | }); 30 | 31 | test("Check base validation class", function() { 32 | var validator = new Angles.Validator({ 33 | dispatcher: _.clone(Backbone.Events) 34 | }), dispatcher, validationEventTriggered = 0, validationEndEventTriggered = 0, validationErrorEventTriggered = 0; 35 | 36 | expect(28); 37 | 38 | dispatcher = validator.dispatcher; 39 | 40 | dispatcher.on("validation", function() { 41 | validationEventTriggered += 1; 42 | }); 43 | dispatcher.on("validation:end", function() { 44 | validationEndEventTriggered += 1; 45 | }); 46 | dispatcher.on("validation:error", function() { 47 | validationErrorEventTriggered += 1; 48 | }); 49 | 50 | ok(typeof validator !== "undefined" && validator !== null, "Validator object is created"); 51 | ok(typeof validator.displayErrors !== "undefined" && validator.displayErrors !== null, "displayErrors method exists"); 52 | ok(typeof validator.endValidation !== "undefined" && validator.endValidation !== null, "endValidation method exists"); 53 | ok(typeof validator.setSchema !== "undefined" && validator.setSchema !== null, "setSchema method exists"); 54 | ok(typeof validator.errors !== "undefined" && validator.errors !== null, "errors method exists"); 55 | 56 | equal(validationEventTriggered, 0, "validation event counter zero before test"); 57 | equal(validationErrorEventTriggered, 0, "validation:error counter zero before test"); 58 | equal(validationEndEventTriggered, 0, "validation:end counter zero before test"); 59 | validator.setSchema({}); 60 | equal(validationEventTriggered, 1, "validation event was triggered by setting the schema"); 61 | equal(validationErrorEventTriggered, 0, "validation:error not triggered by setting the schema"); 62 | equal(validationEndEventTriggered, 0, "validation:end not triggered by setting the schema"); 63 | 64 | validationEventTriggered = 0; 65 | validationErrorEventTriggered = 0; 66 | validationEndEventTriggered = 0; 67 | equal(validationEventTriggered, 0, "validation event counter zero before test"); 68 | equal(validationErrorEventTriggered, 0, "validation:error counter zero before test"); 69 | equal(validationEndEventTriggered, 0, "validation:end counter zero before test"); 70 | validator.endValidation(); 71 | equal(validationEventTriggered, 0, "validation event not triggered by endValidation"); 72 | equal(validationErrorEventTriggered, 0, "validation:error not triggered by endValidation"); 73 | equal(validationEndEventTriggered, 1, "validation:end was triggered by endValidation"); 74 | 75 | validationEventTriggered = 0; 76 | validationErrorEventTriggered = 0; 77 | validationEndEventTriggered = 0; 78 | 79 | ok(!validator.hasErrors(), "validator has no errors"); 80 | validator.addError({}); 81 | validator.addError({}); 82 | equal(validationEventTriggered, 0, "validation event not triggered by addError"); 83 | equal(validationErrorEventTriggered, 0, "validation:error not triggered by addError"); 84 | equal(validationEndEventTriggered, 0, "validation:end not triggered by addError"); 85 | ok(validator.hasErrors(), "validator now has errors"); 86 | equal(validator.errors().length, 2, "validator has two errors"); 87 | validator.displayErrors(); 88 | equal(validationEventTriggered, 0, "validation event not triggered by displayErrors"); 89 | equal(validationErrorEventTriggered, 2, "validation:error triggered twice by displayErrors"); 90 | equal(validationEndEventTriggered, 1, "validation:end triggered by displayErrors"); 91 | 92 | validationEventTriggered = 0; 93 | validationErrorEventTriggered = 0; 94 | validationEndEventTriggered = 0; 95 | 96 | validator.clearErrors(); 97 | ok(!validator.hasErrors(), "validator has no errors after clearErrors"); 98 | equal(validator.errors().length, 0, "validator errors() returns empty array after clearErrors"); 99 | }); 100 | 101 | test("Check SAX/browser-based validation class", function() { 102 | var validator, dispatcher, validationEventTriggered = 0, validationEndEventTriggered = 0, 103 | validationErrorEventTriggered = 0, doc; 104 | 105 | expect(23); 106 | 107 | validator = new Angles.ValidatorSAX({ 108 | dispatcher: _.clone(Backbone.Events) 109 | }); 110 | 111 | ok(typeof validator !== "undefined" && validator !== null, "Validator object is created"); 112 | ok(typeof validator.displayErrors !== "undefined" && validator.displayErrors !== null, "displayErrors method exists"); 113 | ok(typeof validator.endValidation !== "undefined" && validator.endValidation !== null, "endValidation method exists"); 114 | ok(typeof validator.setSchema !== "undefined" && validator.setSchema !== null, "setSchema method exists"); 115 | ok(typeof validator.errors !== "undefined" && validator.errors !== null, "errors method exists"); 116 | 117 | dispatcher = validator.dispatcher; 118 | 119 | dispatcher.on("validation", function() { 120 | validationEventTriggered = 1; 121 | }); 122 | dispatcher.on("validation:end", function() { 123 | validationEndEventTriggered = 1; 124 | }); 125 | dispatcher.on("validation:error", function() { 126 | validationErrorEventTriggered += 1; 127 | }); 128 | 129 | ok(typeof window.testSchema !== "undefined" && window.testSchema !== null, "Schema loaded"); 130 | equal(validationEventTriggered, 0, "validation event counter zero before test"); 131 | equal(validationErrorEventTriggered, 0, "validation:error counter zero before test"); 132 | equal(validationEndEventTriggered, 0, "validation:end counter zero before test"); 133 | validator.setSchema(window.testSchema); 134 | 135 | equal(validationEventTriggered, 1, "validation event was triggered by setting the schema"); 136 | equal(validationErrorEventTriggered, 0, "validation:error not triggered by setting the schema"); 137 | equal(validationEndEventTriggered, 0, "validation:end not triggered by setting the schema"); 138 | 139 | validationEventTriggered = 0; 140 | validationErrorEventTriggered = 0; 141 | validationEndEventTriggered = 0; 142 | 143 | doc = { 144 | getLine: function(i) { 145 | return doc.$lines[i]; 146 | }, 147 | getLength: function() { return doc.$lines.length; }, 148 | $lines: [ 149 | "", 150 | "" 151 | ] 152 | }; 153 | 154 | equal(validationEventTriggered, 0, "validation event counter zero before test"); 155 | equal(validationErrorEventTriggered, 0, "validation:error counter zero before test"); 156 | equal(validationEndEventTriggered, 0, "validation:end counter zero before test"); 157 | validator.validate(doc); 158 | 159 | equal(validationEventTriggered, 0, "validation event not triggered by validation"); 160 | ok(validationErrorEventTriggered > 0, "validation:error triggered by validation"); 161 | equal(validationEndEventTriggered, 1, "validation:end triggered by validation"); 162 | equal(validator.errors().length, 1, "one error"); 163 | equal(validator.errors()[0].row, 1, "on row one"); 164 | equal(validator.errors()[0].type, "error", "an error (not a warning)"); 165 | 166 | // no RDF allowed in the browser-based validation schema, so RDF removed. Otherwise, this is the document 167 | // from https://github.com/opensiddur/opensiddur/blob/master/code/tests/minimal-valid.xml 168 | 169 | doc.$lines = [ 170 | '', 171 | ' ', 172 | ' ', 173 | ' ', 174 | ' Minimal valid JLPTEI', 175 | ' ', 176 | ' ', 177 | ' ', 178 | '

    To the extent possible under law, ', 179 | 'the contributors who associated ', 180 | 'Creative Commons Zero ', 181 | 'with this work have waived all copyright and related or ', 182 | 'neighboring rights to this work. ', 183 | 'A list of contributors is available at ', 184 | 'http://jewishliturgy.org/base/text/contributors.', 185 | '

    ', 186 | '
    ', 187 | ' $Id: minimal-valid.xml 411 2010-01-03 06:58:09Z efraim.feinstein $', 188 | '
    ', 189 | ' ', 190 | '

    Born digital.

    ', 191 | '
    ', 192 | '
    ', 193 | '
    ', 194 | '', 195 | ' ', 196 | '
    ', 197 | ' Shortest document ever', 198 | '

    Yay!

    ', 199 | '
    ', 200 | ' ', 201 | '
    ', 202 | '
    ' 203 | ]; 204 | 205 | validationEventTriggered = 0; 206 | validationErrorEventTriggered = 0; 207 | validationEndEventTriggered = 0; 208 | validator.clearErrors(); 209 | 210 | ok(!validator.hasErrors(), "Errors cleared"); 211 | 212 | validator.validate(doc); 213 | ok(!validator.hasErrors(), "no errors after validating valid document"); 214 | }); 215 | 216 | test("Check notification infrastructure", function() { 217 | var note, noteList, note1, note2, noteCenter, dispatcher; 218 | 219 | expect(22); 220 | 221 | ok(typeof Angles.Notification !== "undefined" && Angles.Notification !== null, "Notification class is defined"); 222 | ok(typeof Angles.NotificationList !== "undefined" && Angles.NotificationList !== null, "NotificationList class is defined"); 223 | ok(typeof Angles.NotificationCenter !== "undefined" && Angles.NotificationCenter !== null, "NotificationCenter class is defined"); 224 | 225 | note = new Angles.Notification(); 226 | ok(typeof note !== "undefined" && note !== null, "Created Angles.Notification successfully"); 227 | deepEqual(note.attributes, { 228 | info: "", 229 | location: { 230 | column: -1, 231 | row: -1 232 | }, 233 | message: "", 234 | resource: "", 235 | type: "" 236 | }, "Proper initialized default attributes"); 237 | 238 | note = new Angles.Notification({ 239 | info: "info", 240 | location: { 241 | column: 10, 242 | row: 20 243 | }, 244 | message: "message", 245 | resource: "resource", 246 | type: "type" 247 | }); 248 | ok(typeof note !== "undefined" && note !== null, "Created Angles.Notification successfully with custom data"); 249 | deepEqual(note.attributes, { 250 | info: "info", 251 | location: { 252 | column: 10, 253 | row: 20 254 | }, 255 | message: "message", 256 | resource: "resource", 257 | type: "type" 258 | }, "Proper initialized given attributes"); 259 | 260 | noteList = new Angles.NotificationList(); 261 | ok(typeof noteList !== "undefined" && noteList !== null, "Created Angles.NotificationList"); 262 | 263 | equal(noteList.length, 0, "note list is empty"); 264 | noteList.add(note); 265 | equal(noteList.length, 1, "note list should have one entry"); 266 | noteList.add(note); 267 | equal(noteList.length, 1, "note list should have one entry"); 268 | noteList.add({ 269 | info: "info2", 270 | message: "Message2", 271 | resource: "resource2", 272 | type: 'type2' 273 | }); 274 | equal(noteList.length, 2, "note list should have two entries"); 275 | 276 | note1 = noteList.at(0); 277 | note2 = noteList.at(1); 278 | ok(typeof note1 !== "undefined" && note1 !== null, "first item in noteList is defined"); 279 | ok(typeof note2 !== "undefined" && note2 !== null, "second item in noteList is defined"); 280 | 281 | equal(note1.get('info'), 'info', 'First note was inserted first'); 282 | equal(note2.get('info'), 'info2', 'Second note was inserted second'); 283 | 284 | noteCenter = new Angles.NotificationCenter({ 285 | dispatcher: _.clone(Backbone.Events) 286 | }); 287 | ok(typeof noteCenter !== "undefined" && noteCenter !== null, "notification center object was created"); 288 | 289 | dispatcher = noteCenter.dispatcher; 290 | ok(typeof dispatcher !== "undefined" && dispatcher !== null, "notification center dispatcher was created"); 291 | 292 | equal(noteCenter.$notifications.length, 0, "No notifications"); 293 | 294 | noteCenter.push({}); 295 | 296 | equal(noteCenter.$notifications.length, 1, "One notification now"); 297 | 298 | dispatcher.trigger("notification:push", {}); 299 | 300 | equal(noteCenter.$notifications.length, 2, "Two notifications now"); 301 | 302 | dispatcher.trigger("notification:clear"); 303 | 304 | equal(noteCenter.$notifications.length, 0, "No notifications after notification:clear trigger"); 305 | 306 | }); 307 | 308 | test("Check context help", function() { 309 | var contextHelp, dispatcher; 310 | //expect(0); 311 | ok(typeof Angles.ContextHelp !== "undefined" && Angles.ContextHelp !== null, "ContextHelp class is defined"); 312 | 313 | ok(typeof window.testODD !== "undefined" && window.testODD !== null, "Test ODD file loaded"); 314 | /* 315 | getDescOf: (e) -> @getODDfor(e)?.desc 316 | 317 | getChildrenOf: (e) -> 318 | @getODDfor(e)?.children 319 | */ 320 | 321 | contextHelp = new Angles.ContextHelp({ 322 | dispatcher: _.clone(Backbone.Events) 323 | }); 324 | dispatcher = contextHelp.dispatcher; 325 | contextHelp.setODD(window.testODD); 326 | 327 | ok(contextHelp.getODDfor("p"), "There's something for 'p'"); 328 | ok(!contextHelp.getODDfor("foobar"), "There's nothing for 'foobar'"); 329 | }); 330 | 331 | test("Check XMLDocument(List)", function() { 332 | var doc, docList; 333 | 334 | ok(typeof Angles.XMLDocument !== "undefined" && Angles.XMLDocument !== null, "XMLDocument class is defined"); 335 | ok(typeof Angles.XMLDocumentList !== "undefined" && Angles.XMLDocumentList !== null, "XMLDocumentList class is defined"); 336 | 337 | doc = new Angles.XMLDocument(); 338 | ok(typeof doc !== "undefined" && doc !== null, "XMLDocument instance created"); 339 | deepEqual(doc.attributes, { 340 | "name": "untitled", 341 | "content": "" 342 | }, "correct default attributes for a document"); 343 | 344 | doc = new Angles.XMLDocument({ 345 | "name": "Foo", 346 | "content": "Bar" 347 | }); 348 | 349 | ok(typeof doc !== "undefined" && doc !== null, "XMLDocument instance created"); 350 | 351 | deepEqual(doc.attributes, { 352 | "name": "Foo", 353 | "content": "Bar" 354 | }, "correct attributes for document"); 355 | 356 | docList = new Angles.XMLDocumentList(); 357 | ok(typeof docList !== "undefined" && docList !== null, "XMLDocumentList instance created"); 358 | }); 359 | 360 | test("Check ACE editor instantiation", function() { 361 | var editor, dispatcher, doc; 362 | //expect(5); 363 | 364 | ok(typeof Angles.ACEEditorView !== "undefined" && Angles.ACEEditorView !== null, "ACEEditorView class is defined"); 365 | editor = new Angles.ACEEditorView({ 366 | el: "#ace-editor" 367 | }); 368 | ok(typeof editor !== "undefined" && editor !== null, "editor is created"); 369 | 370 | editor.render(); 371 | ok(typeof editor.$editor !== "undefined" && editor.$editor !== null, "ACE instance is defined"); 372 | 373 | ok(editor.$el.hasClass("ace_editor"), "ACE edit area has the right class"); 374 | 375 | dispatcher = editor.dispatcher; 376 | 377 | doc = new Angles.XMLDocument({ 378 | "content": "***Foo***" 379 | }); 380 | editor.setModel(doc); 381 | equal(editor.getContent(), "***Foo***", "Getting content from editor returns value set"); 382 | 383 | }); 384 | 385 | })(); -------------------------------------------------------------------------------- /demo/css/jasny-bootstrap.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Jasny Bootstrap Extensions j3 3 | * 4 | * Copyright 2012 Jasny BV 5 | * Licensed under the Apache License v2.0 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Extended with pride by @ArnoldDaniels of jasny.net 9 | */.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;line-height:0;content:""}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.container-semifluid{max-width:940px;padding-right:20px;padding-left:20px;margin-right:auto;margin-left:auto;*zoom:1}.container-semifluid:before,.container-semifluid:after{display:table;line-height:0;content:""}.container-semifluid:after{clear:both}form>*:last-child{margin-bottom:0}label input[type="image"],label input[type="checkbox"],label input[type="radio"]{vertical-align:middle}select{padding-left:2px}.small-labels .control-group>label{width:70px}.small-labels .controls{margin-left:80px}.small-labels .form-actions{padding-left:80px}.form-vertical .form-horizontal .control-group>label{text-align:left}.form-horizontal .form-vertical .control-group>label{float:none;padding-top:0;text-align:left}.form-horizontal .form-vertical .controls{margin-left:0}.form-horizontal .form-vertical.form-actions,.form-horizontal .form-vertical .form-actions{padding-left:20px}.control-group .control-group{margin-bottom:0}.form-horizontal .well .control-label{width:120px}.form-horizontal .well .controls{margin-left:140px}form .well>*:last-child{margin-bottom:0}.editor{width:100%;height:100px;padding:5px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.uneditable-textarea.editor-html{padding:5px 3px 5px 5px;white-space:normal}textarea.editor-html{visibility:hidden}.uneditable-input,.uneditable-textarea{display:inline-block;padding:4px 3px 4px 5px;font-size:14px;line-height:20px;color:#555;cursor:not-allowed;background-color:#fff;border:1px solid #eee;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.uneditable-input{height:20px;overflow:hidden;white-space:pre}.uneditable-textarea{overflow-x:hidden;overflow-y:auto;white-space:pre-wrap}select[disabled],textarea[disabled],input[type="text"][disabled],input[type="password"][disabled],input[type="datetime"][disabled],input[type="datetime-local"][disabled],input[type="date"][disabled],input[type="month"][disabled],input[type="time"][disabled],input[type="week"][disabled],input[type="number"][disabled],input[type="email"][disabled],input[type="url"][disabled],input[type="search"][disabled]{color:#999}.uneditable-input.disabled,.uneditable-textarea.disabled{color:#999;cursor:not-allowed;background-color:#f5f5f5;border-color:#ddd}textarea,.uneditable-textarea{height:60px}textarea[rows="1"],.uneditable-textarea[rows="1"]{height:40px}textarea[rows="2"],.uneditable-textarea[rows="2"]{height:60px}textarea[rows="3"],.uneditable-textarea[rows="3"]{height:80px}textarea[rows="4"],.uneditable-textarea[rows="4"]{height:100px}textarea[rows="5"],.uneditable-textarea[rows="5"]{height:120px}textarea[rows="6"],.uneditable-textarea[rows="6"]{height:140px}textarea[rows="7"],.uneditable-textarea[rows="7"]{height:160px}textarea[rows="8"],.uneditable-textarea[rows="8"]{height:180px}textarea[rows="9"],.uneditable-textarea[rows="9"]{height:200px}textarea[rows="10"],.uneditable-textarea[rows="10"]{height:220px}textarea[rows="11"],.uneditable-textarea[rows="11"]{height:240px}textarea[rows="12"],.uneditable-textarea[rows="12"]{height:260px}textarea[rows="13"],.uneditable-textarea[rows="13"]{height:280px}textarea[rows="14"],.uneditable-textarea[rows="14"]{height:300px}textarea[rows="15"],.uneditable-textarea[rows="15"]{height:320px}textarea[rows="16"],.uneditable-textarea[rows="16"]{height:340px}textarea[rows="17"],.uneditable-textarea[rows="17"]{height:360px}textarea[rows="18"],.uneditable-textarea[rows="18"]{height:380px}textarea[rows="19"],.uneditable-textarea[rows="19"]{height:400px}textarea[rows="20"],.uneditable-textarea[rows="20"]{height:420px}textarea[rows="21"],.uneditable-textarea[rows="21"]{height:440px}textarea[rows="22"],.uneditable-textarea[rows="22"]{height:460px}textarea[rows="23"],.uneditable-textarea[rows="23"]{height:480px}textarea[rows="24"],.uneditable-textarea[rows="24"]{height:500px}textarea[rows="25"],.uneditable-textarea[rows="25"]{height:520px}textarea[rows="26"],.uneditable-textarea[rows="26"]{height:540px}textarea[rows="27"],.uneditable-textarea[rows="27"]{height:560px}textarea[rows="28"],.uneditable-textarea[rows="28"]{height:580px}textarea[rows="29"],.uneditable-textarea[rows="29"]{height:600px}textarea[rows="30"],.uneditable-textarea[rows="30"]{height:620px}textarea[rows="35"],.uneditable-textarea[rows="35"]{height:720px}textarea[rows="40"],.uneditable-textarea[rows="40"]{height:820px}textarea[rows="45"],.uneditable-textarea[rows="45"]{height:920px}textarea[rows="50"],.uneditable-textarea[rows="50"]{height:1020px}textarea[rows="55"],.uneditable-textarea[rows="55"]{height:1120px}textarea[rows="60"],.uneditable-textarea[rows="60"]{height:1220px}textarea[rows="65"],.uneditable-textarea[rows="65"]{height:1320px}textarea[rows="70"],.uneditable-textarea[rows="70"]{height:1420px}textarea[rows="75"],.uneditable-textarea[rows="75"]{height:1520px}textarea[rows="80"],.uneditable-textarea[rows="80"]{height:1620px}textarea[rows="85"],.uneditable-textarea[rows="85"]{height:1720px}textarea[rows="90"],.uneditable-textarea[rows="90"]{height:1820px}textarea[rows="95"],.uneditable-textarea[rows="95"]{height:1920px}textarea[rows="100"],.uneditable-textarea[rows="100"]{height:2020px}.uneditable-textarea{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.uneditable-input[class*="span"],.uneditable-textarea[class*="span"],.row-fluid .uneditable-input[class*="span"],.row-fluid .uneditable-textarea[class*="span"]{float:none;margin-left:0}.input-append .uneditable-input,.input-prepend .uneditable-input{vertical-align:top}.input-append .uneditable-input[class*="span"],.input-prepend .uneditable-input[class*="span"]{display:inline-block}.uneditable-form input[disabled],.uneditable-form textarea[disabled],.uneditable-form select[disabled]{cursor:auto}.uneditable-form .uneditable-input,.uneditable-form .uneditable-textarea{cursor:text}.uneditable-form .form-actions{background-color:transparent}.header-actions{padding:0 20px;line-height:36px}.table-actions{padding-bottom:20px;*zoom:1}.table-actions:before,.table-actions:after{display:table;line-height:0;content:""}.table-actions:after{clear:both}tr.rowlink td{cursor:pointer}tr.rowlink td.nolink{cursor:auto}.table tbody tr.rowlink:hover td{background-color:#cfcfcf}a.rowlink{font:inherit;color:inherit;text-decoration:inherit}.act{display:inline;padding:0;font-weight:bold;color:#555;background:inherit;border:0;-webkit-transition:text-shadow .1s linear;-moz-transition:text-shadow .1s linear;-o-transition:text-shadow .1s linear;transition:text-shadow .1s linear}.act:hover{color:#333;text-decoration:none;text-shadow:1px 1px 3px rgba(85,85,85,0.5)}.act-primary{color:#006dcc}.act-primary:hover{color:#04c;text-shadow:1px 1px 3px rgba(0,109,204,0.5)}.act-info{color:#49afcd}.act-info:hover{color:#2f96b4;text-shadow:1px 1px 3px rgba(75,175,206,0.5)}.act-success{color:#51a351}.act-success:hover{color:#468847;text-shadow:1px 1px 3px rgba(81,164,81,0.5)}.act-warning{color:#c09853}.act-warning:hover{color:#f89406;text-shadow:1px 1px 3px rgba(192,152,84,0.5)}.act-danger{color:#b94a48}.act-danger:hover{color:#bd362f;text-shadow:1px 1px 3px rgba(185,72,70,0.5)}.act.disabled,.act[disabled]{color:#aaa;cursor:not-allowed}.act.disabled:hover,.act[disabled]:hover{color:#aaa;text-shadow:none}.form-actions .act{line-height:30px}@font-face{font-family:IconicStroke;font-weight:normal;src:url(../font/iconic_stroke.eot);src:local('IconicStroke'),url(../font/iconic_stroke.eot?#iefix) format('embedded-opentype'),url(../font/iconic_stroke.woff) format('woff'),url(../font/iconic_stroke.ttf) format('truetype'),url(../font/iconic_stroke.svg#iconic) format('svg'),url(../font/iconic_stroke.otf) format('opentype')}@font-face{font-family:IconicFill;font-weight:normal;src:url(../font/iconic_fill.eot);src:local('IconicFill'),url(../font/iconic_fill.eot?#iefix) format('embedded-opentype'),url(../font/iconic_fill.woff) format('woff'),url(../font/iconic_fill.ttf) format('truetype'),url(../font/iconic_fill.svg#iconic) format('svg'),url(../font/iconic_fill.otf) format('opentype')}@media screen,print{[class*="iconic-"]{font-style:inherit;font-weight:normal;vertical-align:bottom}[class*="iconic-"]:before{display:inline-block;width:1em;font-family:IconicFill;font-size:.9em;text-align:center;vertical-align:middle;content:""}.iconic-stroke:before{font-family:IconicStroke}.iconic-hash:before{content:'\23'}.iconic-question-mark:before{content:'\3f'}.iconic-at:before{content:'\40'}.iconic-pilcrow:before{content:'\b6'}.iconic-info:before{content:'\2139'}.iconic-arrow-left:before{content:'\2190'}.iconic-arrow-up:before{content:'\2191'}.iconic-arrow-right:before{content:'\2192'}.iconic-arrow-down:before{content:'\2193'}.iconic-home:before{content:'\2302'}.iconic-sun:before{content:'\2600'}.iconic-cloud:before{content:'\2601'}.iconic-umbrella:before{content:'\2602'}.iconic-star:before{content:'\2605'}.iconic-moon:before{content:'\263e'}.iconic-heart:before{content:'\2764'}.iconic-cog:before{content:'\2699'}.iconic-bolt:before{content:'\26a1'}.iconic-key:before{content:'\26bf'}.iconic-rain:before{content:'\26c6'}.iconic-denied:before{content:'\26d4'}.iconic-mail:before{content:'\2709'}.iconic-pen:before{content:'\270e'}.iconic-x:before{content:'\2717'}.iconic-o-x:before{content:'\2718'}.iconic-check:before{content:'\2713'}.iconic-o-check:before{content:'\2714'}.iconic-left-quote:before{content:'\275d'}.iconic-right-quote:before{content:'\275e'}.iconic-plus:before{content:'\2795'}.iconic-minus:before{content:'\2796'}.iconic-curved-arrow:before{content:'\2935'}.iconic-document-alt:before{content:'\e000'}.iconic-calendar:before{content:'\e001'}.iconic-map-pin-alt:before{content:'\e002'}.iconic-comment-alt1:before{content:'\e003'}.iconic-comment-alt2:before{content:'\e004'}.iconic-pen-alt:before{content:'\e005'}.iconic-pen-alt2:before{content:'\e006'}.iconic-chat-alt:before{content:'\e007'}.iconic-o-plus:before{content:'\e008'}.iconic-o-minus:before{content:'\e009'}.iconic-bars-alt:before{content:'\e00a'}.iconic-book-alt:before{content:'\e00b'}.iconic-aperture-alt:before{content:'\e00c'}.iconic-beaker-alt:before{content:'\e010'}.iconic-left-quote-alt:before{content:'\e011'}.iconic-right-quote-alt:before{content:'\e012'}.iconic-o-arrow-left:before{content:'\e013'}.iconic-o-arrow-up:before{content:'\e014'}.iconic-o-arrow-right:before{content:'\e015'}.iconic-o-arrow-down:before{content:'\e016'}.iconic-o-arrow-left-alt:before{content:'\e017'}.iconic-o-arrow-up-alt:before{content:'\e018'}.iconic-o-arrow-right-alt:before{content:'\e019'}.iconic-o-arrow-down-alt:before{content:'\e01a'}.iconic-brush:before{content:'\e01b'}.iconic-brush-alt:before{content:'\e01c'}.iconic-eyedropper:before{content:'\e01e'}.iconic-layers:before{content:'\e01f'}.iconic-layers-alt:before{content:'\e020'}.iconic-compass:before{content:'\e021'}.iconic-award:before{content:'\e022'}.iconic-beaker:before{content:'\e023'}.iconic-steering-wheel:before{content:'\e024'}.iconic-eye:before{content:'\e025'}.iconic-aperture:before{content:'\e026'}.iconic-image:before{content:'\e027'}.iconic-chart:before{content:'\e028'}.iconic-chart-alt:before{content:'\e029'}.iconic-target:before{content:'\e02a'}.iconic-tag:before{content:'\e02b'}.iconic-rss:before{content:'\e02c'}.iconic-rss-alt:before{content:'\e02d'}.iconic-share:before{content:'\e02e'}.iconic-undo:before{content:'\e02f'}.iconic-reload:before{content:'\e030'}.iconic-reload-alt:before{content:'\e031'}.iconic-loop:before{content:'\e032'}.iconic-loop-alt:before{content:'\e033'}.iconic-back-forth:before{content:'\e034'}.iconic-back-forth-alt:before{content:'\e035'}.iconic-spin:before{content:'\e036'}.iconic-spin-alt:before{content:'\e037'}.iconic-move-horizontal:before{content:'\e038'}.iconic-move-horizontal-alt:before{content:'\e039'}.iconic-o-move-horizontal:before{content:'\e03a'}.iconic-move-vertical:before{content:'\e03b'}.iconic-move-vertical-alt:before{content:'\e03c'}.iconic-o-move-vertical:before{content:'\e03d'}.iconic-move:before{content:'\e03e'}.iconic-move-alt:before{content:'\e03f'}.iconic-o-move:before{content:'\e040'}.iconic-transfer:before{content:'\e041'}.iconic-download:before{content:'\e042'}.iconic-upload:before{content:'\e043'}.iconic-cloud-download:before{content:'\e044'}.iconic-cloud-upload:before{content:'\e045'}.iconic-fork:before{content:'\e046'}.iconic-play:before{content:'\e047'}.iconic-o-play:before{content:'\e048'}.iconic-pause:before{content:'\e049'}.iconic-stop:before{content:'\e04a'}.iconic-eject:before{content:'\e04b'}.iconic-first:before{content:'\e04c'}.iconic-last:before{content:'\e04d'}.iconic-fullscreen:before{content:'\e04e'}.iconic-fullscreen-alt:before{content:'\e04f'}.iconic-fullscreen-exit:before{content:'\e050'}.iconic-fullscreen-exit-alt:before{content:'\e051'}.iconic-equalizer:before{content:'\e052'}.iconic-article:before{content:'\e053'}.iconic-read-more:before{content:'\e054'}.iconic-list:before{content:'\e055'}.iconic-list-nested:before{content:'\e056'}.iconic-cursor:before{content:'\e057'}.iconic-dial:before{content:'\e058'}.iconic-new-window:before{content:'\e059'}.iconic-trash:before{content:'\e05a'}.iconic-battery-half:before{content:'\e05b'}.iconic-battery-empty:before{content:'\e05c'}.iconic-battery-charging:before{content:'\e05d'}.iconic-chat:before{content:'\e05e'}.iconic-mic:before{content:'\e05f'}.iconic-movie:before{content:'\e060'}.iconic-headphones:before{content:'\e061'}.iconic-user:before{content:'\e062'}.iconic-lightbulb:before{content:'\e063'}.iconic-cd:before{content:'\e064'}.iconic-folder:before{content:'\e065'}.iconic-document:before{content:'\e066'}.iconic-pin:before{content:'\e067'}.iconic-map-pin:before{content:'\e068'}.iconic-book:before{content:'\e069'}.iconic-book-alt2:before{content:'\e06a'}.iconic-box:before{content:'\e06b'}.iconic-calendar-alt:before{content:'\e06c'}.iconic-comment:before{content:'\e06d'}.iconic-iphone:before{content:'\e06e'}.iconic-bars:before{content:'\e06f'}.iconic-camera:before{content:'\e070'}.iconic-volume-mute:before{content:'\e071'}.iconic-volume:before{content:'\e072'}.iconic-battery-full:before{content:'\e073'}.iconic-magnifying-glass:before{content:'\e074'}.iconic-lock:before{content:'\e075'}.iconic-unlock:before{content:'\e076'}.iconic-link:before{content:'\e077'}.iconic-wrench:before{content:'\e078'}.iconic-clock:before{content:'\e079'}.iconic-sun-stroke:before{font-family:IconicStroke;content:'\2600'}.iconic-moon-stroke:before{font-family:IconicStroke;content:'\263e'}.iconic-star-stroke:before{font-family:IconicStroke;content:'\2605'}.iconic-heart-stroke:before{font-family:IconicStroke;content:'\2764'}.iconic-key-stroke:before{font-family:IconicStroke;content:'\26bf'}.iconic-document-alt-stroke:before{font-family:IconicStroke;content:'\e000'}.iconic-comment-alt1-stroke:before{font-family:IconicStroke;content:'\e003'}.iconic-comment-alt2-stroke:before{font-family:IconicStroke;content:'\e004'}.iconic-pen-alt-stroke:before{font-family:IconicStroke;content:'\e005'}.iconic-chat-alt-stroke:before{font-family:IconicStroke;content:'\e007'}.iconic-award-stroke:before{font-family:IconicStroke;content:'\e022'}.iconic-tag-stroke:before{font-family:IconicStroke;content:'\e02b'}.iconic-trash-stroke:before{font-family:IconicStroke;content:'\e05a'}.iconic-folder-stroke:before{font-family:IconicStroke;content:'\e065'}.iconic-document-stroke:before{font-family:IconicStroke;content:'\e066'}.iconic-map-pin-stroke:before{font-family:IconicStroke;content:'\e068'}.iconic-calendar-alt-stroke:before{font-family:IconicStroke;content:'\e06c'}.iconic-comment-stroke:before{font-family:IconicStroke;content:'\e06d'}.iconic-lock-stroke:before{font-family:IconicStroke;content:'\e075'}.iconic-unlock-stroke:before{font-family:IconicStroke;content:'\e076'}}.page-alert{position:absolute;top:0;left:50%;z-index:1020;width:0}.page-alert .alert{width:550px;margin-left:-300px;border-top-width:0;-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}.navbar-fixed-top+.page-alert{top:40px}body>.page-alert{position:fixed}.btn-file{position:relative;overflow:hidden;vertical-align:middle}.btn-file>input{position:absolute;top:0;right:0;margin:0;font-size:23px;cursor:pointer;opacity:0;filter:alpha(opacity=0);transform:translate(-300px,0) scale(4);direction:ltr}.fileupload{margin-bottom:9px}.fileupload .uneditable-input{display:inline-block;margin-bottom:0;vertical-align:middle;cursor:text}.fileupload .thumbnail{display:inline-block;margin-bottom:5px;overflow:hidden;text-align:center;vertical-align:middle}.fileupload .thumbnail>img{display:inline-block;max-height:100%;vertical-align:middle}.fileupload .btn{vertical-align:middle}.fileupload-exists .fileupload-new,.fileupload-new .fileupload-exists{display:none}.fileupload-inline .fileupload-controls{display:inline}.fileupload-new .input-append .btn-file{-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0}.thumbnail-borderless .thumbnail{padding:0;border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.fileupload-new.thumbnail-borderless .thumbnail{border:1px solid #ddd}.control-group.warning .fileupload .uneditable-input{color:#a47e3c;border-color:#a47e3c}.control-group.warning .fileupload .fileupload-preview{color:#a47e3c}.control-group.warning .fileupload .thumbnail{border-color:#a47e3c}.control-group.error .fileupload .uneditable-input{color:#b94a48;border-color:#b94a48}.control-group.error .fileupload .fileupload-preview{color:#b94a48}.control-group.error .fileupload .thumbnail{border-color:#b94a48}.control-group.success .fileupload .uneditable-input{color:#468847;border-color:#468847}.control-group.success .fileupload .fileupload-preview{color:#468847}.control-group.success .fileupload .thumbnail{border-color:#468847}.nav-tabs>li>a,.nav-pills>li>a{outline:0}.nav-tabs>li.disabled>a{color:#ccc;cursor:not-allowed}.tabbable{border-color:#ddd;border-style:solid;border-width:0;*zoom:1}.tabbable:before,.tabbable:after{display:table;line-height:0;content:""}.tabbable:after{clear:both}.tabbable>.nav-tabs{margin:0}.tab-content{padding:18px 0 0 0;overflow:auto;border-color:#ddd;border-style:solid;border-width:0}.tabbable-bordered{-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.tabbable-bordered>.tab-content{padding:20px 20px 10px 20px;border-width:0 1px 1px 1px;-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}body>.container.tabbable>.nav-tabs{padding-top:15px}.tabs-below>.tab-content{padding:0 0 10px 0}.tabs-below.tabbable-bordered>.tab-content{padding:20px 20px 10px 20px;border-width:1px 1px 0 1px;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}body>.container.tabs-below.tabbable-bodered>.tab-content{border-top-width:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.tabs-left,.tabs-right{margin-bottom:20px}.tabs-left>.nav-tabs,.tabs-right>.nav-tabs{position:relative;z-index:1;margin-bottom:0}.tabs-left>.tab-content,.tabs-right>.tab-content{overflow:hidden}.tabs-left>.nav-tabs{left:1px}.tabs-left>.nav-tabs>.active>a,.tabs-left>.nav-tabs>.active>a:hover{border-color:#ddd transparent #ddd #ddd;*border-right-color:#fff}.tabs-left>.tab-content{padding:0 0 0 19px;border-left-width:1px}.tabs-left.tabbable-bordered{border-width:0 1px 0 0}.tabs-left.tabbable-bordered>.tab-content{padding:20px 20px 10px 20px;border-width:1px 0 1px 1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}body>.container.tabs-left.tabbable-bodered>.tab-content{border-top-width:0;-webkit-border-radius:0 0 4px 0;-moz-border-radius:0 0 4px 0;border-radius:0 0 4px 0}.tabs-right>.nav-tabs{right:1px}.tabs-right>.nav-tabs>.active>a,.tabs-right>.nav-tabs>.active>a:hover{border-color:#ddd #ddd #ddd transparent;*border-left-color:#fff}.tabs-right>.tab-content{padding:0 19px 0 0;border-right-width:1px}.tabs-right.tabbable-bordered{border-width:0 0 0 1px}.tabs-right.tabbable-bordered>.tab-content{padding:20px 20px 10px 20px;border-width:1px 1px 1px 0;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}body>.container.tabs-right.tabbable-bodered>.tab-content{border-top-width:0;-webkit-border-radius:0 0 0 4px;-moz-border-radius:0 0 0 4px;border-radius:0 0 0 4px} 10 | -------------------------------------------------------------------------------- /demo/css/bootstrap-responsive.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Responsive v2.2.1 3 | * 4 | * Copyright 2012 Twitter, Inc 5 | * Licensed under the Apache License v2.0 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Designed and built with all the love in the world @twitter by @mdo and @fat. 9 | */ 10 | 11 | .clearfix { 12 | *zoom: 1; 13 | } 14 | 15 | .clearfix:before, 16 | .clearfix:after { 17 | display: table; 18 | line-height: 0; 19 | content: ""; 20 | } 21 | 22 | .clearfix:after { 23 | clear: both; 24 | } 25 | 26 | .hide-text { 27 | font: 0/0 a; 28 | color: transparent; 29 | text-shadow: none; 30 | background-color: transparent; 31 | border: 0; 32 | } 33 | 34 | .input-block-level { 35 | display: block; 36 | width: 100%; 37 | min-height: 30px; 38 | -webkit-box-sizing: border-box; 39 | -moz-box-sizing: border-box; 40 | box-sizing: border-box; 41 | } 42 | 43 | .hidden { 44 | display: none; 45 | visibility: hidden; 46 | } 47 | 48 | .visible-phone { 49 | display: none !important; 50 | } 51 | 52 | .visible-tablet { 53 | display: none !important; 54 | } 55 | 56 | .hidden-desktop { 57 | display: none !important; 58 | } 59 | 60 | .visible-desktop { 61 | display: inherit !important; 62 | } 63 | 64 | @media (min-width: 768px) and (max-width: 979px) { 65 | .hidden-desktop { 66 | display: inherit !important; 67 | } 68 | .visible-desktop { 69 | display: none !important ; 70 | } 71 | .visible-tablet { 72 | display: inherit !important; 73 | } 74 | .hidden-tablet { 75 | display: none !important; 76 | } 77 | } 78 | 79 | @media (max-width: 767px) { 80 | .hidden-desktop { 81 | display: inherit !important; 82 | } 83 | .visible-desktop { 84 | display: none !important; 85 | } 86 | .visible-phone { 87 | display: inherit !important; 88 | } 89 | .hidden-phone { 90 | display: none !important; 91 | } 92 | } 93 | 94 | @media (min-width: 1200px) { 95 | .row { 96 | margin-left: -30px; 97 | *zoom: 1; 98 | } 99 | .row:before, 100 | .row:after { 101 | display: table; 102 | line-height: 0; 103 | content: ""; 104 | } 105 | .row:after { 106 | clear: both; 107 | } 108 | [class*="span"] { 109 | float: left; 110 | min-height: 1px; 111 | margin-left: 30px; 112 | } 113 | .container, 114 | .navbar-static-top .container, 115 | .navbar-fixed-top .container, 116 | .navbar-fixed-bottom .container { 117 | width: 1170px; 118 | } 119 | .span12 { 120 | width: 1170px; 121 | } 122 | .span11 { 123 | width: 1070px; 124 | } 125 | .span10 { 126 | width: 970px; 127 | } 128 | .span9 { 129 | width: 870px; 130 | } 131 | .span8 { 132 | width: 770px; 133 | } 134 | .span7 { 135 | width: 670px; 136 | } 137 | .span6 { 138 | width: 570px; 139 | } 140 | .span5 { 141 | width: 470px; 142 | } 143 | .span4 { 144 | width: 370px; 145 | } 146 | .span3 { 147 | width: 270px; 148 | } 149 | .span2 { 150 | width: 170px; 151 | } 152 | .span1 { 153 | width: 70px; 154 | } 155 | .offset12 { 156 | margin-left: 1230px; 157 | } 158 | .offset11 { 159 | margin-left: 1130px; 160 | } 161 | .offset10 { 162 | margin-left: 1030px; 163 | } 164 | .offset9 { 165 | margin-left: 930px; 166 | } 167 | .offset8 { 168 | margin-left: 830px; 169 | } 170 | .offset7 { 171 | margin-left: 730px; 172 | } 173 | .offset6 { 174 | margin-left: 630px; 175 | } 176 | .offset5 { 177 | margin-left: 530px; 178 | } 179 | .offset4 { 180 | margin-left: 430px; 181 | } 182 | .offset3 { 183 | margin-left: 330px; 184 | } 185 | .offset2 { 186 | margin-left: 230px; 187 | } 188 | .offset1 { 189 | margin-left: 130px; 190 | } 191 | .row-fluid { 192 | width: 100%; 193 | *zoom: 1; 194 | } 195 | .row-fluid:before, 196 | .row-fluid:after { 197 | display: table; 198 | line-height: 0; 199 | content: ""; 200 | } 201 | .row-fluid:after { 202 | clear: both; 203 | } 204 | .row-fluid [class*="span"] { 205 | display: block; 206 | float: left; 207 | width: 100%; 208 | min-height: 30px; 209 | margin-left: 2.564102564102564%; 210 | *margin-left: 2.5109110747408616%; 211 | -webkit-box-sizing: border-box; 212 | -moz-box-sizing: border-box; 213 | box-sizing: border-box; 214 | } 215 | .row-fluid [class*="span"]:first-child { 216 | margin-left: 0; 217 | } 218 | .row-fluid .controls-row [class*="span"] + [class*="span"] { 219 | margin-left: 2.564102564102564%; 220 | } 221 | .row-fluid .span12 { 222 | width: 100%; 223 | *width: 99.94680851063829%; 224 | } 225 | .row-fluid .span11 { 226 | width: 91.45299145299145%; 227 | *width: 91.39979996362975%; 228 | } 229 | .row-fluid .span10 { 230 | width: 82.90598290598291%; 231 | *width: 82.8527914166212%; 232 | } 233 | .row-fluid .span9 { 234 | width: 74.35897435897436%; 235 | *width: 74.30578286961266%; 236 | } 237 | .row-fluid .span8 { 238 | width: 65.81196581196582%; 239 | *width: 65.75877432260411%; 240 | } 241 | .row-fluid .span7 { 242 | width: 57.26495726495726%; 243 | *width: 57.21176577559556%; 244 | } 245 | .row-fluid .span6 { 246 | width: 48.717948717948715%; 247 | *width: 48.664757228587014%; 248 | } 249 | .row-fluid .span5 { 250 | width: 40.17094017094017%; 251 | *width: 40.11774868157847%; 252 | } 253 | .row-fluid .span4 { 254 | width: 31.623931623931625%; 255 | *width: 31.570740134569924%; 256 | } 257 | .row-fluid .span3 { 258 | width: 23.076923076923077%; 259 | *width: 23.023731587561375%; 260 | } 261 | .row-fluid .span2 { 262 | width: 14.52991452991453%; 263 | *width: 14.476723040552828%; 264 | } 265 | .row-fluid .span1 { 266 | width: 5.982905982905983%; 267 | *width: 5.929714493544281%; 268 | } 269 | .row-fluid .offset12 { 270 | margin-left: 105.12820512820512%; 271 | *margin-left: 105.02182214948171%; 272 | } 273 | .row-fluid .offset12:first-child { 274 | margin-left: 102.56410256410257%; 275 | *margin-left: 102.45771958537915%; 276 | } 277 | .row-fluid .offset11 { 278 | margin-left: 96.58119658119658%; 279 | *margin-left: 96.47481360247316%; 280 | } 281 | .row-fluid .offset11:first-child { 282 | margin-left: 94.01709401709402%; 283 | *margin-left: 93.91071103837061%; 284 | } 285 | .row-fluid .offset10 { 286 | margin-left: 88.03418803418803%; 287 | *margin-left: 87.92780505546462%; 288 | } 289 | .row-fluid .offset10:first-child { 290 | margin-left: 85.47008547008548%; 291 | *margin-left: 85.36370249136206%; 292 | } 293 | .row-fluid .offset9 { 294 | margin-left: 79.48717948717949%; 295 | *margin-left: 79.38079650845607%; 296 | } 297 | .row-fluid .offset9:first-child { 298 | margin-left: 76.92307692307693%; 299 | *margin-left: 76.81669394435352%; 300 | } 301 | .row-fluid .offset8 { 302 | margin-left: 70.94017094017094%; 303 | *margin-left: 70.83378796144753%; 304 | } 305 | .row-fluid .offset8:first-child { 306 | margin-left: 68.37606837606839%; 307 | *margin-left: 68.26968539734497%; 308 | } 309 | .row-fluid .offset7 { 310 | margin-left: 62.393162393162385%; 311 | *margin-left: 62.28677941443899%; 312 | } 313 | .row-fluid .offset7:first-child { 314 | margin-left: 59.82905982905982%; 315 | *margin-left: 59.72267685033642%; 316 | } 317 | .row-fluid .offset6 { 318 | margin-left: 53.84615384615384%; 319 | *margin-left: 53.739770867430444%; 320 | } 321 | .row-fluid .offset6:first-child { 322 | margin-left: 51.28205128205128%; 323 | *margin-left: 51.175668303327875%; 324 | } 325 | .row-fluid .offset5 { 326 | margin-left: 45.299145299145295%; 327 | *margin-left: 45.1927623204219%; 328 | } 329 | .row-fluid .offset5:first-child { 330 | margin-left: 42.73504273504273%; 331 | *margin-left: 42.62865975631933%; 332 | } 333 | .row-fluid .offset4 { 334 | margin-left: 36.75213675213675%; 335 | *margin-left: 36.645753773413354%; 336 | } 337 | .row-fluid .offset4:first-child { 338 | margin-left: 34.18803418803419%; 339 | *margin-left: 34.081651209310785%; 340 | } 341 | .row-fluid .offset3 { 342 | margin-left: 28.205128205128204%; 343 | *margin-left: 28.0987452264048%; 344 | } 345 | .row-fluid .offset3:first-child { 346 | margin-left: 25.641025641025642%; 347 | *margin-left: 25.53464266230224%; 348 | } 349 | .row-fluid .offset2 { 350 | margin-left: 19.65811965811966%; 351 | *margin-left: 19.551736679396257%; 352 | } 353 | .row-fluid .offset2:first-child { 354 | margin-left: 17.094017094017094%; 355 | *margin-left: 16.98763411529369%; 356 | } 357 | .row-fluid .offset1 { 358 | margin-left: 11.11111111111111%; 359 | *margin-left: 11.004728132387708%; 360 | } 361 | .row-fluid .offset1:first-child { 362 | margin-left: 8.547008547008547%; 363 | *margin-left: 8.440625568285142%; 364 | } 365 | input, 366 | textarea, 367 | .uneditable-input { 368 | margin-left: 0; 369 | } 370 | .controls-row [class*="span"] + [class*="span"] { 371 | margin-left: 30px; 372 | } 373 | input.span12, 374 | textarea.span12, 375 | .uneditable-input.span12 { 376 | width: 1156px; 377 | } 378 | input.span11, 379 | textarea.span11, 380 | .uneditable-input.span11 { 381 | width: 1056px; 382 | } 383 | input.span10, 384 | textarea.span10, 385 | .uneditable-input.span10 { 386 | width: 956px; 387 | } 388 | input.span9, 389 | textarea.span9, 390 | .uneditable-input.span9 { 391 | width: 856px; 392 | } 393 | input.span8, 394 | textarea.span8, 395 | .uneditable-input.span8 { 396 | width: 756px; 397 | } 398 | input.span7, 399 | textarea.span7, 400 | .uneditable-input.span7 { 401 | width: 656px; 402 | } 403 | input.span6, 404 | textarea.span6, 405 | .uneditable-input.span6 { 406 | width: 556px; 407 | } 408 | input.span5, 409 | textarea.span5, 410 | .uneditable-input.span5 { 411 | width: 456px; 412 | } 413 | input.span4, 414 | textarea.span4, 415 | .uneditable-input.span4 { 416 | width: 356px; 417 | } 418 | input.span3, 419 | textarea.span3, 420 | .uneditable-input.span3 { 421 | width: 256px; 422 | } 423 | input.span2, 424 | textarea.span2, 425 | .uneditable-input.span2 { 426 | width: 156px; 427 | } 428 | input.span1, 429 | textarea.span1, 430 | .uneditable-input.span1 { 431 | width: 56px; 432 | } 433 | .thumbnails { 434 | margin-left: -30px; 435 | } 436 | .thumbnails > li { 437 | margin-left: 30px; 438 | } 439 | .row-fluid .thumbnails { 440 | margin-left: 0; 441 | } 442 | } 443 | 444 | @media (min-width: 768px) and (max-width: 979px) { 445 | .row { 446 | margin-left: -20px; 447 | *zoom: 1; 448 | } 449 | .row:before, 450 | .row:after { 451 | display: table; 452 | line-height: 0; 453 | content: ""; 454 | } 455 | .row:after { 456 | clear: both; 457 | } 458 | [class*="span"] { 459 | float: left; 460 | min-height: 1px; 461 | margin-left: 20px; 462 | } 463 | .container, 464 | .navbar-static-top .container, 465 | .navbar-fixed-top .container, 466 | .navbar-fixed-bottom .container { 467 | width: 724px; 468 | } 469 | .span12 { 470 | width: 724px; 471 | } 472 | .span11 { 473 | width: 662px; 474 | } 475 | .span10 { 476 | width: 600px; 477 | } 478 | .span9 { 479 | width: 538px; 480 | } 481 | .span8 { 482 | width: 476px; 483 | } 484 | .span7 { 485 | width: 414px; 486 | } 487 | .span6 { 488 | width: 352px; 489 | } 490 | .span5 { 491 | width: 290px; 492 | } 493 | .span4 { 494 | width: 228px; 495 | } 496 | .span3 { 497 | width: 166px; 498 | } 499 | .span2 { 500 | width: 104px; 501 | } 502 | .span1 { 503 | width: 42px; 504 | } 505 | .offset12 { 506 | margin-left: 764px; 507 | } 508 | .offset11 { 509 | margin-left: 702px; 510 | } 511 | .offset10 { 512 | margin-left: 640px; 513 | } 514 | .offset9 { 515 | margin-left: 578px; 516 | } 517 | .offset8 { 518 | margin-left: 516px; 519 | } 520 | .offset7 { 521 | margin-left: 454px; 522 | } 523 | .offset6 { 524 | margin-left: 392px; 525 | } 526 | .offset5 { 527 | margin-left: 330px; 528 | } 529 | .offset4 { 530 | margin-left: 268px; 531 | } 532 | .offset3 { 533 | margin-left: 206px; 534 | } 535 | .offset2 { 536 | margin-left: 144px; 537 | } 538 | .offset1 { 539 | margin-left: 82px; 540 | } 541 | .row-fluid { 542 | width: 100%; 543 | *zoom: 1; 544 | } 545 | .row-fluid:before, 546 | .row-fluid:after { 547 | display: table; 548 | line-height: 0; 549 | content: ""; 550 | } 551 | .row-fluid:after { 552 | clear: both; 553 | } 554 | .row-fluid [class*="span"] { 555 | display: block; 556 | float: left; 557 | width: 100%; 558 | min-height: 30px; 559 | margin-left: 2.7624309392265194%; 560 | *margin-left: 2.709239449864817%; 561 | -webkit-box-sizing: border-box; 562 | -moz-box-sizing: border-box; 563 | box-sizing: border-box; 564 | } 565 | .row-fluid [class*="span"]:first-child { 566 | margin-left: 0; 567 | } 568 | .row-fluid .controls-row [class*="span"] + [class*="span"] { 569 | margin-left: 2.7624309392265194%; 570 | } 571 | .row-fluid .span12 { 572 | width: 100%; 573 | *width: 99.94680851063829%; 574 | } 575 | .row-fluid .span11 { 576 | width: 91.43646408839778%; 577 | *width: 91.38327259903608%; 578 | } 579 | .row-fluid .span10 { 580 | width: 82.87292817679558%; 581 | *width: 82.81973668743387%; 582 | } 583 | .row-fluid .span9 { 584 | width: 74.30939226519337%; 585 | *width: 74.25620077583166%; 586 | } 587 | .row-fluid .span8 { 588 | width: 65.74585635359117%; 589 | *width: 65.69266486422946%; 590 | } 591 | .row-fluid .span7 { 592 | width: 57.18232044198895%; 593 | *width: 57.12912895262725%; 594 | } 595 | .row-fluid .span6 { 596 | width: 48.61878453038674%; 597 | *width: 48.56559304102504%; 598 | } 599 | .row-fluid .span5 { 600 | width: 40.05524861878453%; 601 | *width: 40.00205712942283%; 602 | } 603 | .row-fluid .span4 { 604 | width: 31.491712707182323%; 605 | *width: 31.43852121782062%; 606 | } 607 | .row-fluid .span3 { 608 | width: 22.92817679558011%; 609 | *width: 22.87498530621841%; 610 | } 611 | .row-fluid .span2 { 612 | width: 14.3646408839779%; 613 | *width: 14.311449394616199%; 614 | } 615 | .row-fluid .span1 { 616 | width: 5.801104972375691%; 617 | *width: 5.747913483013988%; 618 | } 619 | .row-fluid .offset12 { 620 | margin-left: 105.52486187845304%; 621 | *margin-left: 105.41847889972962%; 622 | } 623 | .row-fluid .offset12:first-child { 624 | margin-left: 102.76243093922652%; 625 | *margin-left: 102.6560479605031%; 626 | } 627 | .row-fluid .offset11 { 628 | margin-left: 96.96132596685082%; 629 | *margin-left: 96.8549429881274%; 630 | } 631 | .row-fluid .offset11:first-child { 632 | margin-left: 94.1988950276243%; 633 | *margin-left: 94.09251204890089%; 634 | } 635 | .row-fluid .offset10 { 636 | margin-left: 88.39779005524862%; 637 | *margin-left: 88.2914070765252%; 638 | } 639 | .row-fluid .offset10:first-child { 640 | margin-left: 85.6353591160221%; 641 | *margin-left: 85.52897613729868%; 642 | } 643 | .row-fluid .offset9 { 644 | margin-left: 79.8342541436464%; 645 | *margin-left: 79.72787116492299%; 646 | } 647 | .row-fluid .offset9:first-child { 648 | margin-left: 77.07182320441989%; 649 | *margin-left: 76.96544022569647%; 650 | } 651 | .row-fluid .offset8 { 652 | margin-left: 71.2707182320442%; 653 | *margin-left: 71.16433525332079%; 654 | } 655 | .row-fluid .offset8:first-child { 656 | margin-left: 68.50828729281768%; 657 | *margin-left: 68.40190431409427%; 658 | } 659 | .row-fluid .offset7 { 660 | margin-left: 62.70718232044199%; 661 | *margin-left: 62.600799341718584%; 662 | } 663 | .row-fluid .offset7:first-child { 664 | margin-left: 59.94475138121547%; 665 | *margin-left: 59.838368402492065%; 666 | } 667 | .row-fluid .offset6 { 668 | margin-left: 54.14364640883978%; 669 | *margin-left: 54.037263430116376%; 670 | } 671 | .row-fluid .offset6:first-child { 672 | margin-left: 51.38121546961326%; 673 | *margin-left: 51.27483249088986%; 674 | } 675 | .row-fluid .offset5 { 676 | margin-left: 45.58011049723757%; 677 | *margin-left: 45.47372751851417%; 678 | } 679 | .row-fluid .offset5:first-child { 680 | margin-left: 42.81767955801105%; 681 | *margin-left: 42.71129657928765%; 682 | } 683 | .row-fluid .offset4 { 684 | margin-left: 37.01657458563536%; 685 | *margin-left: 36.91019160691196%; 686 | } 687 | .row-fluid .offset4:first-child { 688 | margin-left: 34.25414364640884%; 689 | *margin-left: 34.14776066768544%; 690 | } 691 | .row-fluid .offset3 { 692 | margin-left: 28.45303867403315%; 693 | *margin-left: 28.346655695309746%; 694 | } 695 | .row-fluid .offset3:first-child { 696 | margin-left: 25.69060773480663%; 697 | *margin-left: 25.584224756083227%; 698 | } 699 | .row-fluid .offset2 { 700 | margin-left: 19.88950276243094%; 701 | *margin-left: 19.783119783707537%; 702 | } 703 | .row-fluid .offset2:first-child { 704 | margin-left: 17.12707182320442%; 705 | *margin-left: 17.02068884448102%; 706 | } 707 | .row-fluid .offset1 { 708 | margin-left: 11.32596685082873%; 709 | *margin-left: 11.219583872105325%; 710 | } 711 | .row-fluid .offset1:first-child { 712 | margin-left: 8.56353591160221%; 713 | *margin-left: 8.457152932878806%; 714 | } 715 | input, 716 | textarea, 717 | .uneditable-input { 718 | margin-left: 0; 719 | } 720 | .controls-row [class*="span"] + [class*="span"] { 721 | margin-left: 20px; 722 | } 723 | input.span12, 724 | textarea.span12, 725 | .uneditable-input.span12 { 726 | width: 710px; 727 | } 728 | input.span11, 729 | textarea.span11, 730 | .uneditable-input.span11 { 731 | width: 648px; 732 | } 733 | input.span10, 734 | textarea.span10, 735 | .uneditable-input.span10 { 736 | width: 586px; 737 | } 738 | input.span9, 739 | textarea.span9, 740 | .uneditable-input.span9 { 741 | width: 524px; 742 | } 743 | input.span8, 744 | textarea.span8, 745 | .uneditable-input.span8 { 746 | width: 462px; 747 | } 748 | input.span7, 749 | textarea.span7, 750 | .uneditable-input.span7 { 751 | width: 400px; 752 | } 753 | input.span6, 754 | textarea.span6, 755 | .uneditable-input.span6 { 756 | width: 338px; 757 | } 758 | input.span5, 759 | textarea.span5, 760 | .uneditable-input.span5 { 761 | width: 276px; 762 | } 763 | input.span4, 764 | textarea.span4, 765 | .uneditable-input.span4 { 766 | width: 214px; 767 | } 768 | input.span3, 769 | textarea.span3, 770 | .uneditable-input.span3 { 771 | width: 152px; 772 | } 773 | input.span2, 774 | textarea.span2, 775 | .uneditable-input.span2 { 776 | width: 90px; 777 | } 778 | input.span1, 779 | textarea.span1, 780 | .uneditable-input.span1 { 781 | width: 28px; 782 | } 783 | } 784 | 785 | @media (max-width: 767px) { 786 | body { 787 | padding-right: 20px; 788 | padding-left: 20px; 789 | } 790 | .navbar-fixed-top, 791 | .navbar-fixed-bottom, 792 | .navbar-static-top { 793 | margin-right: -20px; 794 | margin-left: -20px; 795 | } 796 | .container-fluid { 797 | padding: 0; 798 | } 799 | .dl-horizontal dt { 800 | float: none; 801 | width: auto; 802 | clear: none; 803 | text-align: left; 804 | } 805 | .dl-horizontal dd { 806 | margin-left: 0; 807 | } 808 | .container { 809 | width: auto; 810 | } 811 | .row-fluid { 812 | width: 100%; 813 | } 814 | .row, 815 | .thumbnails { 816 | margin-left: 0; 817 | } 818 | .thumbnails > li { 819 | float: none; 820 | margin-left: 0; 821 | } 822 | [class*="span"], 823 | .uneditable-input[class*="span"], 824 | .row-fluid [class*="span"] { 825 | display: block; 826 | float: none; 827 | width: 100%; 828 | margin-left: 0; 829 | -webkit-box-sizing: border-box; 830 | -moz-box-sizing: border-box; 831 | box-sizing: border-box; 832 | } 833 | .span12, 834 | .row-fluid .span12 { 835 | width: 100%; 836 | -webkit-box-sizing: border-box; 837 | -moz-box-sizing: border-box; 838 | box-sizing: border-box; 839 | } 840 | .row-fluid [class*="offset"]:first-child { 841 | margin-left: 0; 842 | } 843 | .input-large, 844 | .input-xlarge, 845 | .input-xxlarge, 846 | input[class*="span"], 847 | select[class*="span"], 848 | textarea[class*="span"], 849 | .uneditable-input { 850 | display: block; 851 | width: 100%; 852 | min-height: 30px; 853 | -webkit-box-sizing: border-box; 854 | -moz-box-sizing: border-box; 855 | box-sizing: border-box; 856 | } 857 | .input-prepend input, 858 | .input-append input, 859 | .input-prepend input[class*="span"], 860 | .input-append input[class*="span"] { 861 | display: inline-block; 862 | width: auto; 863 | } 864 | .controls-row [class*="span"] + [class*="span"] { 865 | margin-left: 0; 866 | } 867 | .modal { 868 | position: fixed; 869 | top: 20px; 870 | right: 20px; 871 | left: 20px; 872 | width: auto; 873 | margin: 0; 874 | } 875 | .modal.fade { 876 | top: -100px; 877 | } 878 | .modal.fade.in { 879 | top: 20px; 880 | } 881 | } 882 | 883 | @media (max-width: 480px) { 884 | .nav-collapse { 885 | -webkit-transform: translate3d(0, 0, 0); 886 | } 887 | .page-header h1 small { 888 | display: block; 889 | line-height: 20px; 890 | } 891 | input[type="checkbox"], 892 | input[type="radio"] { 893 | border: 1px solid #ccc; 894 | } 895 | .form-horizontal .control-label { 896 | float: none; 897 | width: auto; 898 | padding-top: 0; 899 | text-align: left; 900 | } 901 | .form-horizontal .controls { 902 | margin-left: 0; 903 | } 904 | .form-horizontal .control-list { 905 | padding-top: 0; 906 | } 907 | .form-horizontal .form-actions { 908 | padding-right: 10px; 909 | padding-left: 10px; 910 | } 911 | .media .pull-left, 912 | .media .pull-right { 913 | display: block; 914 | float: none; 915 | margin-bottom: 10px; 916 | } 917 | .media-object { 918 | margin-right: 0; 919 | margin-left: 0; 920 | } 921 | .modal { 922 | top: 10px; 923 | right: 10px; 924 | left: 10px; 925 | } 926 | .modal-header .close { 927 | padding: 10px; 928 | margin: -10px; 929 | } 930 | .carousel-caption { 931 | position: static; 932 | } 933 | } 934 | 935 | @media (max-width: 979px) { 936 | body { 937 | padding-top: 0; 938 | } 939 | .navbar-fixed-top, 940 | .navbar-fixed-bottom { 941 | position: static; 942 | } 943 | .navbar-fixed-top { 944 | margin-bottom: 20px; 945 | } 946 | .navbar-fixed-bottom { 947 | margin-top: 20px; 948 | } 949 | .navbar-fixed-top .navbar-inner, 950 | .navbar-fixed-bottom .navbar-inner { 951 | padding: 5px; 952 | } 953 | .navbar .container { 954 | width: auto; 955 | padding: 0; 956 | } 957 | .navbar .brand { 958 | padding-right: 10px; 959 | padding-left: 10px; 960 | margin: 0 0 0 -5px; 961 | } 962 | .nav-collapse { 963 | clear: both; 964 | } 965 | .nav-collapse .nav { 966 | float: none; 967 | margin: 0 0 10px; 968 | } 969 | .nav-collapse .nav > li { 970 | float: none; 971 | } 972 | .nav-collapse .nav > li > a { 973 | margin-bottom: 2px; 974 | } 975 | .nav-collapse .nav > .divider-vertical { 976 | display: none; 977 | } 978 | .nav-collapse .nav .nav-header { 979 | color: #777777; 980 | text-shadow: none; 981 | } 982 | .nav-collapse .nav > li > a, 983 | .nav-collapse .dropdown-menu a { 984 | padding: 9px 15px; 985 | font-weight: bold; 986 | color: #777777; 987 | -webkit-border-radius: 3px; 988 | -moz-border-radius: 3px; 989 | border-radius: 3px; 990 | } 991 | .nav-collapse .btn { 992 | padding: 4px 10px 4px; 993 | font-weight: normal; 994 | -webkit-border-radius: 4px; 995 | -moz-border-radius: 4px; 996 | border-radius: 4px; 997 | } 998 | .nav-collapse .dropdown-menu li + li a { 999 | margin-bottom: 2px; 1000 | } 1001 | .nav-collapse .nav > li > a:hover, 1002 | .nav-collapse .dropdown-menu a:hover { 1003 | background-color: #f2f2f2; 1004 | } 1005 | .navbar-inverse .nav-collapse .nav > li > a, 1006 | .navbar-inverse .nav-collapse .dropdown-menu a { 1007 | color: #999999; 1008 | } 1009 | .navbar-inverse .nav-collapse .nav > li > a:hover, 1010 | .navbar-inverse .nav-collapse .dropdown-menu a:hover { 1011 | background-color: #111111; 1012 | } 1013 | .nav-collapse.in .btn-group { 1014 | padding: 0; 1015 | margin-top: 5px; 1016 | } 1017 | .nav-collapse .dropdown-menu { 1018 | position: static; 1019 | top: auto; 1020 | left: auto; 1021 | display: none; 1022 | float: none; 1023 | max-width: none; 1024 | padding: 0; 1025 | margin: 0 15px; 1026 | background-color: transparent; 1027 | border: none; 1028 | -webkit-border-radius: 0; 1029 | -moz-border-radius: 0; 1030 | border-radius: 0; 1031 | -webkit-box-shadow: none; 1032 | -moz-box-shadow: none; 1033 | box-shadow: none; 1034 | } 1035 | .nav-collapse .open > .dropdown-menu { 1036 | display: block; 1037 | } 1038 | .nav-collapse .dropdown-menu:before, 1039 | .nav-collapse .dropdown-menu:after { 1040 | display: none; 1041 | } 1042 | .nav-collapse .dropdown-menu .divider { 1043 | display: none; 1044 | } 1045 | .nav-collapse .nav > li > .dropdown-menu:before, 1046 | .nav-collapse .nav > li > .dropdown-menu:after { 1047 | display: none; 1048 | } 1049 | .nav-collapse .navbar-form, 1050 | .nav-collapse .navbar-search { 1051 | float: none; 1052 | padding: 10px 15px; 1053 | margin: 10px 0; 1054 | border-top: 1px solid #f2f2f2; 1055 | border-bottom: 1px solid #f2f2f2; 1056 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); 1057 | -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); 1058 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); 1059 | } 1060 | .navbar-inverse .nav-collapse .navbar-form, 1061 | .navbar-inverse .nav-collapse .navbar-search { 1062 | border-top-color: #111111; 1063 | border-bottom-color: #111111; 1064 | } 1065 | .navbar .nav-collapse .nav.pull-right { 1066 | float: none; 1067 | margin-left: 0; 1068 | } 1069 | .nav-collapse, 1070 | .nav-collapse.collapse { 1071 | height: 0; 1072 | overflow: hidden; 1073 | } 1074 | .navbar .btn-navbar { 1075 | display: block; 1076 | } 1077 | .navbar-static .navbar-inner { 1078 | padding-right: 10px; 1079 | padding-left: 10px; 1080 | } 1081 | } 1082 | 1083 | @media (min-width: 980px) { 1084 | .nav-collapse.collapse { 1085 | height: auto !important; 1086 | overflow: visible !important; 1087 | } 1088 | } 1089 | -------------------------------------------------------------------------------- /dist/angles.min.js: -------------------------------------------------------------------------------- 1 | /*! angles 2013-11-25 */ 2 | !function(){var a={}.hasOwnProperty,b=function(b,c){function d(){this.constructor=b}for(var e in c)a.call(c,e)&&(b[e]=c[e]);return d.prototype=c.prototype,b.prototype=new d,b.__super__=c.prototype,b};window.Angles={},function(a,c,d,e){var f,g,h,i,j,k,l,m,n,o;return f=null,a.XMLDocument=function(a){function c(){return g=c.__super__.constructor.apply(this,arguments)}return b(c,a),c.prototype.defaults={name:"untitled",content:""},c.prototype.validate=function(){},c}(d.Model),a.XMLDocumentList=function(c){function d(){return h=d.__super__.constructor.apply(this,arguments)}return b(d,c),d.prototype.model=a.XMLDocument,d}(d.Collection),a.Notification=function(a){function c(){return i=c.__super__.constructor.apply(this,arguments)}return b(c,a),c.prototype.defaults={type:"",info:"",message:"",resource:"",location:{column:-1,row:-1}},c}(d.Model),a.NotificationList=function(c){function d(){return j=d.__super__.constructor.apply(this,arguments)}return b(d,c),d.prototype.model=a.Notification,d}(d.Collection),a.FileSelector=function(d){function e(){return k=e.__super__.constructor.apply(this,arguments)}return b(e,d),e.prototype.initialize=function(){return this.template=c.template($("#file-list-template").html())},e.prototype.render=function(){return this.$el.html(this.template({})),this.collection.each(this.addOne,this),this},e.prototype.addOne=function(b){var c;return c=new a.FileSelectorRow({model:b}),this.$("form").append(c.render().$el)},e}(d.View),a.FileSelectorRow=function(a){function d(){return l=d.__super__.constructor.apply(this,arguments)}return b(d,a),d.prototype.initialize=function(){return this.template=c.template($("#file-item-template").html()),this.listenTo(this.model,"change",this.render),this.listenTo(this.model,"destroy",this.remove)},d.prototype.render=function(){return this.$el.html(this.template(this.model.toJSON())),this},d}(d.View),a.NotificationTable=function(d){function e(){return m=e.__super__.constructor.apply(this,arguments)}return b(e,d),e.prototype.initialize=function(){return this.template=c.template($("#notification-list-template").html())},e.prototype.render=function(){return this.$el.html(this.template({})),this.listenTo(this.collection,"add",this.addOne),this},e.prototype.addOne=function(b){var c;return c=new a.NotificationRow({model:b}),this.$(".notifications").append(c.render().$el)},e}(d.View),a.NotificationRow=function(a){function d(){return n=d.__super__.constructor.apply(this,arguments)}return b(d,a),d.prototype.initialize=function(){return this.template=c.template($("#notification-template").html()),this.listenTo(this.model,"change",this.render),this.listenTo(this.model,"destroy",this.remove)},d.prototype.render=function(){return this.$el.html(this.template(this.model.toJSON())),this},d}(d.View),a.ACEEditorView=function(a){function f(){return o=f.__super__.constructor.apply(this,arguments)}return b(f,a),f.prototype.tagName="div",f.prototype.className="ace-editor",f.prototype.initialize=function(){var a,b,e=this;return a=[],b=this.options.dispatcher||c.clone(d.Events),this.dispatcher=b,b.on("editor:reload",function(){return e.clearAnnotations(),e.setContent()}),b.on("document:save",function(){return e.saveModel()}),b.on("validation:start",function(){return a=[],e.dispatcher.trigger("notification:clear")}),b.on("validation:error",function(b){var c;return a.push(b),c={type:"validation",info:b.type,message:b.text,location:{row:b.row,column:b.column}},e.dispatcher.trigger("notification:push",c)}),b.on("validation:end",function(){var b;return b=e.$editor.getSelection(),e.clearAnnotations(),e.$editor.focus(),a.length>0&&(e.$editor.gotoLine(a[0].row+1,a[0].column,!0),b.selectWordLeft(),b.selectWordLeft()),e.$editor.session.setAnnotations(a)}),b.on("document:switch",function(a){return e.setModel(a)})},f.prototype.render=function(){var a=this;return this.$editor=e.edit(this.el),this.$editor.getSession().on("change",function(b){return a.dispatcher.trigger("editor:change",b)}),this.$editor.getSession().setMode("ace/mode/xml"),e.config.loadModule("ext/angles",function(){var b;return a.$editor.setOptions({enableODDAutocompletion:!0}),b={getCompletions:function(b,c,d,e,f){var g,h,i,j,k,l,m,n;if(null==a.$context)return 0;if(j=a.$context,l=function(a,c){var d,e,f,g,h,i,j,k;return j=[],e=[],d=[],h=!1,g=!1,f="",i=b.getSession().getLength(),k=function(a,c){var f,l,m,n,o,p,q,r,s;if(!(a>i)){for(f=0,q=b.getSession().getTokens(a),m=null,r=0,s=q.length;s>r;r++)if(p=q[r],f+=p.value.length,l=function(){switch(!1){case 0!==j.length:return!0;case j.length!==e.length:return j.pop(),e.pop(),!1;case j[j.length-1]!==e[e.length-1]:return j.pop(),e.pop(),!1;default:return!1}},"meta.tag.tag-name"===p.type&&(n=p.value),f>c)switch(!1){case!("meta.tag"===p.type&&"<"===p.value):h=!0;break;case!("meta.tag.r"===p.type&&">"===p.value&&0===j.length):return n;case!("meta.tag"===p.type&&""===p.value):if(h=!1,g=!1,o=j[j.length-1],null==o&&(o=n),e.push(o),l())return o;break;case!("meta.tag.tag-name"===p.type&&h):if(d.push("<"+p.value+">"),j.push(p.value),h=!1,l())return p.value;break;case!("meta.tag.tag-name"===p.type&&g):if(d.push(""),e.push(p.value),g=!1,l())return p.value}return k(a+1,0)}},k(a,c)},d=b.getCursorPosition(),k=l(d.row,d.column),i=[],h=j.getChildrenOf(k),null!=h)for(m=0,n=h.length;n>m;m++)g=h[m],i.push({caption:g.ident,snippet:""+g.ident+">",meta:"element"});else i.push({caption:"unknown parent",snippet:"",meta:"element"});return i.length>0?f(null,i):void 0}},a.$editor.completers=[b],e.config.on("desc",function(b){return a.dispatcher.trigger("editor:context",b.ident)}),e.config.on("desc:clear",function(){return a.dispatcher.trigger("notification:clear")})}),this},f.prototype.setContent=function(){return this.$editor.setValue(this.model.get("content"))},f.prototype.getContent=function(){return this.$editor.getValue()},f.prototype.getDocument=function(){var a=this;return{getValue:function(){return a.$editor.getValue()},getLength:function(){return a.$editor.session.getDocument().getLength()},getLine:function(b){return a.$editor.session.getDocument().getLine(b)}}},f.prototype.saveModel=function(){var a=this;return this.model.set("content",this.getContent()),this.model.save({success:function(){return a.dispatcher.trigger("editor:reload")},error:function(){return a.dispatcher.trigger("editor:error","Unable to change document")}})},f.prototype.setModel=function(a){return this.model=a,this.dispatcher.trigger("editor:reload")},f.prototype.clearAnnotations=function(){return this.$editor.session.clearAnnotations()},f.prototype.setMode=function(a){return this.$editor.getSession().setMode(a)},f}(d.View)}(window.Angles,_,Backbone,ace)}.call(this),function(){"undefined"!=typeof define&&null!==define&&(define("ext/angles",["require","exports","module","ace/snippets","ace/autocomplete","ace/config","ace/autocomplete/text_completer","ace/editor"],function(a,b){var c,d,e,f,g,h,i,j,k,l;return k=a("ace/snippets").snippetManager,c=a("ace/autocomplete").Autocomplete,f=a("ace/config"),l=a("ace/autocomplete/text_completer"),h={getCompletions:function(a,b,c,d,e){var f;return f=b.$mode.$keywordList||[],f=f.filter(function(a){return 0===a.lastIndexOf(d,0)}),e(null,f.map(function(a){return{name:a,value:a,score:0,meta:"keyword"}}))}},j={getCompletions:function(a,b,c,d,e){var f,g,h;return g=k.$getScope(a),h=k.snippetMap,f=[],[g,"_"].forEach(function(a){var b,c,e,g,i,j;for(e=h[a]||[],j=[],b=g=i=e.length-1;0>=i?0>=g:g>=0;b=0>=i?++g:--g)c=e[b],c.tabTrigger&&0===c.tabTrigger.indexOf(d)?j.push(f.push({caption:c.tabTrigger,snippet:c.content,meta:"snippet"})):j.push(void 0);return j}),e(null,f)}},e=[j,l,h],b.addCompleter=function(a){return e.push(a)},g={name:"expandSnippet",exec:function(a){var b;return b=k.expandWithTab(a),b?void 0:a.execCommand("indent")},bindKey:"tab"},i=function(a,b){var c,d,e;return d=b.session.$mode,c=d.$id,k.files||(k.files={}),c&&!k.files[c]?(e=c.replace("mode","snippets"),f.loadModule(e,function(a){return a?(k.files[c]=a,a.snippets=k.parseSnippetFile(a.snippetText),k.register(a.snippets,a.scope)):void 0})):void 0},d=a("ace/editor").Editor,a("ace/config").defineOptions(d.prototype,"editor",{enableBasicAutocompletion:{set:function(a){return a?(this.completers=e,this.commands.addCommand(c.startCommand)):this.commands.removeCommand(c.startCommand)},value:!1},enableODDAutocompletion:{set:function(a){return a?(this.completers=e,this.commands.addCommand(c.startCommand)):this.commands.removeCommand(c.startCommand)},value:!1},enableSnippets:{set:function(a){return a?(this.commands.addCommand(g),this.on("changeMode",i),i(null,this)):(this.commands.removeCommand(g),this.off("changeMode",i))},value:!1}})}),define("ace/snippets",["require","exports","module","ace/lib/lang","ace/range","ace/keyboard/hash_handler","ace/tokenizer","ace/lib/dom"],function(a,b){var c,d,f,g,h,i,j,k,l;return j=a("./lib/lang"),d=a("ace/range").Range,c=a("./keyboard/hash_handler").HashHandler,h=a("./tokenizer").Tokenizer,i=d.comparePoints,f=function(){function a(){this.snippetMap={},this.snippetNameMap={},this.variables={}}return a.prototype.getTokenizer=function(){var b,c;return b=function(a,b,c){return a=a.substr(1),/^\d+$/.test(a)&&!c.inFormatString?[{tabstopId:parseInt(a,10)}]:[{text:a}]},c=function(a){return"(?:[^\\\\"+a+"]|\\\\.)"},a.$tokenizer=new h({start:[{regex:/:/,onMatch:function(a,b,c){return c.length&&c[0].expectIf?(c[0].expectIf=!1,c[0].elseBranch=c[0],[c[0]]):":"}},{regex:/\\./,onMatch:function(a,b,c){var d;switch(d=a[1],!1){case!("}"===d&&c.length):a=d;break;case-1==="`$\\".indexOf(d):a=d;break;case!c.inFormatString:switch(!1){case"n"!==d:a="\n";break;case"t"!==d:a="\n";break;case-1==="ulULE".indexOf(d):a={changeCase:d,local:d>"a"}}}return[a]}},{regex:/\}/,onMatch:function(a,b,c){return[c.length?c.shift():a]}},{regex:/\$(?:\d+|\w+)/,onMatch:b},{regex:/\$\{[\dA-Z_a-z]+/,onMatch:function(a,c,d){var e;return e=b(a.substr(1),c,d),d.unshift(e[0]),e},next:"snippetVar"},{regex:/\n/,token:"newline",merge:!1}],snippetVar:[{regex:"\\|"+c("\\|")+"*\\|",onMatch:function(a,b,c){return c[0].choices=a.slice(1,-1).split(",")},next:"start"},{regex:"/("+c("/")+"+)/(?:("+c("/")+"*)/)(\\w*):?",onMatch:function(a,b,c){var d;return d=c[0],d.fmtString=a,a=this.splitRegex.exec(a),d.guard=a[1],d.fmt=a[2],d.flag=a[3],""},next:"start"},{regex:"`"+c("`")+"*`",onMatch:function(a,b,c){return c[0].code=a.splice(1,-1),""},next:"start"},{regex:"\\?",onMatch:function(a,b,c){return c[0]?c[0].expectIf=!0:void 0},next:"start"},{regex:"([^:}\\\\]|\\\\.)*:?",token:"",next:"start"}],formatString:[{regex:"/("+c("/")+"+)/",token:"regex"},{regex:"",onMatch:function(a,b,c){return c.inFormatString=!0},next:"start"}]}),a.prototype.getTokenizer=function(){return a.$tokenizer},a.$tokenizer},a.prototype.tokenizeTmSnippet=function(a,b){return this.getTokenizer().getLineTokens(a,b).tokens.map(function(a){return a.value||a})},a.prototype.$getDefaultValue=function(a,b){var c,d,f;switch(!1){case!/^[A-Z]\d+$/.test(b):return c=b.substr(1),(this.variables[b[0]+"__"]||{})[c];case!/^\d+$/.test(b):return(this.variables.__||{})[b];default:if(b=b.replace(/^TM_/,""),!a)return;switch(f=a.session,b){case"CURRENT_WORD":return d=f.getWordRange();case"SELECTION":case"SELECTED_TEXT":return f.getTextRange(d);case"CURRENT_LINE":return f.getLine(e.getCursorPosition().row);case"LINE_INDEX":return e.getCursorPosition().column;case"LINE_NUMBER":return e.getCursorPosition().row+1;case"SOFT_TABS":return f.getUseSoftTabs()?"YES":"NO";case"TAB_SIZE":return f.getTabSize();case"FILENAME":case"FILEPATH":return"ace.ajax.org";case"FULLNAME":return"Ace"}}},a.prototype.getVariableValue=function(a,b){return this.variables.hasOwnProperty(b)?this.variables[b](a,b)||"":this.$getDefaultValue(a,b)||""},a.prototype.tmStrFormat=function(a,b,c){var d,e,f,g,h=this;return d=b.flag||"",g=b.guard,g=new RegExp(g,d.replace(/[^gi]/,"")),e=this.tokenizeTmSnippet(b.fmt,"formatString"),f=a.replace(g,function(){var a,d,f,g,i,j;for(h.variables.__=arguments,a=h.resolveVariables(e,c),d="E",f=i=0,j=a.length;j>=0?j>i:i>j;f=j>=0?++i:--i)switch(b=a[f],!1){case"object"!=typeof b:a[f]="",b.changeCase&&b.local?(g=a[f+1],g&&"string"==typeof g&&(a[f]="u"===b.changeCase?g[0].toUpperCase():g[0].toLowerCase(),a[f+1]=g.substr(1))):b.changeCase&&(d=b.changeCase);break;case"U"!==d:a[f]=b.toUpperCase();break;case"L"!==d:a[f]=b.toLowerCase()}return a.join("")}),this.variables.__=null,f},a.prototype.resolveVariables=function(a,b){var c,d,e,f,g,h,i;for(f=[],d=function(b){var c,d;return d=a.indexOf(b,c+1),-1!==d?c=d:void 0},e=h=0,i=a.length;i>=0?i>h:h>i;e=i>=0?++h:--h)switch(c=a[e],!1){case"string"!=typeof c:f.push(c);break;case"object"==typeof c:continue;case!c.skip:d(c);break;case!(c.processed=g?0>=f:f>=0;d=0>=g?++f:--f)if(e=a[d],!(e.startRe&&!e.startRe.test(b)||e.endRe&&!e.endRe.test(c)||!e.startRe&&!e.endRe))return e.matchBefore=e.startRe?e.startRe.exec(b):[""],e.matchAfter=e.endRe?e.endRe.exec(c):[""],e.replaceBefore=e.triggerRe?e.triggerRe.exec(b)[0]:"",e.replaceAfter=e.endTriggerRe?e.endTriggerRe.exec(c)[0]:"",e},a.prototype.register=function(a,b){var c,d,e,f,g,h;return f=this.snippetMap,g=this.snippetNameMap,e=this,h=function(a){return a&&!/^\^?\(.*\)\$?$|^\\b$/.test(a)&&(a="(?:"+a+")"),a||""},d=function(a,b,c){return a=h(a),b=h(b),c?(a=b+a,a&&"$"!==a[a.length-1]&&(a+="$")):(a+=b,a&&"^"!==a[0]&&(a="^"+a)),new RegExp(a)},c=function(a){var c,h;return a.scope||(a.scope=b||"_"),b=a.scope,f[b]||(f[b]=[],g[b]={}),c=g[b],a.name&&(h=c[a.name],h&&e.unregister(h),c[a.name]=a),f[b].push(a),a.tabTrigger&&!a.trigger&&(!a.guard&&/^\w/.test(a.tabTrigger)&&(a.guard="\\b"),a.trigger=j.escapeRegExp(a.tabTrigger)),a.startRe=d(a.trigger,a.guard,!0),a.triggerRe=new RegExp(a.trigger,"",!0),a.endRe=d(a.endTrigger,a.endGuard,!0),a.endTriggerRe=new RegExp(a.endTrigger,"",!0)},a.content?c(a):Array.isArray(a)?a.forEach(c):void 0},a.prototype.unregister=function(a,b){var c,d,e;return d=this.snippetMap,e=this.snippetNameMap,c=function(a){var c,f,g;return g=e[a.scope||b],g&&g[a.name]&&(delete g[a.name],f=d[a.scope||b],c=null!=f?f.indexOf(a):void 0,c>=0)?f.splice(c,1):void 0},a.content?c(a):Array.isArray(a)?a.forEach(c):void 0},a.prototype.parseSnippetFile=function(a){var b,c,d,e,f,g,h,i;for(a=a.replace(/\r/,""),e=[],h={},g=/^#.*|^({[\s\S]*})\s*$|^(\S+) (.*)$|^((?:\n*\t.*)+)/gm;f=g.exec(a);){if(f[1])try{h=JSON.parse(f[1]),e.push(h)}catch(j){b=j}if(f[4])h.content=f[4].replace(/^\t/gm,""),e.push(h),h={};else switch(d=f[2],i=f[3],d){case"regex":c=/\/((?:[^\/\\]|\\.)*)|$/g,h.guard=c.exec(i)[1],h.trigger=c.exec(i)[1],h.endTrigger=c.exec(i)[1],h.endGuard=c.exec(i)[1];break;case"snippet":h.tabTrigger=i.match(/^\S*/)[0],h.name||(h.name=i);break;default:h[d]=i}}return e},a.prototype.getSnippetByName=function(a,b){var c,d;return c=b&&this.$getScope(b),d=this.snippetNameMap,[c,"_"].some(function(b){var c,e;return e=d[b],e&&(c=e[a]),!!c}),snippet},a}(),g=function(){function a(a){a.tabstopManager?a.tabstopManager:(a.tabstopManager=this,this.$onChange=this.onChange.bind(this),this.$onChangeSelection=j.delayedCall(this.onChangeSelection.bind(this)).schedule,this.$onChangeSession=this.onChangeSession.bind(this),this.$onAfterExec=this.onAfterExec.bind(this),this.attach(a)),this.keyboardHandler=new c,this.keyboardHandler.bindKeys({Tab:function(a){return a.tabstopManager.tabNext(1)},"Shift-Tab":function(a){return a.tabstopManager.tabNext(-1)},Esc:function(a){return a.tabstopManager.detach()},Return:function(){return!1}})}return a.prototype.attach=function(a){return this.index=-1,this.ranges=[],this.tabstops=[],this.selectedTabstop=null,this.editor=a,this.editor.on("change",this.$onChange),this.editor.on("changeSelection",this.$onChangeSelection),this.editor.on("changeSession",this.$onChangeSession),this.editor.commands.on("afterExec",this.$onAfterExec),this.editor.keyBinding.addKeyboardHandler(this.keyboardHandler)},a.prototype.detach=function(){return this.tabstops.forEach(this.removeTabstopMarkers,this),this.ranges=null,this.tabstops=null,this.selectedTabstop=null,this.editor.removeListener("change",this.$onChange),this.editor.removeListener("changeSelection",this.$onChangeSelection),this.editor.removeListener("changeSession",this.$onChangeSession),this.editor.commands.removeListener("afterExec",this.$onAfterExec),this.editor.keyBinding.removeKeyboardHandler(this.keyboardHandler),this.editor.tabstopManager=null,this.editor=null},a.prototype.onChange=function(a){var b,c,d,e,f,g,h,j,k,l,m,n,o,p,q;if(b=a.data.range,h="r"===a.data.action[0],m=b.start,e=b.end,n=m.row,f=e.row,j=f-n,d=e.column-m.column,h&&(j=-j,d=-d),!this.$inChange&&h&&(o=this.selectedTabstop,c=!o.some(function(a){return i(a.start,m)<=0&&i(a.end,e)>=0})))return this.detach();for(l=this.ranges,g=p=0,q=l.length;q>=0?q>p:p>q;g=q>=0?++p:--p)k=l[g],k.end.row0?(this.removeRange(k),g--):(k.start.row===n&&k.start.column>m.column&&(k.start.column+=d),k.end.row===n&&k.end.column>=m.column&&(k.end.column+=d),k.start.row>=n&&(k.start.row+=j),k.end.row>=n&&(k.end.row+=j),i(k.start,k.end)>0&&this.removeRange(k)));return l.length?void 0:this.detach()},a.prototype.updateLinkedFields=function(){var a,c,d,e,f,g,h,i;if(g=this.selectedTabstop,g.hasLinkedRanges){for(this.$inChange=!0,e=this.editor.session,f=e.getTextRange(g.firstNonLinked),c=h=i=g.length-1;0>=i?0>h:h>0;c=0>=i?++h:--h)d=g[c],d.linked&&(a=b.snippetManager.tmStrFormat(f,d.original),e.replace(d,a));return this.$inChange=!1}},a.prototype.onAfterExec=function(a){return a.command&&!a.command.readOnly?this.updateLinkedFields():void 0},a.prototype.onChangeSelection=function(){var a,b,c,d,e,f,g,h;if(this.editor){for(f=this.editor.selection.lead,a=this.editor.selection.anchor,e=this.editor.selection.isEmpty(),d=g=h=this.ranges.length-1;0>=h?0>=g:g>=0;d=0>=h?++g:--g)if(!this.ranges[d].linked&&(c=this.ranges[d].contains(f.row,f.column),b=e||this.ranges[d].contains(a.row,a.column),c&&b))return;return this.detach()}},a.prototype.onChangeSession=function(){return this.detach()},a.prototype.tabNext=function(a){var b,c;return c=this.tabstops.length-1,b=this.index+(a||1),b=Math.min(Math.max(b,0),c),this.selectTabstop(b),b===c?this.detach():void 0},a.prototype.selectTabstop=function(a){var b,c,d,e,f;if(d=this.tabstops[this.index],d&&this.addTabstopMarkers(d),this.index=a,d=this.tabstops[this.index],null!=d?d.length:void 0){if(this.selectedTabstop=d,this.editor.inVirtualSelectionMode)this.editor.selection.setRange(d.firstNonLinked);else for(c=this.editor.multiSelect,d.hasLinkedRanges&&c.toSingleRange(d.firstNonLinked.clone()),b=e=f=d.length-1;0>=f?0>=e:e>=0;b=0>=f?++e:--e)d.hasLinkedRanges&&d[b].linked||c.addRange(d[b].clone(),!0);return this.editor.keyBinding.addKeyboardHandler(this.keyboardHandler)}},a.prototype.addTabstops=function(a,b,c){var e,f,g,h,i,j=this;return a[0]||(h=d.fromPoints(c,c),l(h.start,b),l(h.end,b),a[0]=[h],a[0].index=0),g=this.index,e=[g,0],i=this.ranges,f=this.editor,a.forEach(function(a){var c,f,l;for(g=f=l=a.length-1;0>=l?0>f:f>0;g=0>=l?++f:--f)h=a[g],c=d.fromPoints(h.start,h.end||h.start),k(c.start,b),k(c.end,b),c.original=h,c.tabstop=a,i.push(c),a[g]=c,h.fmtString?(c.linked=!0,a.hasLinkedRanges=!0):a.firstNonLinked||(a.firstNonLinked=c);return a.firstNonLinked||(a.hasLinkedRanges=!1),e.push(a),j.addTabstopMarkers(a)}),e.push(e.splice(2,1)[0]),this.tabstops.splice.apply(this.tabstops,e)},a.prototype.addTabstopMarkers=function(a){var b;return b=this.editor.session,a.forEach(function(a){return a.markerId?void 0:a.markerId=b.addMarker(a,"ace_snippet-marker","text")})},a.prototype.removeTabstopMarkers=function(a){var b;return b=this.editor.session,a.forEach(function(a){return b.removeMarker(a.markerId),a.markerId=null})},a.prototype.removeRange=function(a){var b;return b=a.tabstop.indexOf(a),a.tabstop.splice(b,1),b=this.ranges.indexOf(a),this.ranges.splice(b,1),this.editor.session.removeMarker(a.markerId)},a}(),k=function(a,b){return 0===a.row&&(a.column+=b.column),a.row+=b.row},l=function(a,b){return a.row===b.row&&(a.column-=b.column),a.row-=b.row},a("./lib/dom").importCssString(".ace_snippet-marker {\n -moz-box-sizing: border-box;\n box-sizing: border-box;\n background: rgba(194, 193, 208, 0.09);\n border: 1px dotted rgba(211, 208, 235, 0.62);\n position: absolute;\n}"),b.snippetManager=new f,b}),define("ace/autocomplete",["require","exports","module","ace/keyboard/hash_handler","ace/autocomplete/popup","ace/autocomplete/util","ace/lib/event","ace/lib/lang","ace/snippets"],function(a,b){var c,d,e,f,g,h,i,j;return f=a("./keyboard/hash_handler").HashHandler,c=a("./autocomplete/popup").AcePopup,j=a("./autocomplete/util"),g=a("./lib/event"),h=a("./lib/lang"),i=a("./snippets").snippetManager,d=function(){function a(){var a=this;this.keyboardHandler=new f,this.keyboardHandler.bindKeys(this.commands),this.blurListener=this.blurListener.bind(this),this.changeListener=this.changeListener.bind(this),this.mousedownListener=this.mousedownListener.bind(this),this.mousewheelListener=this.mousewheelListener.bind(this),this.changeTimer=h.delayedCall(function(){return a.updateCompletions(!0)})}return a.prototype.$init=function(){var a=this;return this.popup=c(document.body||document.documentElement),this.popup.on("click",function(b){return a.insertMatch(),b.stop()})},a.prototype.openPopup=function(a,b){var c,d,e,f;return this.popup||this.$init(),ace.config._dispatchEvent("desc",{ident:this.completions.filtered[0].caption}),this.popup.setData(this.completions.filtered),f=a.renderer,b||(c=f.layerConfig.lineHeight,d=f.$cursorLayer.getPixelPosition(null,!0),e=a.container.getBoundingClientRect(),d.top+=e.top-f.layerConfig.offset,d.left+=e.left,d.left+=f.$gutterLayer.gutterWidth,this.popup.show(d,c)),f.updateText()},a.prototype.detach=function(){var a;return this.editor.keyBinding.removeKeyboardHandler(this.keyboardHandler),this.editor.removeEventListener("changeSelection",this.changeListener),this.editor.removeEventListener("blur",this.changeListener),this.editor.removeEventListener("mousedown",this.changeListener),this.changeTimer.cancel(),null!=(a=this.popup)&&a.hide(),this.activated=!1},a.prototype.changeListener=function(){return this.activated?this.changeTimer.schedule():this.detach()},a.prototype.blurListener=function(){return document.activeElement!==this.editor.textInput.getElement()?this.detach():void 0},a.prototype.mousedownListener=function(){return this.detach()},a.prototype.mousewheelListener=function(){return this.detach()},a.prototype.goTo=function(a){var b,c;switch(c=this.popup.getRow(),b=this.popup.session.getLength()-1,a){case"up":c=0>=c?b:c-1;break;case"down":c=c>=b?0:c+1;break;case"start":c=0;break;case"end":c=b}return this.popup.setRow(c)},a.prototype.insertMatch=function(a){var b,c;return this.detach(),null==a&&(a=this.popup.getData(this.popup.getRow())),a?(null!=(c=a.completer)?c.insertMatch:void 0)?a.completer.insertMatch(this.editor):(this.completions.filterText&&(b=this.editor.selection.getRange(),b.start.column-=this.completions.filterText.length,this.editor.session.remove(b)),a.snippet?i.insertSnippet(this.editor,a.snippet):this.editor.insert(a.value||a)):!1},a.prototype.commands={Up:function(a){return a.completer.goTo("up")},Down:function(a){return a.completer.goTo("down")},"Ctrl-Up|Ctrl-Home":function(a){return a.completer.goTo("start")},"Ctrl-Down|Ctrl-End":function(a){return a.completer.goTo("end")},Esc:function(a){return a.completer.detach()},Space:function(a){return a.completer.detach(),a.insert(" ")},Return:function(a){return a.completer.insertMatch()},"Shift-Return":function(a){return a.completer.insertMatch(!0)},Tab:function(a){return a.completer.insertMatch()},PageUp:function(a){return a.completer.popup.gotoPageDown()},PageDown:function(a){return a.completer.popup.gotoPageUp()}},a.prototype.gatherCompletions=function(a,b){var c,d,e,f,g;return g=a.getSession(),e=a.getCursorPosition(),c=g.getLine(e.row),f=j.retrievePrecedingIdentifier(c,e.column),d=[],j.parForEach(a.completers,function(b,c){return b.getCompletions(a,g,e,f,function(a,b){return a||(d=d.concat(b)),c()})},function(){return d.sort(function(a,b){return b.score-a.score}),b(null,{prefix:f,matches:d})}),!0},a.prototype.showPopup=function(a){return this.editor&&this.detach(),this.activated=!0,this.editor=a,a.completer!==this&&(a.completer&&a.completer.detach(),a.completer=this),a.keyBinding.addKeyboardHandler(this.keyboardHandler),a.on("blur",this.blurListener),a.on("mousedown",this.mousedownListener),this.updateCompletions(),this.changeTimer.cancel()},a.prototype.updateCompletions=function(a){var b=this;return this.gatherCompletions(this.editor,function(c,d){var f;return f=null!=d?d.matches:void 0,(null!=f?f.length:void 0)?(b.completions=new e(f),b.completions.setFilter(d.prefix),b.openPopup(b.editor,a)):b.detach()})},a.prototype.cancelContextMenu=function(){var a,b=this;return a=function(c){return b.editor.off("nativecontextmenu",a),(null!=c?c.domEvent:void 0)?g.stopEvent(c.domEvent):void 0},setTimeout(a,10),this.editor.on("nativecontextmenu",a)},a}(),d.startCommand={name:"startAutocomplete",exec:function(a){return a.completer||(a.completer=new d),a.completer.showPopup(a),a.completer.cancelContextMenu(),a.getSession().insert(a.getCursorPosition(),"<")},bindKey:"<"},e=function(){function a(a){this.all=a,this.filtered=a.concat(),this.filterText=""}return a.prototype.setFilter=function(a){return this.filterText=a},a}(),b.Autocomplete=d,b.FilteredList=e,b}),define("ace/autocomplete/popup",["require","exports","module","ace/edit_session","ace/virtual_renderer","ace/editor","ace/range","ace/lib/event","ace/lib/lang","ace/lib/dom"],function(a,b){var c,d,e,f,g,h,i,j,k;return e=a("ace/edit_session").EditSession,h=a("ace/virtual_renderer").VirtualRenderer,f=a("ace/editor").Editor,g=a("ace/range").Range,j=a("ace/lib/event"),k=a("ace/lib/lang"),i=a("ace/lib/dom"),c=function(a){var b,c;return c=new h(a),c.$maxLines=4,b=new f(c),b.setHighlightActiveLine(!1),b.setShowPrintMargin(!1),b.renderer.setShowGutter(!1),b.renderer.setHighlightGutterLine(!1),b.$mouseHandler.$focusWaitTimout=0,b},d=function(a){var b,d,e,f,h,l;return d=i.createElement("div"),l=new c(d),a&&a.appendChild(d),d.style.display="none",l.renderer.content.style.cursor="default",l.renderer.setStyle("ace_autocomplete"),h=function(){},l.focus=h,l.$isFocused=!0,l.renderer.$cursorLayer.restartTimer=h,l.renderer.$cursorLayer.element.style.opacity=0,l.renderer.$maxLines=8,l.renderer.$keepTextAreaAtCursor=!1,l.setHighlightActiveLine(!0),l.session.highlight(""),l.session.$searchHighlight.clazz="ace_highlight-marker",l.on("mousedown",function(a){var b;return b=a.getDocumentPosition(),l.moveCursorToPosition(b),l.selection.clearSelection(),a.stop()}),f=new g(-1,0,-1,1/0),f.id=l.session.addMarker(f,"ace_line-hover","fullLine"),l.on("mousemove",function(a){var b;return b=a.getDocumentPosition().row,f.start.row=f.end.row=b,l.session._emit("changeBackMarker")}),e=function(){return f.start.row=f.end.row=-1,l.session._emit("changeBackMarker")},j.addListener(l.container,"mouseout",e),l.on("hide",e),l.on("changeSelection",e),l.on("mousewheel",function(a){return setTimeout(function(){return l._signal("mousemove",a)})}),l.session.doc.getLength=function(){return l.data.length},l.session.doc.getLine=function(a){var b;return b=l.data[a],"string"==typeof b?b:b&&b.value||""},b=l.session.bgTokenizer,b.$tokenizeRow=function(a){var b,c,d;return b=l.data[a],d=[],b?("string"==typeof b&&(b={value:b}),b.caption||(b.caption=b.value),d.push({type:b.className||"",value:b.caption}),b.meta&&(c=l.renderer.$size.scrollerWidth/l.renderer.layerConfig.characterWidth,b.meta.length+b.caption.lengthwindow.innerHeight/2+b?(d.style.top="",d.style.bottom=window.innerHeight-a.top+"px"):(a.top+=b,d.style.top=a.top+"px",d.style.bottom=""),d.style.left=a.left+"px",d.style.display="",l.renderer.$textLayer.checkForSizeChanges(),l._signal("show")},l},i.importCssString(".ace_autocomplete.ace-tm .ace_marker-layer .ace_active-line {\n background-color: #abbffe;\n}\n.ace_autocomplete.ace-tm .ace_line-hover {\n border: 1px solid #abbffe;\n position: absolute;\n background: rgba(233,233,253,0.4);\n z-index: 2;\n margin-top: -1px;\n}\n.ace_rightAlignedText {\n color: gray;\n display: inline-block;\n position: absolute;\n right: 4px;\n text-align: right;\n z-index: -1;\n}\n.ace_autocomplete {\n width: 200px;\n height: 120px;\n z-index: 200000;\n background: #f8f8f8;\n border: 1px lightgray solid;\n position: fixed;\n box-shadow: 2px 3px 5px rgba(0,0,0,.2);\n}"),b.AcePopup=d,b}),define("ace/autocomplete/util",["require","exports","module"],function(a,b){var c;return b.parForEach=function(a,b,c){var d,e,f,g,h,i;for(e=0,d=a.length,0===d&&c(),i=[],g=0,h=a.length;h>g;g++)f=a[g],i.push(b(f,function(a,b){return e++,e===d?c(a,b):void 0}));return i},c=/[a-zA-Z_0-9\$-]/,b.retrievePrecedingIdentifier=function(a,b,d){var e,f,g,h;for(d=d||c,e=[],f=g=h=b-1;(0>=h?0>=g:g>=0)&&d.test(a[f]);f=0>=h?++g:--g)e.push(a[f]); 3 | return e.reverse().join("")},b.retrieveFollowingIdentifier=function(a,b,d){var e,f,g,h;for(d=d||c,e=[],f=g=b,h=a.length;(h>=b?h>g:g>h)&&d.test(a[f]);f=h>=b?++g:--g)e.push(a[f]);return e},b}),define("ace/autocomplete/text_completer",["require","exports","module","ace/range"],function(a,b){var c,d,e,f,g;return c=a("ace/range").Range,f=/[^a-zA-Z_0-9\$\-]+/,e=function(a,b){var d;return d=a.getTextRange(c.fromPoints({row:0,column:0},b)),d.split(f).length-1},d=function(a,b){var c,d,e,f;for(d=[],c=e=0,f=b.length;f>=0?f>e:e>f;c=f>=0?++e:--e)0===b[c].lastIndexOf(a,0)&&d.push(b[c]);return d},g=function(a,b){var c,d,g,h;return d=e(a,b),h=a.getValue().split(f),g=Object.create(null),c=h[d],h.forEach(function(a,b){var e,f;return a&&a!==c?(e=Math.abs(d-b),f=h.length-e,g[a]=g[a]?Math.max(f,g[a]):f):void 0}),g},b.getCompletions=function(a,b,c,e,f){var h,i;return i=g(b,c,e),h=d(e,Object.keys(i)),f(null,h.map(function(a){return{name:a,value:a,score:i[a],meta:"local"}}))},b}))}.call(this),function(){Angles.ContextHelp=function(){function a(a){var b;b=this.dispatcher=a.dispatcher,this.$odd={},this.$angles=a.anglesView}return a.prototype.setODD=function(a){return this.$odd=a},a.prototype.getODDfor=function(a){var b,c,d,e;for(b=this.$odd.members,d=0,e=b.length;e>d;d++)if(c=b[d],c.ident===a)return c;return null},a.prototype.getDescOf=function(a){var b;return null!=(b=this.getODDfor(a))?b.desc:void 0},a.prototype.getChildrenOf=function(a){var b;return null!=(b=this.getODDfor(a))?b.children:void 0},a}()}.call(this),function(){var a=function(a,b){return function(){return a.apply(b,arguments)}};Angles.FileUploader=function(){function b(b){this._handleFileSelect=a(this._handleFileSelect,this);var c;c=this.dispatcher=b.dispatcher,this.$angles=b.anglesView,this.storedFiles=b.storedFiles}return b.prototype._handleFileSelect=function(a){var b,c,d=this;return b=a.target.files[0],c=new FileReader,c.onload=function(a){var c,e;return e=d.storedFiles.find(function(a){return a.get("name")===b.name}),null!=e&&e.destroy(),c=d.storedFiles.create({name:b.name,content:a.target.result}),d.dispatcher.trigger("document:switch",c)},c.readAsText(b,"UTF-8")},b.prototype.bind=function(a){return $(a).change(this._handleFileSelect)},b}()}.call(this),function(){Angles.NotificationCenter=function(){function a(a){var b,c=this;b=this.dispatcher=a.dispatcher,this.$angles=a.anglesView,this.$notifications=new Angles.NotificationList,b.on("notification:push",function(a){return c.push(a)}),b.on("notification:clear",function(){return c.clear()})}return a.prototype.push=function(a){return this.$notifications.add(a)},a.prototype.clear=function(){for(var a;a=this.$notifications.first();)a.destroy();return null},a}()}.call(this),function(){Angles.Validator=function(){function a(a){var b;b=this.dispatcher=a.dispatcher,this.$schema={},this.$errors=[],this.$angles=a.anglesView}return a.prototype.displayErrors=function(){var a,b,c,d;for(d=this.errors(),b=0,c=d.length;c>b;b++)a=d[b],this.dispatcher.trigger("validation:error",a);return this.endValidation()},a.prototype.addError=function(a){return this.$errors.push(a)},a.prototype.clearErrors=function(){return this.$errors=[]},a.prototype.endValidation=function(){return this.dispatcher.trigger("validation:end")},a.prototype.setSchema=function(a){return this.$schema=a,this.dispatcher.trigger("validation")},a.prototype.errors=function(){return this.$errors},a.prototype.hasErrors=function(){return 0!==this.$errors.length},a}()}.call(this),function(){var a={}.hasOwnProperty,b=function(b,c){function d(){this.constructor=b}for(var e in c)a.call(c,e)&&(b[e]=c[e]);return d.prototype=c.prototype,b.prototype=new d,b.__super__=c.prototype,b},c=[].indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(b in this&&this[b]===a)return b;return-1};Angles.SAXParser=function(){function a(a){this.reset=function(){var b,c=this;return b=sax.parser(!0,{xmlns:!0,noscript:!0,position:!0}),b.onerror=null!=a.error?function(d){return"Text data outside of root node."!==d.message.split(/\n/)[0]&&a.error.call(c,d),b.resume()}:function(a){return"Text data outside of root node."!==a.message.split(/\n/)[0]&&c.validationError(a.message.split(/\n/)[0]),b.resume()},null!=a.characters&&(b.ontext=function(b){return a.characters.call(c,b)}),null!=a.startElement&&(b.onopentag=function(b){return a.startElement.call(c,b)}),null!=a.endElement&&(b.onclosetag=function(b){return a.endElement.call(c,b)}),null!=a.comment&&(b.oncomment=function(b){return a.comment.call(c,b)}),null!=a.startCdata&&(b.onopencdata=function(){return a.startCdata.call(c)}),null!=a.cdata&&(b.oncdata=function(b){return a.cdata.call(c,b)}),null!=a.endCdata&&(b.onclosecdata=function(){return a.endCdata.call(c)}),null!=a.endDocument&&(b.onend=function(){return a.endDocument.call(c)}),b.onstart=null!=a.startDocument?function(){return a.startDocument.call(c)}:function(){},this.$parser=b,this.$errors=[]}}return a.prototype.parse=function(a){var b,c,d,e;for(this.reset(),d=this.$parser,c=a.getLength(),d.onstart(),b=e=0;c>=0?c>=e:e>=c;b=c>=0?++e:--e)d.write(a.getLine(b)+"\n");return d.close(),this.validated()?!0:!1},a.prototype.validationError=function(a,b){var c;return c=this.$parser,this.$errors.push({text:a,row:c.line,column:c.column,type:null!=b?b:"error"})},a.prototype.validated=function(){return 0===this.$errors.length},a}(),Angles.ValidatorSAX=function(a){function d(a){var b=this;d.__super__.constructor.call(this,a),this.dispatcher.on("validation",function(){var a,c;return a=null!=(c=b.$angles)?c.getDocument():void 0,null!=a?(b.dispatcher.trigger("validation:start"),b.validate(b.$angles.getDocument())):void 0})}return b(d,a),d.prototype.checkSchema=function(a,b){var d,e,f,g,h;if(null!=this.$schema)return 1===(null!=b?b.length:void 0)?(this.$schema.hasOwnProperty(null!=(g=b[0])?g.name:void 0)?(f=new RegExp(this.$schema._start,"ig"),null===f.exec(b[0].name+",")&&a.validationError("Invalid root element: "+b[0].name+".")):a.validationError("Invalid root element: "+b[0].name+"."),void 0):(d=b[0].name,e=b[1].name,null==this.$schema[e]?a.validationError("The "+d+" element is not allowed as a child of the "+e+" element."):(c.call(null!=(h=this.$schema[e])?h.children:void 0,d)<0&&a.validationError("The "+d+" element is not allowed as a child of the "+e+" element."),void 0))},d.prototype.checkChildren=function(a,b){var c,d,e;if(null!=this.$schema&&b.length>0&&(d=b[0],c=d.children.join(","),""!==c&&(c+=","),this.$schema.hasOwnProperty(null!=d?d.name:void 0)&&this.$schema[d.name].hasOwnProperty("model")))return e=new RegExp(this.$schema[d.name].model,"ig"),null===e.exec(c)?a.validationError(d.name+" is invalid: one or more required children are missing or its child elements are in the wrong order."):void 0},d.prototype.validate=function(a){var b,c,d=this;return b=[],c=new Angles.SAXParser({startDocument:function(){return b=[]},endDocument:function(){var a,d;return b.length>0?(d=function(){var c,d,e;for(e=[],c=0,d=b.length;d>c;c++)a=b[c],e.push(a.name);return e}(),c.validationError("Unclosed elements at end of document: "+d.join(", "))):void 0},startElement:function(a){return b.length>0&&b[0].children.push(a.local),b.unshift({name:a.local,children:[]}),d.checkSchema(c,b)},characters:function(a){return b.length>0&&null===a.match(/^[\s\r\n]*$/)?b[0].children.push("_text_"):void 0},endElement:function(){return d.checkChildren(c,b),b.shift()}}),c.parse(a),this.$errors=c.$errors,this.displayErrors()},d}(Angles.Validator)}.call(this),function(){var a={}.hasOwnProperty,b=function(b,c){function d(){this.constructor=b}for(var e in c)a.call(c,e)&&(b[e]=c[e]);return d.prototype=c.prototype,b.prototype=new d,b.__super__=c.prototype,b};Angles.ValidatorSRV=function(a){function c(a){var b=this;c.__super__.constructor.call(this,a),this.$validatorUrl=a.validator,this.$requestHandler=null!=a.requestHandler?a.requestHandler:d,this.$validationHandler=null!=a.validationHandler?a.validationHandler:e,this.dispatcher.on("validation",function(){return b.dispatcher.trigger("validation:start"),b.$requestHandler(b)})}var d,e;return b(c,a),d=function(a){var b,c,d=this;return b=a.$angles.getDocument(),c=escape(b.getValue()),$.ajax({url:a.$validatorUrl,type:"POST",crossDomain:!0,processData:!1,data:"schema="+a.$schema+"&document="+c,dataType:"json",success:function(b){return a.$validationHandler(a,b)},error:function(a,b,c){var e;return d.dispatcher.trigger("notification:clear"),c=0===a.status?"Cannot reach server":c,e={type:"Server",info:"Status: "+a.status,message:c,location:{row:-1,column:-1}},d.dispatcher.trigger("notification:push",e)}})},e=function(a,b){var c,d,e;for(a.$errors=[],d=0,e=b.length;e>d;d++)c=b[d],a.$errors.push({text:c.message,row:c.line-1,column:c.column,type:c.type});return a.displayErrors()},c}(Angles.Validator)}.call(this); --------------------------------------------------------------------------------