diff --git a/.gitignore b/.gitignore index 6f4d056..4f002b6 100644 --- a/.gitignore +++ b/.gitignore @@ -35,9 +35,12 @@ circle/*.key circle/*.pem # collected static files: -circle/static circle/static_collected +circle/bower_components # jsi18n files jsi18n scripts.rc + +# less +*.css diff --git a/circle/bower.json b/circle/bower.json new file mode 100644 index 0000000..cae36cf --- /dev/null +++ b/circle/bower.json @@ -0,0 +1,23 @@ +{ + "name": "circle", + "version": "0.0.0", + "license": "GPL", + "private": true, + "ignore": [ + "**/.*", + "node_modules", + "bower_components", + "test", + "tests" + ], + "dependencies": { + "bootstrap": "~3.2.0", + "fontawesome": "~4.2.0", + "jquery": "~2.1.1", + "no-vnc": "*", + "jquery-knob": "~1.2.9", + "jquery-simple-slider": "https://github.com/BME-IK/jquery-simple-slider.git", + "bootbox": "~4.3.0", + "intro.js": "0.9.0" + } +} diff --git a/circle/bower_components/.gitkeep b/circle/bower_components/.gitkeep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/circle/bower_components/.gitkeep diff --git a/circle/circle/settings/base.py b/circle/circle/settings/base.py index 3e7b86e..c51e91c 100644 --- a/circle/circle/settings/base.py +++ b/circle/circle/settings/base.py @@ -160,10 +160,88 @@ STATICFILES_FINDERS = ( 'django.contrib.staticfiles.finders.AppDirectoriesFinder', ) ########## END STATIC FILE CONFIGURATION +STATICFILES_DIRS = [normpath(join(SITE_ROOT, 'bower_components'))] p = normpath(join(SITE_ROOT, '../../site-circle/static')) if exists(p): - STATICFILES_DIRS = (p, ) + STATICFILES_DIRS.append(p) + +STATICFILES_STORAGE = 'pipeline.storage.PipelineCachedStorage' +PIPELINE_COMPILERS = ( + 'pipeline.compilers.less.LessCompiler', +) +PIPELINE_CSS_COMPRESSOR = 'pipeline.compressors.yuglify.YuglifyCompressor' +PIPELINE_JS_COMPRESSOR = 'pipeline.compressors.slimit.SlimItCompressor' +PIPELINE_DISABLE_WRAPPER = True +PIPELINE_LESS_ARGUMENTS = u'--include-path={}'.format(':'.join(STATICFILES_DIRS)) +PIPELINE_CSS = { + "all": {"source_filenames": ( + "compile_bootstrap.less", + "bootstrap/dist/css/bootstrap-theme.css", + "fontawesome/css/font-awesome.css", + "jquery-simple-slider/css/simple-slider.css", + "intro.js/introjs.css", + "template.less", + "dashboard/dashboard.less", + "network/network.less", + "autocomplete_light/style.css", + ), + "output_filename": "all.css", + } +} +PIPELINE_JS = { + "all": {"source_filenames": ( + # "jquery/dist/jquery.js", # included separately + "bootbox/bootbox.js", + "bootstrap/dist/js/bootstrap.js", + "intro.js/intro.js", + "jquery-knob/dist/jquery.knob.min.js", + "jquery-simple-slider/js/simple-slider.js", + "dashboard/dashboard.js", + "dashboard/group-details.js", + "dashboard/group-list.js", + "dashboard/js/stupidtable.min.js", # no bower file + "dashboard/node-create.js", + "dashboard/node-details.js", + "dashboard/node-list.js", + "dashboard/profile.js", + "dashboard/store.js", + "dashboard/template-list.js", + "dashboard/vm-common.js", + "dashboard/vm-create.js", + "dashboard/vm-list.js", + "js/host.js", + "js/network.js", + "js/switch-port.js", + "autocomplete_light/autocomplete.js", + "autocomplete_light/widget.js", + "autocomplete_light/addanother.js", + "autocomplete_light/text_widget.js", + "autocomplete_light/remote.js", + ), + "output_filename": "all.js", + }, + "vm-detail": {"source_filenames": ( + "dashboard/vm-details.js", + "no-vnc/include/util.js", + "no-vnc/include/webutil.js", + "no-vnc/include/base64.js", + "no-vnc/include/websock.js", + "no-vnc/include/des.js", + "no-vnc/include/keysym.js", + "no-vnc/include/keysymdef.js", + "no-vnc/include/keyboard.js", + "no-vnc/include/input.js", + "no-vnc/include/display.js", + "no-vnc/include/jsunzip.js", + "no-vnc/include/rfb.js", + "dashboard/vm-console.js", + "dashboard/vm-tour.js", + ), + "output_filename": "vm-detail.js", + }, +} + ########## SECRET CONFIGURATION @@ -266,6 +344,7 @@ THIRD_PARTY_APPS = ( 'statici18n', 'django_sshkey', 'autocomplete_light', + 'pipeline', ) # Apps specific for this project go here. diff --git a/circle/circle/settings/local.py b/circle/circle/settings/local.py index 1d5cb37..dd82156 100644 --- a/circle/circle/settings/local.py +++ b/circle/circle/settings/local.py @@ -109,3 +109,7 @@ CRISPY_FAIL_SILENTLY = not DEBUG if DEBUG: from django.dispatch import Signal Signal.send_robust = Signal.send + +PIPELINE_DISABLED_COMPILERS = ( + 'pipeline.compilers.less.LessCompiler', +) diff --git a/circle/circle/settings/test.py b/circle/circle/settings/test.py index 5cf6062..3f3f978 100644 --- a/circle/circle/settings/test.py +++ b/circle/circle/settings/test.py @@ -58,3 +58,6 @@ for i in LOCAL_APPS: LOGGING['loggers'][i] = {'handlers': ['console'], 'level': level} # Forbid store usage STORE_URL = "" + +# buildbot doesn't love pipeline +STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.StaticFilesStorage' diff --git a/circle/common/management/__init__.py b/circle/common/management/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/circle/common/management/__init__.py diff --git a/circle/common/management/commands/__init__.py b/circle/common/management/commands/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/circle/common/management/commands/__init__.py diff --git a/circle/common/management/commands/compileless.py b/circle/common/management/commands/compileless.py new file mode 100644 index 0000000..0168974 --- /dev/null +++ b/circle/common/management/commands/compileless.py @@ -0,0 +1,11 @@ +from django.core.management.base import BaseCommand + +from common.management.commands.watch import LessUtils + + +class Command(BaseCommand): + help = "Compiles all LESS files." + + def handle(self, *args, **kwargs): + print("Compiling LESS") + LessUtils.initial_compile() diff --git a/circle/common/management/commands/watch.py b/circle/common/management/commands/watch.py new file mode 100644 index 0000000..e0889a3 --- /dev/null +++ b/circle/common/management/commands/watch.py @@ -0,0 +1,86 @@ +import subprocess +import os +import pyinotify + +from django.core.management.base import BaseCommand +from django.conf import settings + +STATIC_FILES = u'--include-path={}'.format(':'.join(settings.STATICFILES_DIRS)) +IGNORED_FOLDERS = ("static_collected", "bower_components", ) + + +class LessUtils(object): + @staticmethod + def less_path_to_css_path(pathname): + return "%s.css" % pathname[:-1 * len(".less")] + + @staticmethod + def compile_less(less_pathname, css_pathname): + cmd = ["lessc", STATIC_FILES, less_pathname, css_pathname] + + print("\n%s" % ("=" * 30)) + print("Compiling: %s" % os.path.basename(less_pathname)) + + try: + subprocess.check_output(cmd) + except subprocess.CalledProcessError as e: + print(e.output) + else: + print("Successfully compiled:\n%s\n->\n%s" % ( + less_pathname, css_pathname)) + + @staticmethod + def initial_compile(): + """ Walks through the project looking for LESS files + and compiles them into CSS. + """ + for root, dirs, files in os.walk(settings.SITE_ROOT): + for f in files: + if not f.endswith(".less"): + continue + + relpath = os.path.relpath(root, settings.SITE_ROOT) + if relpath.startswith(IGNORED_FOLDERS): + continue + + less_pathname = "%s/%s" % (root, f) + css_pathname = LessUtils.less_path_to_css_path(less_pathname) + LessUtils.compile_less(less_pathname, css_pathname) + + @staticmethod + def start_watch(): + """ Watches for changes in LESS files recursively from the + project's root and compiles the files + """ + wm = pyinotify.WatchManager() + + class EventHandler(pyinotify.ProcessEvent): + def process_IN_MODIFY(self, event): + if not event.name.endswith(".less"): + return + + relpath = os.path.relpath(event.pathname, settings.SITE_ROOT) + if relpath.startswith(IGNORED_FOLDERS): + return + + css_pathname = LessUtils.less_path_to_css_path(event.pathname) + LessUtils.compile_less(event.pathname, css_pathname) + + handler = EventHandler() + notifier = pyinotify.Notifier(wm, handler) + wm.add_watch(settings.SITE_ROOT, pyinotify.IN_MODIFY, rec=True) + notifier.loop() + + +class Command(BaseCommand): + help = "Compiles all LESS files then watches for changes." + + def handle(self, *args, **kwargs): + # for first run compile everything + print("Initial LESS compiles") + LessUtils.initial_compile() + print("\n%s\n" % ("=" * 30)) + print("End of initial LESS compiles\n") + + # after first run watch less files + LessUtils.start_watch() diff --git a/circle/dashboard/management/__init__.py b/circle/dashboard/management/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/circle/dashboard/management/__init__.py diff --git a/circle/dashboard/management/commands/__init__.py b/circle/dashboard/management/commands/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/circle/dashboard/management/commands/__init__.py diff --git a/circle/dashboard/management/commands/init.py b/circle/dashboard/management/commands/init.py new file mode 100644 index 0000000..9cb5121 --- /dev/null +++ b/circle/dashboard/management/commands/init.py @@ -0,0 +1,165 @@ +# Copyright 2014 Budapest University of Technology and Economics (BME IK) +# +# This file is part of CIRCLE Cloud. +# +# CIRCLE is free software: you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) +# any later version. +# +# CIRCLE is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License along +# with CIRCLE. If not, see . + +from __future__ import unicode_literals, absolute_import + +from optparse import make_option + +from django.contrib.auth.models import User +from django.core.management.base import BaseCommand + +from firewall.models import (Vlan, VlanGroup, Domain, Firewall, Rule, + SwitchPort, EthernetDevice, Host) +from storage.models import DataStore +from vm.models import Lease + + +class Command(BaseCommand): + option_list = BaseCommand.option_list + ( + make_option('--force', action="store_true"), + make_option('--portal-ip'), + make_option('--external-net'), + make_option('--management-net'), + make_option('--vm-net'), + make_option('--external-if'), + make_option('--management-if'), + make_option('--trunk-if'), + make_option('--datastore-queue'), + make_option('--firewall-queue'), + make_option('--admin-user'), + make_option('--admin-pass'), + ) + + def create(self, model, field, **kwargs): + value = kwargs[field] + qs = model.objects.filter(**{field: value})[:1] + if not qs.exists(): + obj = model.objects.create(**kwargs) + self.changed.append('New %s: %s' % (model, obj)) + return obj + else: + return qs[0] + +# http://docs.saltstack.com/en/latest/ref/states/all/salt.states.cmd.html + def print_state(self): + changed = "yes" if len(self.changed) else "no" + print "\nchanged=%s comment='%s'" % (changed, ", ".join(self.changed)) + + def handle(self, *args, **options): + self.changed = [] + + if (DataStore.objects.exists() and Vlan.objects.exists() + and not options['force']): + return self.print_state() + + admin = self.create(User, 'username', username=options['admin_user'], + is_superuser=True, is_staff=True) + admin.set_password(options['admin_pass']) + admin.save() + + self.create(DataStore, 'path', path='/datastore', name='default', + hostname=options['datastore_queue']) + + # leases + self.create(Lease, 'name', name='lab', + suspend_interval_seconds=3600 * 5, + delete_interval_seconds=3600 * 24 * 7) + + self.create(Lease, 'name', name='project', + suspend_interval_seconds=3600 * 24 * 30, + delete_interval_seconds=3600 * 24 * 30 * 6) + + self.create(Lease, 'name', name='server', + suspend_interval_seconds=3600 * 24 * 365, + delete_interval_seconds=3600 * 24 * 365 * 3) + + domain = self.create(Domain, 'name', name='example.com', owner=admin) + + # vlans + net = self.create(Vlan, 'name', name='net', vid=4, + network4=options['external_net'], domain=domain) + + man = self.create(Vlan, 'name', name='man', vid=3, dhcp_pool='manual', + network4=options['management_net'], domain=domain, + snat_ip=options['external_net'].split('/')[0]) + man.snat_to.add(net) + man.snat_to.add(man) + + vm = self.create(Vlan, 'name', name='vm', vid=2, dhcp_pool='manual', + network4=options['vm_net'], domain=domain, + snat_ip=options['external_net'].split('/')[0]) + vm.snat_to.add(net) + vm.snat_to.add(vm) + + # default vlan groups + vg_all = self.create(VlanGroup, 'name', name='all') + vg_all.vlans.add(vm, man, net) + + vg_pf = self.create(VlanGroup, 'name', name='portforward') + vg_pf.vlans.add(vm, man, net) + + vg_net = self.create(VlanGroup, 'name', name='net') + vg_net.vlans.add(net) + + # portal host + portal = self.create(Host, 'hostname', hostname='portal', vlan=man, + mac='11:22:33:44:55:66', owner=admin, + shared_ip=True, external_ipv4=man.snat_ip, + ipv4=options['portal_ip']) + portal.add_port(proto='tcp', public=443, private=443) + portal.add_port(proto='tcp', public=22, private=22) + + # firewall rules + fw = self.create(Firewall, 'name', name=options['firewall_queue']) + + self.create(Rule, 'description', description='default output rule', + direction='out', action='accept', + foreign_network=vg_all, firewall=fw) + + self.create(Rule, 'description', description='default input rule', + direction='in', action='accept', + foreign_network=vg_all, firewall=fw) + + # vlan rules + self.create(Rule, 'description', description='allow vm->net', + direction='out', action='accept', + foreign_network=vg_net, vlan=vm) + + self.create(Rule, 'description', description='allow man->net', + direction='out', action='accept', + foreign_network=vg_net, vlan=man) + + # switch + # uplink interface + sp_net = self.create(SwitchPort, 'untagged_vlan', untagged_vlan=net) + self.create(EthernetDevice, 'switch_port', switch_port=sp_net, + name=options['external_if']) + + # management interface + if options['management_if']: + sp_man = self.create( + SwitchPort, 'untagged_vlan', untagged_vlan=man) + self.create(EthernetDevice, 'switch_port', switch_port=sp_man, + name=options['management_if']) + + # vm interface + sp_trunk = self.create( + SwitchPort, 'tagged_vlans', untagged_vlan=man, tagged_vlans=vg_all) + self.create(EthernetDevice, 'switch_port', switch_port=sp_trunk, + name=options['trunk_if']) + + return self.print_state() diff --git a/circle/dashboard/static/compile_bootstrap.less b/circle/dashboard/static/compile_bootstrap.less new file mode 100644 index 0000000..63f0e12 --- /dev/null +++ b/circle/dashboard/static/compile_bootstrap.less @@ -0,0 +1,55 @@ +// Core variables and mixins +@import "bootstrap/less/variables.less"; + +// Custom variables +@navbar-height: 45px; + +@import "bootstrap/less/mixins.less"; + +// Reset and dependencies +@import "bootstrap/less/normalize.less"; +@import "bootstrap/less/print.less"; +// we don't use these, also they make collectstatic fail ... +// @import "bootstrap/less/glyphicons.less"; + +// Core CSS +@import "bootstrap/less/scaffolding.less"; +@import "bootstrap/less/type.less"; +@import "bootstrap/less/code.less"; +@import "bootstrap/less/grid.less"; +@import "bootstrap/less/tables.less"; +@import "bootstrap/less/forms.less"; +@import "bootstrap/less/buttons.less"; + +// Components +@import "bootstrap/less/component-animations.less"; +@import "bootstrap/less/dropdowns.less"; +@import "bootstrap/less/button-groups.less"; +@import "bootstrap/less/input-groups.less"; +@import "bootstrap/less/navs.less"; +@import "bootstrap/less/navbar.less"; +@import "bootstrap/less/breadcrumbs.less"; +@import "bootstrap/less/pagination.less"; +@import "bootstrap/less/pager.less"; +@import "bootstrap/less/labels.less"; +@import "bootstrap/less/badges.less"; +@import "bootstrap/less/jumbotron.less"; +@import "bootstrap/less/thumbnails.less"; +@import "bootstrap/less/alerts.less"; +@import "bootstrap/less/progress-bars.less"; +@import "bootstrap/less/media.less"; +@import "bootstrap/less/list-group.less"; +@import "bootstrap/less/panels.less"; +@import "bootstrap/less/responsive-embed.less"; +@import "bootstrap/less/wells.less"; +@import "bootstrap/less/close.less"; + +// Components w/ JavaScript +@import "bootstrap/less/modals.less"; +@import "bootstrap/less/tooltip.less"; +@import "bootstrap/less/popovers.less"; +@import "bootstrap/less/carousel.less"; + +// Utility classes +@import "bootstrap/less/utilities.less"; +@import "bootstrap/less/responsive-utilities.less"; diff --git a/circle/dashboard/static/dashboard/bootstrap-slider/bootstrap-slider.js b/circle/dashboard/static/dashboard/bootstrap-slider/bootstrap-slider.js deleted file mode 100644 index 0e5a433..0000000 --- a/circle/dashboard/static/dashboard/bootstrap-slider/bootstrap-slider.js +++ /dev/null @@ -1,391 +0,0 @@ -/* ========================================================= - * bootstrap-slider.js v2.0.0 - * http://www.eyecon.ro/bootstrap-slider - * ========================================================= - * Copyright 2012 Stefan Petre - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ========================================================= */ - -!function( $ ) { - - var Slider = function(element, options) { - this.element = $(element); - this.picker = $('
'+ - '
'+ - '
'+ - '
'+ - '
'+ - '
'+ - '
'+ - '
') - .insertBefore(this.element) - .append(this.element); - this.id = this.element.data('slider-id')||options.id; - if (this.id) { - this.picker[0].id = this.id; - } - - if (typeof Modernizr !== 'undefined' && Modernizr.touch) { - this.touchCapable = true; - } - - var tooltip = this.element.data('slider-tooltip')||options.tooltip; - - this.tooltip = this.picker.find('.tooltip'); - this.tooltipInner = this.tooltip.find('div.tooltip-inner'); - - this.orientation = this.element.data('slider-orientation')||options.orientation; - switch(this.orientation) { - case 'vertical': - this.picker.addClass('slider-vertical'); - this.stylePos = 'top'; - this.mousePos = 'pageY'; - this.sizePos = 'offsetHeight'; - this.tooltip.addClass('right')[0].style.left = '100%'; - break; - default: - this.picker - .addClass('slider-horizontal') - .css('width', this.element.outerWidth()); - this.orientation = 'horizontal'; - this.stylePos = 'left'; - this.mousePos = 'pageX'; - this.sizePos = 'offsetWidth'; - this.tooltip.addClass('top')[0].style.top = -this.tooltip.outerHeight() - 14 + 'px'; - break; - } - - this.min = this.element.data('slider-min')||options.min; - this.max = this.element.data('slider-max')||options.max; - this.step = this.element.data('slider-step')||options.step; - this.value = this.element.data('slider-value')||options.value; - if (this.value[1]) { - this.range = true; - } - - this.selection = this.element.data('slider-selection')||options.selection; - this.selectionEl = this.picker.find('.slider-selection'); - if (this.selection === 'none') { - this.selectionEl.addClass('hide'); - } - this.selectionElStyle = this.selectionEl[0].style; - - - this.handle1 = this.picker.find('.slider-handle:first'); - this.handle1Stype = this.handle1[0].style; - this.handle2 = this.picker.find('.slider-handle:last'); - this.handle2Stype = this.handle2[0].style; - - var handle = this.element.data('slider-handle')||options.handle; - switch(handle) { - case 'round': - this.handle1.addClass('round'); - this.handle2.addClass('round'); - break - case 'triangle': - this.handle1.addClass('triangle'); - this.handle2.addClass('triangle'); - break - } - - if (this.range) { - this.value[0] = Math.max(this.min, Math.min(this.max, this.value[0])); - this.value[1] = Math.max(this.min, Math.min(this.max, this.value[1])); - } else { - this.value = [ Math.max(this.min, Math.min(this.max, this.value))]; - this.handle2.addClass('hide'); - if (this.selection == 'after') { - this.value[1] = this.max; - } else { - this.value[1] = this.min; - } - } - this.diff = this.max - this.min; - this.percentage = [ - (this.value[0]-this.min)*100/this.diff, - (this.value[1]-this.min)*100/this.diff, - this.step*100/this.diff - ]; - - this.offset = this.picker.offset(); - this.size = this.picker[0][this.sizePos]; - - this.formater = options.formater; - - this.layout(); - - if (this.touchCapable) { - // Touch: Bind touch events: - this.picker.on({ - touchstart: $.proxy(this.mousedown, this) - }); - } else { - this.picker.on({ - mousedown: $.proxy(this.mousedown, this) - }); - } - - if (tooltip === 'show') { - this.picker.on({ - mouseenter: $.proxy(this.showTooltip, this), - mouseleave: $.proxy(this.hideTooltip, this) - }); - } else { - this.tooltip.addClass('hide'); - } - }; - - Slider.prototype = { - constructor: Slider, - - over: false, - inDrag: false, - - showTooltip: function(){ - this.tooltip.addClass('in'); - //var left = Math.round(this.percent*this.width); - //this.tooltip.css('left', left - this.tooltip.outerWidth()/2); - this.over = true; - }, - - hideTooltip: function(){ - if (this.inDrag === false) { - this.tooltip.removeClass('in'); - } - this.over = false; - }, - - layout: function(){ - this.handle1Stype[this.stylePos] = this.percentage[0]+'%'; - this.handle2Stype[this.stylePos] = this.percentage[1]+'%'; - if (this.orientation == 'vertical') { - this.selectionElStyle.top = Math.min(this.percentage[0], this.percentage[1]) +'%'; - this.selectionElStyle.height = Math.abs(this.percentage[0] - this.percentage[1]) +'%'; - } else { - this.selectionElStyle.left = Math.min(this.percentage[0], this.percentage[1]) +'%'; - this.selectionElStyle.width = Math.abs(this.percentage[0] - this.percentage[1]) +'%'; - } - if (this.range) { - this.tooltipInner.text( - this.formater(this.value[0]) + - ' : ' + - this.formater(this.value[1]) - ); - this.tooltip[0].style[this.stylePos] = this.size * (this.percentage[0] + (this.percentage[1] - this.percentage[0])/2)/100 - (this.orientation === 'vertical' ? this.tooltip.outerHeight()/2 : this.tooltip.outerWidth()/2) +'px'; - } else { - this.tooltipInner.text( - this.formater(this.value[0]) - ); - this.tooltip[0].style[this.stylePos] = this.size * this.percentage[0]/100 - (this.orientation === 'vertical' ? this.tooltip.outerHeight()/2 : this.tooltip.outerWidth()/2) +'px'; - } - }, - - mousedown: function(ev) { - if (this.element[0].disabled) { - return false; - } - - // Touch: Get the original event: - if (this.touchCapable && ev.type === 'touchstart') { - ev = ev.originalEvent; - } - - this.offset = this.picker.offset(); - this.size = this.picker[0][this.sizePos]; - - var percentage = this.getPercentage(ev); - - if (this.range) { - var diff1 = Math.abs(this.percentage[0] - percentage); - var diff2 = Math.abs(this.percentage[1] - percentage); - this.dragged = (diff1 < diff2) ? 0 : 1; - } else { - this.dragged = 0; - } - - this.percentage[this.dragged] = percentage; - this.layout(); - - if (this.touchCapable) { - // Touch: Bind touch events: - $(document).on({ - touchmove: $.proxy(this.mousemove, this), - touchend: $.proxy(this.mouseup, this) - }); - } else { - $(document).on({ - mousemove: $.proxy(this.mousemove, this), - mouseup: $.proxy(this.mouseup, this) - }); - } - - this.inDrag = true; - var val = this.calculateValue(); - this.element.trigger({ - type: 'slideStart', - value: val - }).trigger({ - type: 'slide', - value: val - }); - return false; - }, - - mousemove: function(ev) { - - // Touch: Get the original event: - if (this.touchCapable && ev.type === 'touchmove') { - ev = ev.originalEvent; - } - - var percentage = this.getPercentage(ev); - if (this.range) { - if (this.dragged === 0 && this.percentage[1] < percentage) { - this.percentage[0] = this.percentage[1]; - this.dragged = 1; - } else if (this.dragged === 1 && this.percentage[0] > percentage) { - this.percentage[1] = this.percentage[0]; - this.dragged = 0; - } - } - this.percentage[this.dragged] = percentage; - this.layout(); - var val = this.calculateValue(); - this.element - .trigger({ - type: 'slide', - value: val - }) - .data('value', val) - .prop('value', val); - return false; - }, - - mouseup: function(ev) { - if (this.touchCapable) { - // Touch: Bind touch events: - $(document).off({ - touchmove: this.mousemove, - touchend: this.mouseup - }); - } else { - $(document).off({ - mousemove: this.mousemove, - mouseup: this.mouseup - }); - } - - this.inDrag = false; - if (this.over == false) { - this.hideTooltip(); - } - this.element; - var val = this.calculateValue(); - this.element - .trigger({ - type: 'slideStop', - value: val - }) - .data('value', val) - .prop('value', val); - return false; - }, - - calculateValue: function() { - var val; - if (this.range) { - val = [ - (this.min + Math.round((this.diff * this.percentage[0]/100)/this.step)*this.step), - (this.min + Math.round((this.diff * this.percentage[1]/100)/this.step)*this.step) - ]; - this.value = val; - } else { - val = (this.min + Math.round((this.diff * this.percentage[0]/100)/this.step)*this.step); - this.value = [val, this.value[1]]; - } - return val; - }, - - getPercentage: function(ev) { - if (this.touchCapable) { - ev = ev.touches[0]; - } - var percentage = (ev[this.mousePos] - this.offset[this.stylePos])*100/this.size; - percentage = Math.round(percentage/this.percentage[2])*this.percentage[2]; - return Math.max(0, Math.min(100, percentage)); - }, - - getValue: function() { - if (this.range) { - return this.value; - } - return this.value[0]; - }, - - setValue: function(val) { - this.value = val; - - if (this.range) { - this.value[0] = Math.max(this.min, Math.min(this.max, this.value[0])); - this.value[1] = Math.max(this.min, Math.min(this.max, this.value[1])); - } else { - this.value = [ Math.max(this.min, Math.min(this.max, this.value))]; - this.handle2.addClass('hide'); - if (this.selection == 'after') { - this.value[1] = this.max; - } else { - this.value[1] = this.min; - } - } - this.diff = this.max - this.min; - this.percentage = [ - (this.value[0]-this.min)*100/this.diff, - (this.value[1]-this.min)*100/this.diff, - this.step*100/this.diff - ]; - this.layout(); - } - }; - - $.fn.slider = function ( option, val ) { - return this.each(function () { - var $this = $(this), - data = $this.data('slider'), - options = typeof option === 'object' && option; - if (!data) { - $this.data('slider', (data = new Slider(this, $.extend({}, $.fn.slider.defaults,options)))); - } - if (typeof option == 'string') { - data[option](val); - } - }) - }; - - $.fn.slider.defaults = { - min: 0, - max: 10, - step: 1, - orientation: 'horizontal', - value: 5, - selection: 'before', - tooltip: 'show', - handle: 'round', - formater: function(value) { - return value; - } - }; - - $.fn.slider.Constructor = Slider; - -}( window.jQuery ); \ No newline at end of file diff --git a/circle/dashboard/static/dashboard/bootstrap-slider/less/slider.less b/circle/dashboard/static/dashboard/bootstrap-slider/less/slider.less deleted file mode 100644 index 2dc9c85..0000000 --- a/circle/dashboard/static/dashboard/bootstrap-slider/less/slider.less +++ /dev/null @@ -1,104 +0,0 @@ -/*! - * Slider for Bootstrap - * - * Copyright 2012 Stefan Petre - * Licensed under the Apache License v2.0 - * http://www.apache.org/licenses/LICENSE-2.0 - * - */ - -.slider { - display: inline-block; - vertical-align: middle; - position: relative; - &.slider-horizontal { - width: 210px; - height: @baseLineHeight; - .slider-track { - height: @baseLineHeight/2; - width: 100%; - margin-top: -@baseLineHeight/4; - top: 50%; - left: 0; - } - .slider-selection { - height: 100%; - top: 0; - bottom: 0; - } - .slider-handle { - margin-left: -@baseLineHeight/2; - margin-top: -@baseLineHeight/4; - &.triangle { - border-width: 0 @baseLineHeight/2 @baseLineHeight/2 @baseLineHeight/2; - width: 0; - height: 0; - border-bottom-color: #0480be; - margin-top: 0; - } - } - } - &.slider-vertical { - height: 210px; - width: @baseLineHeight; - .slider-track { - width: @baseLineHeight/2; - height: 100%; - margin-left: -@baseLineHeight/4; - left: 50%; - top: 0; - } - .slider-selection { - width: 100%; - left: 0; - top: 0; - bottom: 0; - } - .slider-handle { - margin-left: -@baseLineHeight/4; - margin-top: -@baseLineHeight/2; - &.triangle { - border-width: @baseLineHeight/2 0 @baseLineHeight/2 @baseLineHeight/2; - width: 1px; - height: 1px; - border-left-color: #0480be; - margin-left: 0; - } - } - } - input { - display: none; - } - .tooltip-inner { - white-space: nowrap; - } -} -.slider-track { - position: absolute; - cursor: pointer; - #gradient > .vertical(#f5f5f5, #f9f9f9); - .box-shadow(inset 0 1px 2px rgba(0,0,0,.1)); - .border-radius(@baseBorderRadius); -} -.slider-selection { - position: absolute; - #gradient > .vertical(#f9f9f9, #f5f5f5); - .box-shadow(inset 0 -1px 0 rgba(0,0,0,.15)); - .box-sizing(border-box); - .border-radius(@baseBorderRadius); -} -.slider-handle { - position: absolute; - width: @baseLineHeight; - height: @baseLineHeight; - #gradient > .vertical(#149bdf, #0480be); - .box-shadow(~"inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05)"); - opacity: 0.8; - border: 0px solid transparent; - &.round { - .border-radius(@baseLineHeight); - } - &.triangle { - background: transparent none; - } -} \ No newline at end of file diff --git a/circle/dashboard/static/dashboard/bootstrap-slider/slider.css b/circle/dashboard/static/dashboard/bootstrap-slider/slider.css deleted file mode 100644 index f6b699c..0000000 --- a/circle/dashboard/static/dashboard/bootstrap-slider/slider.css +++ /dev/null @@ -1,205 +0,0 @@ -/*! - * Slider for Bootstrap - * - * Copyright 2012 Stefan Petre - * Licensed under the Apache License v2.0 - * http://www.apache.org/licenses/LICENSE-2.0 - * - */ -.slider { - display: inline-block; - vertical-align: middle; - position: relative; -} -.slider.slider-horizontal { - width: 210px; - height: 20px; -} -.slider.slider-horizontal .slider-track { - height: 10px; - width: 100%; - margin-top: -5px; - top: 50%; - left: 0; -} -.slider.slider-horizontal .slider-selection { - height: 100%; - top: 0; - bottom: 0; -} -.slider.slider-horizontal .slider-handle { - margin-left: -10px; - margin-top: -5px; -} -.slider.slider-horizontal .slider-handle.triangle { - border-width: 0 10px 10px 10px; - width: 0; - height: 0; - border-bottom-color: #0480be; - margin-top: 0; -} -.slider.slider-vertical { - height: 210px; - width: 20px; -} -.slider.slider-vertical .slider-track { - width: 10px; - height: 100%; - margin-left: -5px; - left: 50%; - top: 0; -} -.slider.slider-vertical .slider-selection { - width: 100%; - left: 0; - top: 0; - bottom: 0; -} -.slider.slider-vertical .slider-handle { - margin-left: -5px; - margin-top: -10px; -} -.slider.slider-vertical .slider-handle.triangle { - border-width: 10px 0 10px 10px; - width: 1px; - height: 1px; - border-left-color: #0480be; - margin-left: 0; -} -.slider input { - display: none; -} -.slider .tooltip-inner { - white-space: nowrap; -} -.slider-track { - position: absolute; - cursor: pointer; - background-color: #f7f7f7; - background-image: -moz-linear-gradient(top, #f5f5f5, #f9f9f9); - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9)); - background-image: -webkit-linear-gradient(top, #f5f5f5, #f9f9f9); - background-image: -o-linear-gradient(top, #f5f5f5, #f9f9f9); - background-image: linear-gradient(to bottom, #f5f5f5, #f9f9f9); - background-repeat: repeat-x; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#fff9f9f9', GradientType=0); - -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); - -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); - box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; -} -.slider-selection { - position: absolute; - background-color: #f7f7f7; - background-image: -moz-linear-gradient(top, #f9f9f9, #f5f5f5); - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f9f9f9), to(#f5f5f5)); - background-image: -webkit-linear-gradient(top, #f9f9f9, #f5f5f5); - background-image: -o-linear-gradient(top, #f9f9f9, #f5f5f5); - background-image: linear-gradient(to bottom, #f9f9f9, #f5f5f5); - background-repeat: repeat-x; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff9f9f9', endColorstr='#fff5f5f5', GradientType=0); - -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); - -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); - box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; -} -.slider-handle { - position: absolute; - width: 20px; - height: 20px; - background-color: #0e90d2; - background-image: -moz-linear-gradient(top, #149bdf, #0480be); - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be)); - background-image: -webkit-linear-gradient(top, #149bdf, #0480be); - background-image: -o-linear-gradient(top, #149bdf, #0480be); - background-image: linear-gradient(to bottom, #149bdf, #0480be); - background-repeat: repeat-x; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff149bdf', endColorstr='#ff0480be', GradientType=0); - -webkit-box-shadow: inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05); - -moz-box-shadow: inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05); - box-shadow: inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05); - opacity: 0.8; - border: 0px solid transparent; -} -.slider-handle.round { - -webkit-border-radius: 20px; - -moz-border-radius: 20px; - border-radius: 20px; -} -.slider-handle.triangle { - background: transparent none; -} - -/* custom */ - -.slider-handle, .slider-handle:hover { - background-color: #3071a9; - opacity: 1; - width: 8px; - height: 26px; - margin-top: -4px!important; - margin-left: -6px !important; - - border-radius: 0px; - -moz-border-radius: 0px; - -webkit-border-radius: 0px; - - text-shadow: 0 1px 0 #fff; - background-image: -webkit-gradient(linear, left 0%, left 100%, from(#428bca), to(#3071a9)); - background-image: -webkit-linear-gradient(top, #428bca, 0%, #3071a9, 100%); - background-image: -moz-linear-gradient(top, #428bca 0%, #3071a9 100%); - background-image: linear-gradient(to bottom, #428bca 0%, #3071a9 100%); - background-repeat: repeat-x; - border-color: #2d6ca2; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0); -} - -.slider-handle:hover { - background: #428bca; - background-image: none; - border-color: #2d6ca2; -} - - -.slider-track, .slider-selection { - height: 20px !important; - background: #ccc; - background: -webkit-linear-gradient(top, #bbb, #ddd); - background: -moz-linear-gradient(top, #bbb, #ddd); - background: linear-gradient(top, #bbb, #ddd); - - -webkit-box-shadow: inset 0 2px 4px rgba(0,0,0,0.1); - -moz-box-shadow: inset 0 2px 4px rgba(0,0,0,0.1); - box-shadow: inset 0 2px 4px rgba(0,0,0,0.1); - - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; - - border: 1px solid #aaa; -} - - -.slider-selection { - background-color: #8DCA09; - background: -webkit-linear-gradient(top, #8DCA09, #72A307); - background: -moz-linear-gradient(top, #8DCA09, #72A307); - background: linear-gradient(top, #8DCA09, #72A307); - border-color: #496805; -} - -.vm-slider { - width: 300px; -} - -.output { - padding-left: 10px; - font-weight: bold; -} diff --git a/circle/dashboard/static/dashboard/dashboard.js b/circle/dashboard/static/dashboard/dashboard.js index 964c692..3184931 100644 --- a/circle/dashboard/static/dashboard/dashboard.js +++ b/circle/dashboard/static/dashboard/dashboard.js @@ -3,8 +3,8 @@ $(function () { var template = $(this).data("template"); $.ajax({ type: 'GET', - url: '/dashboard/vm/create/' + (typeof template === "undefined" ? '' : '?template=' + template), - success: function(data) { + url: '/dashboard/vm/create/' + (typeof template === "undefined" ? '' : '?template=' + template), + success: function(data) { $('body').append(data); vmCreateLoaded(); addSliderMiscs(); @@ -16,12 +16,12 @@ $(function () { }); return false; }); - + $('.node-create').click(function(e) { $.ajax({ type: 'GET', - url: '/dashboard/node/create/', - success: function(data) { + url: '/dashboard/node/create/', + success: function(data) { $('body').append(data); nodeCreateLoaded(); addSliderMiscs(); @@ -68,8 +68,8 @@ $(function () { $('.template-choose').click(function(e) { $.ajax({ type: 'GET', - url: '/dashboard/template/choose/', - success: function(data) { + url: '/dashboard/template/choose/', + success: function(data) { $('body').append(data); $('#create-modal').modal('show'); $('#create-modal').on('hidden.bs.modal', function() { @@ -108,9 +108,9 @@ $(function () { e.stopImmediatePropagation(); return false; }); - $('[title]:not(.title-favourite)').tooltip(); - $('.title-favourite').tooltip({'placement': 'right'}); - $(':input[title]').tooltip({trigger: 'focus', placement: 'auto right'}); + $('body [title]:not(.title-favourite)').tooltip(); + $('body .title-favourite').tooltip({'placement': 'right'}); + $('body :input[title]').tooltip({trigger: 'focus', placement: 'auto right'}); $(".knob").knob(); $('[data-toggle="pill"]').click(function() { @@ -132,15 +132,15 @@ $(function () { $('.js-hidden').hide(); /* favourite star */ - $("#dashboard-vm-list").on('click', '.dashboard-vm-favourite', function(e) { + $("#dashboard-vm-list, .page-header").on('click', '.dashboard-vm-favourite', function(e) { var star = $(this).children("i"); var pk = $(this).data("vm"); if(star.hasClass("fa-star-o")) { star.removeClass("fa-star-o").addClass("fa-star"); - star.prop("title", "Unfavourite"); + star.prop("title", gettext("Unfavourite")); } else { star.removeClass("fa-star").addClass("fa-star-o"); - star.prop("title", "Mark as favourite"); + star.prop("title", gettext("Mark as favourite")); } $.ajax({ url: "/dashboard/favourite/", @@ -169,7 +169,7 @@ $(function () { $('.vm-delete').click(function() { var vm_pk = $(this).data('vm-pk'); var dir = window.location.pathname.indexOf('list') == -1; - addModalConfirmation(deleteObject, + addModalConfirmation(deleteObject, { 'url': '/dashboard/vm/delete/' + vm_pk + '/', 'data': [], 'pk': vm_pk, @@ -177,11 +177,11 @@ $(function () { 'redirect': dir}); return false; }); - + /* for disk remove buttons */ $('.disk-remove').click(function() { var disk_pk = $(this).data('disk-pk'); - addModalConfirmation(deleteObject, + addModalConfirmation(deleteObject, { 'url': '/dashboard/disk/' + disk_pk + '/remove/', 'data': [], 'pk': disk_pk, @@ -194,13 +194,13 @@ $(function () { $('.node-delete').click(function() { var node_pk = $(this).data('node-pk'); var dir = window.location.pathname.indexOf('list') == -1; - addModalConfirmation(deleteObject, + addModalConfirmation(deleteObject, { 'url': '/dashboard/node/delete/' + node_pk + '/', 'data': [], 'pk': node_pk, 'type': "node", 'redirect': dir}); - + return false; }); @@ -209,8 +209,8 @@ $(function () { var node_pk = $(this).data('node-pk'); var postto = $(this).attr('href'); var dir = window.location.pathname.indexOf('list') == -1; - addModalConfirmation(function(){}, - { 'url': postto, + addModalConfirmation(function(){}, + { 'url': postto, 'data': [], 'pk': node_pk, 'type': "node", @@ -223,18 +223,18 @@ $(function () { $('.group-delete').click(function() { var group_pk = $(this).data('group-pk'); var dir = window.location.pathname.indexOf('list') == -1; - addModalConfirmation(deleteObject, + addModalConfirmation(deleteObject, { 'url': '/dashboard/group/delete/' + group_pk + '/', 'data': [], 'type': "group", 'pk': group_pk, 'redirect': dir}); - + return false; }); /* search for vms */ - var my_vms = [] + var my_vms = []; $("#dashboard-vm-search-input").keyup(function(e) { // if my_vms is empty get a list of our vms if(my_vms.length < 1) { @@ -257,7 +257,7 @@ $(function () { } input = $("#dashboard-vm-search-input").val().toLowerCase(); - var search_result = [] + var search_result = []; var html = ''; for(var i in my_vms) { if(my_vms[i].name.indexOf(input) != -1 || my_vms[i].host.indexOf(input) != -1) { @@ -270,7 +270,7 @@ $(function () { search_result[i].owner ? search_result[i].owner : search_result[i].host, search_result[i].icon, search_result[i].status, search_result[i].fav, (search_result.length < 5)); - if(search_result.length == 0) + if(search_result.length === 0) html += '
' + gettext("No result") + '
'; $("#dashboard-vm-list").html(html); $('.title-favourite').tooltip({'placement': 'right'}); @@ -286,7 +286,7 @@ $(function () { }); /* search for nodes */ - var my_nodes = [] + var my_nodes = []; $("#dashboard-node-search-input").keyup(function(e) { // if my_nodes is empty get a list of our nodes if(my_nodes.length < 1) { @@ -306,29 +306,29 @@ $(function () { } input = $("#dashboard-node-search-input").val().toLowerCase(); - var search_result = [] + var search_result = []; var html = ''; for(var i in my_nodes) { if(my_nodes[i].name.indexOf(input) != -1) { search_result.push(my_nodes[i]); } } - for(var i=0; i<5 && i'; $("#dashboard-node-list").html(html); html = ''; - for(var i=0; i<5 && i'; $("#dashboard-node-taglist").html(html); @@ -342,7 +342,7 @@ $(function () { }); /* search for groups */ - var my_groups = [] + var my_groups = []; $("#dashboard-group-search-input").keyup(function(e) { // if my_groups is empty get a list of our groups if(my_groups.length < 1) { @@ -359,16 +359,16 @@ $(function () { } input = $("#dashboard-group-search-input").val().toLowerCase(); - var search_result = [] + var search_result = []; var html = ''; for(var i in my_groups) { if(my_groups[i].name.indexOf(input) != -1) { search_result.push(my_groups[i]); } } - for(var i=0; i<5 && i ' + safe_tags_replace(name) + '' + ' ' + host + '' + - '
' + - (fav ? '' : - '' ) + - '
' + - '
' + - ''; + '
' + + (fav ? '' : + '' ) + + '
' + + '
' + + ''; } function generateGroupHTML(url, name, is_last) { @@ -478,7 +478,7 @@ function generateNodeTagHTML(name, icon, _status, label , url) { /* copare vm-s by fav, pk order */ function compareVmByFav(a, b) { if(a.fav && b.fav) { - return a.pk < b.pk ? -1 : 1; + return a.pk < b.pk ? -1 : 1; } else if(a.fav && !b.fav) { return -1; @@ -487,13 +487,13 @@ function compareVmByFav(a, b) { return 1; } else - return a.pk < b.pk ? -1 : 1; + return a.pk < b.pk ? -1 : 1; } $(document).on('shown.bs.tab', 'a[href="#resources"]', function (e) { $(".cpu-priority-input").trigger("change"); $(".cpu-count-input, .ram-input").trigger("input"); -}) +}); function addSliderMiscs() { // set max values based on inputs @@ -524,7 +524,7 @@ function addSliderMiscs() { if(!val) return; $(".cpu-count-slider").simpleSlider("setValue", val); }); - + var ram_fire = false; $(".ram-slider").bind("slider:changed", function (event, data) { @@ -562,21 +562,21 @@ function setDefaultSliderValues() { function deleteObject(data) { $.ajax({ type: 'POST', - data: {'redirect': data['redirect']}, - url: data['url'], - headers: {"X-CSRFToken": getCookie('csrftoken')}, - success: function(re, textStatus, xhr) { - if(!data['redirect']) { + data: {'redirect': data.redirect}, + url: data.url, + headers: {"X-CSRFToken": getCookie('csrftoken')}, + success: function(re, textStatus, xhr) { + if(!data.redirect) { selected = []; - addMessage(re['message'], 'success'); + addMessage(re.message, 'success'); if(data.type === "disk") { // no need to remove them from DOM $('a[data-disk-pk="' + data.pk + '"]').parent("li").fadeOut(); $('a[data-disk-pk="' + data.pk + '"]').parent("h4").fadeOut(); - } - else { - $('a[data-'+data['type']+'-pk="' + data['pk'] + '"]').closest('tr').fadeOut(function() { - $(this).remove(); + } + else { + $('a[data-'+data.type+'-pk="' + data.pk + '"]').closest('tr').fadeOut(function() { + $(this).remove(); }); } } else { @@ -584,32 +584,33 @@ function deleteObject(data) { } }, error: function(xhr, textStatus, error) { - addMessage('Uh oh :(', 'danger') + addMessage('Uh oh :(', 'danger'); } }); } function massDeleteVm(data) { - $.ajax({ - traditional: true, - url: data['url'], - headers: {"X-CSRFToken": getCookie('csrftoken')}, - type: 'POST', - data: {'vms': data['data']['v']}, - success: function(re, textStatus, xhr) { - for(var i=0; i< data['data']['v'].length; i++) - $('.vm-list-table tbody tr[data-vm-pk="' + data['data']['v'][i] + '"]').fadeOut(500, function() { - selected = []; - // reset group buttons - $('.vm-list-group-control a').attr('disabled', true); - $(this).remove(); - }); - addMessage(re['message'], 'success'); - }, - error: function(xhr, textStatus, error) { - // TODO this - } - }); + f = function() { + selected = []; + // reset group buttons + $('.vm-list-group-control a').attr('disabled', true); + $(this).remove(); + }; + $.ajax({ + traditional: true, + url: data.url, + headers: {"X-CSRFToken": getCookie('csrftoken')}, + type: 'POST', + data: {'vms': data.data.v}, + success: function(re, textStatus, xhr) { + for(var i=0; i< data.data.v.length; i++) + $('.vm-list-table tbody tr[data-vm-pk="' + data.data.v[i] + '"]').fadeOut(500, f); + addMessage(re.message, 'success'); + }, + error: function(xhr, textStatus, error) { + // TODO this + } + }); } @@ -627,8 +628,8 @@ function addMessage(text, type) { function addModalConfirmation(func, data) { $.ajax({ type: 'GET', - url: data['url'], - data: jQuery.param(data['data']), + url: data.url, + data: jQuery.param(data.data), success: function(result) { $('body').append(result); $('#confirmation-modal').modal('show'); @@ -649,28 +650,6 @@ function clientInstalledAction(location) { $('#confirmation-modal').modal("hide"); } -// for AJAX calls -/** - * Getter for user cookies - * @param {String} name Cookie name - * @return {String} Cookie value - */ - -function getCookie(name) { - var cookieValue = null; - if (document.cookie && document.cookie != '') { - var cookies = document.cookie.split(';'); - for (var i = 0; i < cookies.length; i++) { - var cookie = jQuery.trim(cookies[i]); - if (cookie.substring(0, name.length + 1) == (name + '=')) { - cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); - break; - } - } - } - return cookieValue; -} - function setCookie(name, value, seconds, path) { if (seconds!=null) { var today = new Date(); @@ -694,6 +673,46 @@ function getParameterByName(name) { return results == null ? "" : decodeURIComponent(results[1].replace(/\+/g, " ")); } +// for AJAX calls +/** + * Getter for user cookies + * @param {String} name Cookie name + * @return {String} Cookie value + */ + +function getCookie(name) { + var cookieValue = null; + if (document.cookie && document.cookie !== '') { + var cookies = document.cookie.split(';'); + for (var i = 0; i < cookies.length; i++) { + var cookie = jQuery.trim(cookies[i]); + if (cookie.substring(0, name.length + 1) == (name + '=')) { + cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); + break; + } + } + } + return cookieValue; +} + +function csrfSafeMethod(method) { + // these HTTP methods do not require CSRF protection + return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); +} +$.ajaxSetup({ + beforeSend: function(xhr, settings) { + if (!csrfSafeMethod(settings.type) && !this.crossDomain) { + xhr.setRequestHeader("X-CSRFToken", getCookie("csrftoken")); + } + } +}); + +/* for autocomplete */ +$(function() { + yourlabs.TextWidget.prototype.getValue = function(choice) { + return choice.children().html(); + } +}); var tagsToReplace = { '&': '&', diff --git a/circle/dashboard/static/dashboard/dashboard.css b/circle/dashboard/static/dashboard/dashboard.less similarity index 91% rename from circle/dashboard/static/dashboard/dashboard.css rename to circle/dashboard/static/dashboard/dashboard.less index 1e00494..f0191cd 100644 --- a/circle/dashboard/static/dashboard/dashboard.css +++ b/circle/dashboard/static/dashboard/dashboard.less @@ -364,9 +364,11 @@ a.hover-black { display: block; } -.notification-messages { +#notification-messages { padding: 10px 8px; width: 350px; + right: 0; + left: auto; } .notification-message { @@ -375,7 +377,7 @@ a.hover-black { border-bottom: 1px dotted #D3D3D3; } -.notification-messages .notification-message:last-child { +#notification-messages .notification-message:last-child { margin-bottom: 0px; padding: 0px; border-bottom: none; @@ -390,6 +392,15 @@ a.hover-black { cursor: pointer; } +#notification-button a.dropdown-toggle { + color: white; + font-size: 12px; +} + +#notification-button { + margin-right: 15px; +} + #vm-migrate-node-list { list-style: none; } @@ -950,6 +961,48 @@ textarea[name="new_members"] { #vm-list-search, #vm-mass-ops { margin-top: 8px; } +.list-group-item-last { + border-bottom: 1px solid #ddd !important; +} + +.slider { + display: inline-block; +} +.slider .track { + height: 20px; + top: 50%; +} +.slider > .dragger, .slider > .dragger:hover { + border-radius: 0px; + -moz-border-radius: 0px; + -webkit-border-radius: 0px; + width: 8px; + height: 24px; + margin-top: -12px!important; + text-shadow: 0 1px 0 #fff; + background-image: -webkit-gradient(linear, left 0%, left 100%, from(#428bca), to(#3071a9)); + background-image: -webkit-linear-gradient(top, #428bca, 0%, #3071a9, 100%); + background-image: -moz-linear-gradient(top, #428bca 0%, #3071a9 100%); + background-image: linear-gradient(to bottom, #428bca 0%, #3071a9 100%); + background-repeat: repeat-x; + border-color: #2d6ca2; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0); +} +.slider > .dragger:hover { + background-color: #3071a9; + background-image: none; + border-color: #2d6ca2; +} +.slider > .highlight-track { + height: 20px; + top: 50%; +} +.slider > .track, .slider > .highlight-track { + border-radius: 5px; +} +.slider { + width: 100%; +} #vm-list-search-checkbox { margin-top: -1px; @@ -1051,3 +1104,50 @@ textarea[name="new_members"] { white-space: nowrap; text-align: center; } + +/* for introjs + * newer version has this fixed + * but it doesn't work w bootstrap 3.2.0 + */ +.introjs-helperLayer *, +.introjs-helperLayer *:before, +.introjs-helperLayer *:after { + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + -ms-box-sizing: content-box; + -o-box-sizing: content-box; + box-sizing: content-box; +} + +.node-list-table .monitor { + .progress { + position: relative; + width: 150px; + height: 16px; + margin-bottom: 4px; + margin-top: 0px; + background-image: linear-gradient(to bottom, #BBEBEB 0px, #F5F5F5 100%); + } + .progress-bar-text { + position: absolute; + top: -1px; + display: block; + width: 100%; + color: white; + /* outline */ + text-shadow: + -1px -1px 0 #000, + 1px -1px 0 #000, + -1px 1px 0 #000, + 1px 1px 0 #000; + font-size: 13px; + } +} + +.infobtn { + cursor: help; + + &:hover { + background-position: 0 0px; + } +} diff --git a/circle/dashboard/static/dashboard/group-details.js b/circle/dashboard/static/dashboard/group-details.js index 664619f..ac1578d 100644 --- a/circle/dashboard/static/dashboard/group-details.js +++ b/circle/dashboard/static/dashboard/group-details.js @@ -51,14 +51,14 @@ function removeMember(data) { $.ajax({ type: 'POST', - url: data['url'], + url: data.url, headers: {"X-CSRFToken": getCookie('csrftoken')}, success: function(re, textStatus, xhr) { - data['tr'].fadeOut(function() { + data.tr.fadeOut(function() { $(this).remove();}); }, error: function(xhr, textStatus, error) { - addMessage('Uh oh :(', 'danger') + addMessage('Uh oh :(', 'danger'); } }); } diff --git a/circle/dashboard/static/dashboard/group-list.js b/circle/dashboard/static/dashboard/group-list.js index d5159e5..4fec8cf 100644 --- a/circle/dashboard/static/dashboard/group-list.js +++ b/circle/dashboard/static/dashboard/group-list.js @@ -8,7 +8,7 @@ $(function() { /* rename ajax */ $('.group-list-rename-submit').click(function() { - var row = $(this).closest("tr") + var row = $(this).closest("tr"); var name = $('#group-list-rename-name', row).val(); var url = '/dashboard/group/' + row.children("td:first-child").text().replace(" ", "") + '/'; $.ajax({ @@ -17,12 +17,12 @@ $(function() { data: {'new_name': name}, headers: {"X-CSRFToken": getCookie('csrftoken')}, success: function(data, textStatus, xhr) { - + $("#group-list-column-name", row).html( $("", { 'class': "real-link", - href: "/dashboard/group/" + data['group_pk'] + "/", - text: data['new_name'] + href: "/dashboard/group/" + data.group_pk + "/", + text: data.new_name }) ).show(); $('#group-list-rename', row).hide(); diff --git a/circle/dashboard/static/dashboard/introjs/intro.min.js b/circle/dashboard/static/dashboard/introjs/intro.min.js deleted file mode 100644 index e152d52..0000000 --- a/circle/dashboard/static/dashboard/introjs/intro.min.js +++ /dev/null @@ -1,27 +0,0 @@ -(function(p,f){"object"===typeof exports?f(exports):"function"===typeof define&&define.amd?define(["exports"],f):f(p)})(this,function(p){function f(a){this._targetElement=a;this._options={nextLabel:"Next →",prevLabel:"← Back",skipLabel:"Skip",doneLabel:"Done",tooltipPosition:"bottom",tooltipClass:"",exitOnEsc:!0,exitOnOverlayClick:!0,showStepNumbers:!0,keyboardNavigation:!0,showButtons:!0,showBullets:!0,scrollToElement:!0,overlayOpacity:0.8}}function r(a){if(null==a||"object"!=typeof a|| -"undefined"!=typeof a.nodeType)return a;var b={},c;for(c in a)b[c]=r(a[c]);return b}function s(){this._direction="forward";"undefined"===typeof this._currentStep?this._currentStep=0:++this._currentStep;if(this._introItems.length<=this._currentStep)"function"===typeof this._introCompleteCallback&&this._introCompleteCallback.call(this),t.call(this,this._targetElement);else{var a=this._introItems[this._currentStep];"undefined"!==typeof this._introBeforeChangeCallback&&this._introBeforeChangeCallback.call(this, -a.element);A.call(this,a)}}function x(){this._direction="backward";if(0===this._currentStep)return!1;var a=this._introItems[--this._currentStep];"undefined"!==typeof this._introBeforeChangeCallback&&this._introBeforeChangeCallback.call(this,a.element);A.call(this,a)}function t(a){var b=a.querySelector(".introjs-overlay");if(null!=b){b.style.opacity=0;setTimeout(function(){b.parentNode&&b.parentNode.removeChild(b)},500);(a=a.querySelector(".introjs-helperLayer"))&&a.parentNode.removeChild(a);(a=document.querySelector(".introjsFloatingElement"))&& -a.parentNode.removeChild(a);if(a=document.querySelector(".introjs-showElement"))a.className=a.className.replace(/introjs-[a-zA-Z]+/g,"").replace(/^\s+|\s+$/g,"");if((a=document.querySelectorAll(".introjs-fixParent"))&&0 a.active").className="";d.querySelector('.introjs-bullets li > a[data-stepnumber="'+a.step+'"]').className="active";y.style.opacity=1;e&&(e.style.opacity=1)},350)}else{var k=document.createElement("div"),m=document.createElement("div"),j=document.createElement("div"),n=document.createElement("div"),l=document.createElement("div"),f=document.createElement("div");k.className="introjs-helperLayer";v.call(c,k);this._targetElement.appendChild(k);m.className= -"introjs-arrow";n.className="introjs-tooltiptext";n.innerHTML=a.intro;l.className="introjs-bullets";!1===this._options.showBullets&&(l.style.display="none");var p=document.createElement("ul");b=0;for(var u=this._introItems.length;bj)b.className+=" introjs-fixParent";b=b.parentNode}b=a.element.getBoundingClientRect();!(0<=b.top&&0<=b.left&&b.bottom+80<=window.innerHeight&&b.right<=window.innerWidth)&&!0===this._options.scrollToElement&&(j=a.element.getBoundingClientRect(),b=void 0!=window.innerWidth?window.innerHeight:document.documentElement.clientHeight,m=j.bottom-(j.bottom-j.top),j=j.bottom-b,0>m||a.element.clientHeight>b?window.scrollBy(0,m-30):window.scrollBy(0, -j+100));"undefined"!==typeof this._introAfterChangeCallback&&this._introAfterChangeCallback.call(this,a.element)}function z(a,b){var c="";a.currentStyle?c=a.currentStyle[b]:document.defaultView&&document.defaultView.getComputedStyle&&(c=document.defaultView.getComputedStyle(a,null).getPropertyValue(b));return c&&c.toLowerCase?c.toLowerCase():c}function D(a){var b=document.createElement("div"),c="",d=this;b.className="introjs-overlay";if("body"===a.tagName.toLowerCase())c+="top: 0;bottom: 0; left: 0;right: 0;position: fixed;", -b.setAttribute("style",c);else{var e=h(a);e&&(c+="width: "+e.width+"px; height:"+e.height+"px; top:"+e.top+"px;left: "+e.left+"px;",b.setAttribute("style",c))}a.appendChild(b);b.onclick=function(){!0==d._options.exitOnOverlayClick&&(t.call(d,a),void 0!=d._introExitCallback&&d._introExitCallback.call(d))};setTimeout(function(){c+="opacity: "+d._options.overlayOpacity.toString()+";";b.setAttribute("style",c)},10);return!0}function h(a){var b={};b.width=a.offsetWidth;b.height=a.offsetHeight;for(var c= -0,d=0;a&&!isNaN(a.offsetLeft)&&!isNaN(a.offsetTop);)c+=a.offsetLeft,d+=a.offsetTop,a=a.offsetParent;b.top=d;b.left=c;return b}var u=function(a){if("object"===typeof a)return new f(a);if("string"===typeof a){if(a=document.querySelector(a))return new f(a);throw Error("There is no element with given selector.");}return new f(document.body)};u.version="0.9.0";u.fn=f.prototype={clone:function(){return new f(this)},setOption:function(a,b){this._options[a]=b;return this},setOptions:function(a){var b=this._options, -c={},d;for(d in b)c[d]=b[d];for(d in a)c[d]=a[d];this._options=c;return this},start:function(){a:{var a=this._targetElement,b=[],c=this;if(this._options.steps)for(var d=[],e=0,d=this._options.steps.length;ed.length)break a;e=0;for(f=d.length;etd,tr.introjs-showElement>th{z-index:9999999 !important}.introjs-relativePosition,tr.introjs-showElement>td,tr.introjs-showElement>th{position:relative}.introjs-helperLayer{position:absolute;z-index:9999998;background-color:#FFF;background-color:rgba(255,255,255,.9);border:1px solid #777;border:1px solid rgba(0,0,0,.5);border-radius:4px;box-shadow:0 2px 15px rgba(0,0,0,.4);-webkit-transition:all .3s ease-out;-moz-transition:all .3s ease-out;-ms-transition:all .3s ease-out;-o-transition:all .3s ease-out;transition:all .3s ease-out}.introjs-helperNumberLayer{position:absolute;top:-16px;left:-16px;z-index:9999999999 !important;padding:2px;font-family:Arial,verdana,tahoma;font-size:13px;font-weight:bold;color:white;text-align:center;text-shadow:1px 1px 1px rgba(0,0,0,.3);background:#ff3019;background:-webkit-linear-gradient(top,#ff3019 0,#cf0404 100%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0%,#ff3019),color-stop(100%,#cf0404));background:-moz-linear-gradient(top,#ff3019 0,#cf0404 100%);background:-ms-linear-gradient(top,#ff3019 0,#cf0404 100%);background:-o-linear-gradient(top,#ff3019 0,#cf0404 100%);background:linear-gradient(to bottom,#ff3019 0,#cf0404 100%);width:20px;height:20px;line-height:20px;border:3px solid white;border-radius:50%;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3019',endColorstr='#cf0404',GradientType=0);filter:progid:DXImageTransform.Microsoft.Shadow(direction=135,strength=2,color=ff0000);box-shadow:0 2px 5px rgba(0,0,0,.4)}.introjs-arrow{border:5px solid white;content:'';position:absolute}.introjs-arrow.top{top:-10px;border-top-color:transparent;border-right-color:transparent;border-bottom-color:white;border-left-color:transparent}.introjs-arrow.top-right{top:-10px;right:10px;border-top-color:transparent;border-right-color:transparent;border-bottom-color:white;border-left-color:transparent}.introjs-arrow.top-middle{top:-10px;left:50%;margin-left:-5px;border-top-color:transparent;border-right-color:transparent;border-bottom-color:white;border-left-color:transparent}.introjs-arrow.right{right:-10px;top:10px;border-top-color:transparent;border-right-color:transparent;border-bottom-color:transparent;border-left-color:white}.introjs-arrow.bottom{bottom:-10px;border-top-color:white;border-right-color:transparent;border-bottom-color:transparent;border-left-color:transparent}.introjs-arrow.left{left:-10px;top:10px;border-top-color:transparent;border-right-color:white;border-bottom-color:transparent;border-left-color:transparent}.introjs-tooltip{position:absolute;padding:10px;background-color:white;min-width:200px;max-width:300px;border-radius:3px;box-shadow:0 1px 10px rgba(0,0,0,.4);-webkit-transition:opacity .1s ease-out;-moz-transition:opacity .1s ease-out;-ms-transition:opacity .1s ease-out;-o-transition:opacity .1s ease-out;transition:opacity .1s ease-out}.introjs-tooltipbuttons{text-align:right}.introjs-button{position:relative;overflow:visible;display:inline-block;padding:.3em .8em;border:1px solid #d4d4d4;margin:0;text-decoration:none;text-shadow:1px 1px 0 #fff;font:11px/normal sans-serif;color:#333;white-space:nowrap;cursor:pointer;outline:0;background-color:#ececec;background-image:-webkit-gradient(linear,0 0,0 100%,from(#f4f4f4),to(#ececec));background-image:-moz-linear-gradient(#f4f4f4,#ececec);background-image:-o-linear-gradient(#f4f4f4,#ececec);background-image:linear-gradient(#f4f4f4,#ececec);-webkit-background-clip:padding;-moz-background-clip:padding;-o-background-clip:padding-box;-webkit-border-radius:.2em;-moz-border-radius:.2em;border-radius:.2em;zoom:1;*display:inline;margin-top:10px}.introjs-button:hover{border-color:#bcbcbc;text-decoration:none;box-shadow:0 1px 1px #e3e3e3}.introjs-button:focus,.introjs-button:active{background-image:-webkit-gradient(linear,0 0,0 100%,from(#ececec),to(#f4f4f4));background-image:-moz-linear-gradient(#ececec,#f4f4f4);background-image:-o-linear-gradient(#ececec,#f4f4f4);background-image:linear-gradient(#ececec,#f4f4f4)}.introjs-button::-moz-focus-inner{padding:0;border:0}.introjs-skipbutton{margin-right:5px;color:#7a7a7a}.introjs-prevbutton{-webkit-border-radius:.2em 0 0 .2em;-moz-border-radius:.2em 0 0 .2em;border-radius:.2em 0 0 .2em;border-right:0}.introjs-nextbutton{-webkit-border-radius:0 .2em .2em 0;-moz-border-radius:0 .2em .2em 0;border-radius:0 .2em .2em 0}.introjs-disabled,.introjs-disabled:hover,.introjs-disabled:focus{color:#9a9a9a;border-color:#d4d4d4;box-shadow:none;cursor:default;background-color:#f4f4f4;background-image:none;text-decoration:none}.introjs-bullets{text-align:center}.introjs-bullets ul{clear:both;margin:15px auto 0;padding:0;display:inline-block}.introjs-bullets ul li{list-style:none;float:left;margin:0 2px}.introjs-bullets ul li a{display:block;width:6px;height:6px;background:#ccc;border-radius:10px;-moz-border-radius:10px;-webkit-border-radius:10px;text-decoration:none}.introjs-bullets ul li a:hover{background:#999}.introjs-bullets ul li a.active{background:#999}.introjsFloatingElement{position:absolute;height:0;width:0;left:50%;top:50%} - - -.introjs-helperLayer *, -.introjs-helperLayer *:before, -.introjs-helperLayer *:after { - -webkit-box-sizing: content-box; - -moz-box-sizing: content-box; - -ms-box-sizing: content-box; - -o-box-sizing: content-box; - box-sizing: content-box; -} diff --git a/circle/dashboard/static/dashboard/js/jquery.knob.js b/circle/dashboard/static/dashboard/js/jquery.knob.js deleted file mode 100644 index ae36b6b..0000000 --- a/circle/dashboard/static/dashboard/js/jquery.knob.js +++ /dev/null @@ -1,685 +0,0 @@ -/*!jQuery Knob*/ -/** - * Downward compatible, touchable dial - * - * Version: 1.2.0 (15/07/2012) - * Requires: jQuery v1.7+ - * - * Copyright (c) 2012 Anthony Terrien - * Under MIT and GPL licenses: - * http://www.opensource.org/licenses/mit-license.php - * http://www.gnu.org/licenses/gpl.html - * - * Thanks to vor, eskimoblood, spiffistan, FabrizioC - */ -(function($) { - - /** - * Kontrol library - */ - "use strict"; - - /** - * Definition of globals and core - */ - var k = {}, // kontrol - max = Math.max, - min = Math.min; - - k.c = {}; - k.c.d = $(document); - k.c.t = function (e) { - return e.originalEvent.touches.length - 1; - }; - - /** - * Kontrol Object - * - * Definition of an abstract UI control - * - * Each concrete component must call this one. - * - * k.o.call(this); - * - */ - k.o = function () { - var s = this; - - this.o = null; // array of options - this.$ = null; // jQuery wrapped element - this.i = null; // mixed HTMLInputElement or array of HTMLInputElement - this.g = null; // 2D graphics context for 'pre-rendering' - this.v = null; // value ; mixed array or integer - this.cv = null; // change value ; not commited value - this.x = 0; // canvas x position - this.y = 0; // canvas y position - this.$c = null; // jQuery canvas element - this.c = null; // rendered canvas context - this.t = 0; // touches index - this.isInit = false; - this.fgColor = null; // main color - this.pColor = null; // previous color - this.dH = null; // draw hook - this.cH = null; // change hook - this.eH = null; // cancel hook - this.rH = null; // release hook - this.scale = 1; // scale factor - - this.run = function () { - var cf = function (e, conf) { - var k; - for (k in conf) { - s.o[k] = conf[k]; - } - s.init(); - s._configure() - ._draw(); - }; - - if(this.$.data('kontroled')) return; - this.$.data('kontroled', true); - - this.extend(); - this.o = $.extend( - { - // Config - min : this.$.data('min') || 0, - max : this.$.data('max') || 100, - stopper : true, - readOnly : this.$.data('readonly'), - - // UI - cursor : (this.$.data('cursor') === true && 30) - || this.$.data('cursor') - || 0, - thickness : this.$.data('thickness') || 0.35, - lineCap : this.$.data('linecap') || 'butt', - width : this.$.data('width') || 200, - height : this.$.data('height') || 200, - displayInput : this.$.data('displayinput') == null || this.$.data('displayinput'), - displayPrevious : this.$.data('displayprevious'), - fgColor : this.$.data('fgcolor') || '#87CEEB', - inputColor: this.$.data('inputcolor') || this.$.data('fgcolor') || '#87CEEB', - inline : false, - step : this.$.data('step') || 1, - - // Hooks - draw : null, // function () {} - change : null, // function (value) {} - cancel : null, // function () {} - release : null, // function (value) {} - error : null // function () {} - }, this.o - ); - - // routing value - if(this.$.is('fieldset')) { - - // fieldset = array of integer - this.v = {}; - this.i = this.$.find('input') - this.i.each(function(k) { - var $this = $(this); - s.i[k] = $this; - s.v[k] = $this.val(); - - $this.bind( - 'change' - , function () { - var val = {}; - val[k] = $this.val(); - s.val(val); - } - ); - }); - this.$.find('legend').remove(); - - } else { - // input = integer - this.i = this.$; - this.v = this.$.val(); - (this.v == '') && (this.v = this.o.min); - - this.$.bind( - 'change' - , function () { - s.val(s._validate(s.$.val())); - } - ); - } - - (!this.o.displayInput) && this.$.hide(); - - this.$c = $(''); - - this.c = this.$c[0].getContext? this.$c[0].getContext('2d') : null; - - if (!this.c) { - this.o.error && this.o.error(); - return; - } - - this.$ - .wrap($('
')) - .before(this.$c); - - this.scale = (window.devicePixelRatio || 1) / - ( - this.c.webkitBackingStorePixelRatio || - this.c.mozBackingStorePixelRatio || - this.c.msBackingStorePixelRatio || - this.c.oBackingStorePixelRatio || - this.c.backingStorePixelRatio || 1 - ); - if (this.scale !== 1) { - this.$c[0].width = this.$c[0].width * this.scale; - this.$c[0].height = this.$c[0].height * this.scale; - this.$c.width(this.o.width); - this.$c.height(this.o.height); - } - - if (this.v instanceof Object) { - this.cv = {}; - this.copy(this.v, this.cv); - } else { - this.cv = this.v; - } - - this.$ - .bind("configure", cf) - .parent() - .bind("configure", cf); - - this._listen() - ._configure() - ._xy() - .init(); - - this.isInit = true; - - this._draw(); - - return this; - }; - - this._draw = function () { - - // canvas pre-rendering - var d = true, - c = document.createElement('canvas'); - - c.width = s.o.width * s.scale; - c.height = s.o.height * s.scale; - - s.g = c.getContext('2d'); - - s.clear(); - - s.dH - && (d = s.dH()); - - (d !== false) && s.draw(); - - s.c.drawImage(c, 0, 0); - c = null; - }; - - this._touch = function (e) { - - var touchMove = function (e) { - - var v = s.xy2val( - e.originalEvent.touches[s.t].pageX, - e.originalEvent.touches[s.t].pageY - ); - - if (v == s.cv) return; - - if ( - s.cH - && (s.cH(v) === false) - ) return; - - - s.change(s._validate(v)); - s._draw(); - }; - - // get touches index - this.t = k.c.t(e); - - // First touch - touchMove(e); - - // Touch events listeners - k.c.d - .bind("touchmove.k", touchMove) - .bind( - "touchend.k" - , function () { - k.c.d.unbind('touchmove.k touchend.k'); - - if ( - s.rH - && (s.rH(s.cv) === false) - ) return; - - s.val(s.cv); - } - ); - - return this; - }; - - this._mouse = function (e) { - - var mouseMove = function (e) { - var v = s.xy2val(e.pageX, e.pageY); - if (v == s.cv) return; - - if ( - s.cH - && (s.cH(v) === false) - ) return; - - s.change(s._validate(v)); - s._draw(); - }; - - // First click - mouseMove(e); - - // Mouse events listeners - k.c.d - .bind("mousemove.k", mouseMove) - .bind( - // Escape key cancel current change - "keyup.k" - , function (e) { - if (e.keyCode === 27) { - k.c.d.unbind("mouseup.k mousemove.k keyup.k"); - - if ( - s.eH - && (s.eH() === false) - ) return; - - s.cancel(); - } - } - ) - .bind( - "mouseup.k" - , function (e) { - k.c.d.unbind('mousemove.k mouseup.k keyup.k'); - - if ( - s.rH - && (s.rH(s.cv) === false) - ) return; - - s.val(s.cv); - } - ); - - return this; - }; - - this._xy = function () { - var o = this.$c.offset(); - this.x = o.left; - this.y = o.top; - return this; - }; - - this._listen = function () { - - if (!this.o.readOnly) { - this.$c - .bind( - "mousedown" - , function (e) { - e.preventDefault(); - s._xy()._mouse(e); - } - ) - .bind( - "touchstart" - , function (e) { - e.preventDefault(); - s._xy()._touch(e); - } - ); - this.listen(); - } else { - this.$.attr('readonly', 'readonly'); - } - - return this; - }; - - this._configure = function () { - - // Hooks - if (this.o.draw) this.dH = this.o.draw; - if (this.o.change) this.cH = this.o.change; - if (this.o.cancel) this.eH = this.o.cancel; - if (this.o.release) this.rH = this.o.release; - - if (this.o.displayPrevious) { - this.pColor = this.h2rgba(this.o.fgColor, "0.4"); - this.fgColor = this.h2rgba(this.o.fgColor, "0.6"); - } else { - this.fgColor = this.o.fgColor; - } - - return this; - }; - - this._clear = function () { - this.$c[0].width = this.$c[0].width; - }; - - this._validate = function(v) { - return (~~ (((v < 0) ? -0.5 : 0.5) + (v/this.o.step))) * this.o.step; - }; - - // Abstract methods - this.listen = function () {}; // on start, one time - this.extend = function () {}; // each time configure triggered - this.init = function () {}; // each time configure triggered - this.change = function (v) {}; // on change - this.val = function (v) {}; // on release - this.xy2val = function (x, y) {}; // - this.draw = function () {}; // on change / on release - this.clear = function () { this._clear(); }; - - // Utils - this.h2rgba = function (h, a) { - var rgb; - h = h.substring(1,7) - rgb = [parseInt(h.substring(0,2),16) - ,parseInt(h.substring(2,4),16) - ,parseInt(h.substring(4,6),16)]; - return "rgba(" + rgb[0] + "," + rgb[1] + "," + rgb[2] + "," + a + ")"; - }; - - this.copy = function (f, t) { - for (var i in f) { t[i] = f[i]; } - }; - }; - - - /** - * k.Dial - */ - k.Dial = function () { - k.o.call(this); - - this.startAngle = null; - this.xy = null; - this.radius = null; - this.lineWidth = null; - this.cursorExt = null; - this.w2 = null; - this.PI2 = 2*Math.PI; - - this.extend = function () { - this.o = $.extend( - { - bgColor : this.$.data('bgcolor') || '#EEEEEE', - angleOffset : this.$.data('angleoffset') || 0, - angleArc : this.$.data('anglearc') || 360, - inline : true - }, this.o - ); - }; - - this.val = function (v) { - if (null != v) { - this.cv = this.o.stopper ? max(min(v, this.o.max), this.o.min) : v; - this.v = this.cv; - this.$.val(this.v); - this._draw(); - } else { - return this.v; - } - }; - - this.xy2val = function (x, y) { - var a, ret; - - a = Math.atan2( - x - (this.x + this.w2) - , - (y - this.y - this.w2) - ) - this.angleOffset; - - if(this.angleArc != this.PI2 && (a < 0) && (a > -0.5)) { - // if isset angleArc option, set to min if .5 under min - a = 0; - } else if (a < 0) { - a += this.PI2; - } - - ret = ~~ (0.5 + (a * (this.o.max - this.o.min) / this.angleArc)) - + this.o.min; - - this.o.stopper - && (ret = max(min(ret, this.o.max), this.o.min)); - - return ret; - }; - - this.listen = function () { - // bind MouseWheel - var s = this, - mw = function (e) { - e.preventDefault(); - var ori = e.originalEvent - ,deltaX = ori.detail || ori.wheelDeltaX - ,deltaY = ori.detail || ori.wheelDeltaY - ,v = parseInt(s.$.val()) + (deltaX>0 || deltaY>0 ? s.o.step : deltaX<0 || deltaY<0 ? -s.o.step : 0); - - if ( - s.cH - && (s.cH(v) === false) - ) return; - - s.val(v); - } - , kval, to, m = 1, kv = {37:-s.o.step, 38:s.o.step, 39:s.o.step, 40:-s.o.step}; - - this.$ - .bind( - "keydown" - ,function (e) { - var kc = e.keyCode; - - // numpad support - if(kc >= 96 && kc <= 105) { - kc = e.keyCode = kc - 48; - } - - kval = parseInt(String.fromCharCode(kc)); - - if (isNaN(kval)) { - - (kc !== 13) // enter - && (kc !== 8) // bs - && (kc !== 9) // tab - && (kc !== 189) // - - && e.preventDefault(); - - // arrows - if ($.inArray(kc,[37,38,39,40]) > -1) { - e.preventDefault(); - - var v = parseInt(s.$.val()) + kv[kc] * m; - - s.o.stopper - && (v = max(min(v, s.o.max), s.o.min)); - - s.change(v); - s._draw(); - - // long time keydown speed-up - to = window.setTimeout( - function () { m*=2; } - ,30 - ); - } - } - } - ) - .bind( - "keyup" - ,function (e) { - if (isNaN(kval)) { - if (to) { - window.clearTimeout(to); - to = null; - m = 1; - s.val(s.$.val()); - } - } else { - // kval postcond - (s.$.val() > s.o.max && s.$.val(s.o.max)) - || (s.$.val() < s.o.min && s.$.val(s.o.min)); - } - - } - ); - - this.$c.bind("mousewheel DOMMouseScroll", mw); - this.$.bind("mousewheel DOMMouseScroll", mw) - }; - - this.init = function () { - - if ( - this.v < this.o.min - || this.v > this.o.max - ) this.v = this.o.min; - - this.$.val(this.v); - this.w2 = this.o.width / 2; - this.cursorExt = this.o.cursor / 100; - this.xy = this.w2 * this.scale; - this.lineWidth = this.xy * this.o.thickness; - this.lineCap = this.o.lineCap; - this.radius = this.xy - this.lineWidth / 2; - - this.o.angleOffset - && (this.o.angleOffset = isNaN(this.o.angleOffset) ? 0 : this.o.angleOffset); - - this.o.angleArc - && (this.o.angleArc = isNaN(this.o.angleArc) ? this.PI2 : this.o.angleArc); - - // deg to rad - this.angleOffset = this.o.angleOffset * Math.PI / 180; - this.angleArc = this.o.angleArc * Math.PI / 180; - - // compute start and end angles - this.startAngle = 1.5 * Math.PI + this.angleOffset; - this.endAngle = 1.5 * Math.PI + this.angleOffset + this.angleArc; - - var s = max( - String(Math.abs(this.o.max)).length - , String(Math.abs(this.o.min)).length - , 2 - ) + 2; - - this.o.displayInput - && this.i.css({ - 'width' : ((this.o.width / 2 + 4) >> 0) + 'px' - ,'height' : ((this.o.width / 3) >> 0) + 'px' - ,'position' : 'absolute' - ,'vertical-align' : 'middle' - ,'margin-top' : ((this.o.width / 3) >> 0) + 'px' - ,'margin-left' : '-' + ((this.o.width * 3 / 4 + 2) >> 0) + 'px' - ,'border' : 0 - ,'background' : 'none' - ,'font' : 'bold ' + ((this.o.width / s) >> 0) + 'px Arial' - ,'text-align' : 'center' - ,'color' : this.o.inputColor || this.o.fgColor - ,'padding' : '0px' - ,'-webkit-appearance': 'none' - }) - || this.i.css({ - 'width' : '0px' - ,'visibility' : 'hidden' - }); - }; - - this.change = function (v) { - this.cv = v; - this.$.val(v); - }; - - this.angle = function (v) { - return (v - this.o.min) * this.angleArc / (this.o.max - this.o.min); - }; - - this.draw = function () { - - var c = this.g, // context - a = this.angle(this.cv) // Angle - , sat = this.startAngle // Start angle - , eat = sat + a // End angle - , sa, ea // Previous angles - , r = 1; - - c.lineWidth = this.lineWidth; - - c.lineCap = this.lineCap; - - this.o.cursor - && (sat = eat - this.cursorExt) - && (eat = eat + this.cursorExt); - - c.beginPath(); - c.strokeStyle = this.o.bgColor; - c.arc(this.xy, this.xy, this.radius, this.endAngle, this.startAngle, true); - c.stroke(); - - if (this.o.displayPrevious) { - ea = this.startAngle + this.angle(this.v); - sa = this.startAngle; - this.o.cursor - && (sa = ea - this.cursorExt) - && (ea = ea + this.cursorExt); - - c.beginPath(); - c.strokeStyle = this.pColor; - c.arc(this.xy, this.xy, this.radius, sa, ea, false); - c.stroke(); - r = (this.cv == this.v); - } - - c.beginPath(); - c.strokeStyle = r ? this.o.fgColor : this.fgColor ; - c.arc(this.xy, this.xy, this.radius, sat, eat, false); - c.stroke(); - }; - - this.cancel = function () { - this.val(this.v); - }; - }; - - $.fn.dial = $.fn.knob = function (o) { - return this.each( - function () { - var d = new k.Dial(); - d.o = o; - d.$ = $(this); - d.run(); - } - ).parent(); - }; - -})(jQuery); \ No newline at end of file diff --git a/circle/dashboard/static/dashboard/loopj-jquery-simple-slider/css/simple-slider.css b/circle/dashboard/static/dashboard/loopj-jquery-simple-slider/css/simple-slider.css deleted file mode 100644 index 953ebf2..0000000 --- a/circle/dashboard/static/dashboard/loopj-jquery-simple-slider/css/simple-slider.css +++ /dev/null @@ -1,102 +0,0 @@ -.slider { - width: 300px; -} - -.slider > .dragger { - background: #8DCA09; - background: -webkit-linear-gradient(top, #8DCA09, #72A307); - background: -moz-linear-gradient(top, #8DCA09, #72A307); - background: linear-gradient(top, #8DCA09, #72A307); - - -webkit-box-shadow: inset 0 2px 2px rgba(255,255,255,0.5), 0 2px 8px rgba(0,0,0,0.2); - -moz-box-shadow: inset 0 2px 2px rgba(255,255,255,0.5), 0 2px 8px rgba(0,0,0,0.2); - box-shadow: inset 0 2px 2px rgba(255,255,255,0.5), 0 2px 8px rgba(0,0,0,0.2); - - -webkit-border-radius: 10px; - -moz-border-radius: 10px; - border-radius: 10px; - - border: 1px solid #496805; - width: 16px; - height: 16px; -} - -.slider > .dragger:hover { - background: -webkit-linear-gradient(top, #8DCA09, #8DCA09); -} - - -.slider > .track, .slider > .highlight-track { - background: #ccc; - background: -webkit-linear-gradient(top, #bbb, #ddd); - background: -moz-linear-gradient(top, #bbb, #ddd); - background: linear-gradient(top, #bbb, #ddd); - - -webkit-box-shadow: inset 0 2px 4px rgba(0,0,0,0.1); - -moz-box-shadow: inset 0 2px 4px rgba(0,0,0,0.1); - box-shadow: inset 0 2px 4px rgba(0,0,0,0.1); - - -webkit-border-radius: 8px; - -moz-border-radius: 8px; - border-radius: 8px; - - border: 1px solid #aaa; - height: 4px; -} - -.slider > .highlight-track { - background-color: #8DCA09; - background: -webkit-linear-gradient(top, #8DCA09, #72A307); - background: -moz-linear-gradient(top, #8DCA09, #72A307); - background: linear-gradient(top, #8DCA09, #72A307); - - border-color: #496805; -} - - - -.slider { - display: inline-block; -} -.slider .track { - height: 20px; - top: 50%; -} -.slider > .dragger, .slider > .dragger:hover { - border-radius: 0px; - -moz-border-radius: 0px; - -webkit-border-radius: 0px; - width: 8px; - height: 24px; - margin-top: -12px!important; - text-shadow: 0 1px 0 #fff; - background-image: -webkit-gradient(linear, left 0%, left 100%, from(#428bca), to(#3071a9)); - background-image: -webkit-linear-gradient(top, #428bca, 0%, #3071a9, 100%); - background-image: -moz-linear-gradient(top, #428bca 0%, #3071a9 100%); - background-image: linear-gradient(to bottom, #428bca 0%, #3071a9 100%); - background-repeat: repeat-x; - border-color: #2d6ca2; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0); -} -.slider > .dragger:hover { - background-color: #3071a9; - background-image: none; - border-color: #2d6ca2; -} - -.slider > .highlight-track { - height: 20px; - top: 50%; -} -.slider + .output { - -} - -.slider > .track, .slider > .highlight-track { -border-radius: 5px; -} - -/* review this later */ -.slider { - width: 100%; -} diff --git a/circle/dashboard/static/dashboard/loopj-jquery-simple-slider/js/simple-slider.js b/circle/dashboard/static/dashboard/loopj-jquery-simple-slider/js/simple-slider.js deleted file mode 100644 index 2592270..0000000 --- a/circle/dashboard/static/dashboard/loopj-jquery-simple-slider/js/simple-slider.js +++ /dev/null @@ -1,407 +0,0 @@ -/* - jQuery Simple Slider - - Copyright (c) 2012, 2013 James Smith (http://loopj.com) - Copyright (c) 2013 Maarten van Grootel (http://maatenvangrootel.nl) - Copyright (c) 2013 Nathan Hunzaker (http://natehunzaker.com) - Copyright (c) 2013 Erik J. Nedwidek (http://github.com/nedwidek) - - Licensed under the MIT license (http://mit-license.org/) -*/ - -var __slice = [].slice, - __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; - -(function($, window) { - var SimpleSlider; - SimpleSlider = (function() { - - function SimpleSlider(input, options) { - var ratio, - _this = this; - this.input = input; - this.defaultOptions = { - animate: true, - snapMid: false, - classPrefix: null, - classSuffix: null, - theme: null, - highlight: false, - showScale: false - }; - if(typeof options == 'undefined') { - options = this.loadDataOptions(); - } - this.settings = $.extend({}, this.defaultOptions, options); - if (this.settings.theme) { - this.settings.classSuffix = "-" + this.settings.theme; - } - this.input.hide(); - this.slider = $("
").addClass("slider" + (this.settings.classSuffix || "")).css({ - position: "relative", - userSelect: "none", - boxSizing: "border-box" - }).insertBefore(this.input); - if (this.input.attr("id")) { - this.slider.attr("id", this.input.attr("id") + "-slider"); - } - this.track = this.createDivElement("track").css({ - width: "100%" - }); - if (this.settings.highlight) { - this.highlightTrack = this.createDivElement("highlight-track").css({ - width: "0" - }); - } - this.dragger = this.createDivElement("dragger"); - this.slider.css({ - minHeight: this.dragger.outerHeight(), - marginLeft: this.dragger.outerWidth() / 2, - marginRight: this.dragger.outerWidth() / 2 - }); - this.track.css({ - marginTop: this.track.outerHeight() / -2 - }); - if (this.settings.highlight) { - this.highlightTrack.css({ - marginTop: this.track.outerHeight() / -2 - }); - } - this.dragger.css({ - marginTop: this.dragger.outerWidth() / -2, - marginLeft: this.dragger.outerWidth() / -2 - }); - this.track.mousedown(function(e) { - return _this.trackEvent(e); - }); - if (this.settings.highlight) { - this.highlightTrack.mousedown(function(e) { - return _this.trackEvent(e); - }); - } - this.dragger.mousedown(function(e) { - if (e.which !== 1 || _this.settings.disabled) { - return; - } - _this.dragging = true; - _this.dragger.addClass("dragging"); - _this.domDrag(e.pageX, e.pageY); - return false; - }); - $("body").mousemove(function(e) { - if (_this.dragging) { - _this.domDrag(e.pageX, e.pageY); - return $("body").css({ - cursor: "pointer" - }); - } - }).mouseup(function(e) { - if (_this.dragging) { - _this.dragging = false; - _this.dragger.removeClass("dragging"); - return $("body").css({ - cursor: "auto" - }); - } - }); - this.pagePos = 0; - if (this.input.val() === "") { - this.value = this.getRange().min; - this.input.val(this.value); - } else { - this.value = this.nearestValidValue(this.input.val()); - } - this.setSliderPositionFromValue(this.value); - ratio = this.valueToRatio(this.value); - if (this.settings.showScale) { - this.scale = this.createDivElement("scale"); - this.minScale = this.createSpanElement("min-scale", this.scale); - this.maxScale = this.createSpanElement("max-scale", this.scale); - - range = this.getRange(); - - this.minScale.html(range.min); - this.maxScale.html(range.max); - - this.scale.css('marginTop', function(index, currentValue) { - return (parseInt(currentValue, 10) + this.previousSibling.offsetHeight / 2) + 'px'; - }); - } - this.input.trigger("slider:ready", { - value: this.value, - ratio: ratio, - position: ratio * this.slider.outerWidth(), - el: this.slider - }); - } - - SimpleSlider.prototype.loadDataOptions = function() { - var options = {}; - allowedValues = this.input.data("slider-values"); - if (allowedValues) { - options.allowedValues = (function() { - var _i, _len, _ref, _results; - _ref = allowedValues.split(","); - _results = []; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - x = _ref[_i]; - _results.push(parseFloat(x)); - } - return _results; - })(); - } - if (this.input.data("slider-range")) { - options.range = this.input.data("slider-range").split(","); - } - if (this.input.data("slider-step")) { - options.step = this.input.data("slider-step"); - } - options.snap = this.input.data("slider-snap"); - options.equalSteps = this.input.data("slider-equal-steps"); - if (this.input.data("slider-theme")) { - options.theme = this.input.data("slider-theme"); - } - if (this.input.attr("data-slider-highlight")) { - options.highlight = this.input.data("slider-highlight"); - } - if (this.input.data("slider-animate") != null) { - options.animate = this.input.data("slider-animate"); - } - if (this.input.data("slider-showscale") != null) { - options.showScale = this.input.data("slider-showscale"); - } - if (this.input.data("slider-disabled")) { - options.disabled = this.input.data("slider-disabled"); - } - return options; - } - - SimpleSlider.prototype.createDivElement = function(classname) { - var item; - item = $("
").addClass(classname).css({ - position: "absolute", - top: "50%", - userSelect: "none", - cursor: "pointer" - }).appendTo(this.slider); - return item; - }; - - SimpleSlider.prototype.createSpanElement = function(classname, parent) { - var item; - item = $("").addClass(classname).appendTo(parent); - return item; - }; - - SimpleSlider.prototype.setRatio = function(ratio) { - var value; - ratio = Math.min(1, ratio); - ratio = Math.max(0, ratio); - value = this.ratioToValue(ratio); - this.setSliderPositionFromValue(value); - return this.valueChanged(value, ratio, "setRatio"); - }; - - SimpleSlider.prototype.setValue = function(value) { - var ratio; - value = this.nearestValidValue(value); - ratio = this.valueToRatio(value); - this.setSliderPositionFromValue(value); - return this.valueChanged(value, ratio, "setValue"); - }; - - SimpleSlider.prototype.setDisabled = function(value) { - this.settings.disabled = value; - } - - SimpleSlider.prototype.trackEvent = function(e) { - if (e.which !== 1 || this.settings.disabled) { - return; - } - this.domDrag(e.pageX, e.pageY, true); - this.dragging = true; - return false; - }; - - SimpleSlider.prototype.domDrag = function(pageX, pageY, animate) { - var pagePos, ratio, value; - if (animate == null) { - animate = false; - } - pagePos = pageX - this.slider.offset().left; - pagePos = Math.min(this.slider.outerWidth(), pagePos); - pagePos = Math.max(0, pagePos); - if (this.pagePos !== pagePos) { - this.pagePos = pagePos; - ratio = pagePos / this.slider.outerWidth(); - value = this.ratioToValue(ratio); - this.valueChanged(value, ratio, "domDrag"); - if (this.settings.snap) { - return this.setSliderPositionFromValue(value, animate); - } else { - return this.setSliderPosition(pagePos, animate); - } - } - }; - - SimpleSlider.prototype.setSliderPosition = function(position, animate) { - if (animate == null) { - animate = false; - } - if (animate && this.settings.animate) { - this.dragger.animate({ - left: position - }, 200); - if (this.settings.highlight) { - return this.highlightTrack.animate({ - width: position - }, 200); - } - } else { - this.dragger.css({ - left: position - }); - if (this.settings.highlight) { - return this.highlightTrack.css({ - width: position - }); - } - } - }; - - SimpleSlider.prototype.setSliderPositionFromValue = function(value, animate) { - var ratio; - if (animate == null) { - animate = false; - } - ratio = this.valueToRatio(value); - return this.setSliderPosition(ratio * this.slider.outerWidth(), animate); - }; - - SimpleSlider.prototype.getRange = function() { - if (this.settings.allowedValues) { - return { - min: Math.min.apply(Math, this.settings.allowedValues), - max: Math.max.apply(Math, this.settings.allowedValues) - }; - } else if (this.settings.range) { - return { - min: parseFloat(this.settings.range[0]), - max: parseFloat(this.settings.range[1]) - }; - } else { - return { - min: 0, - max: 1 - }; - } - }; - - SimpleSlider.prototype.nearestValidValue = function(rawValue) { - var closest, maxSteps, range, steps; - range = this.getRange(); - rawValue = Math.min(range.max, rawValue); - rawValue = Math.max(range.min, rawValue); - if (this.settings.allowedValues) { - closest = null; - $.each(this.settings.allowedValues, function() { - if (closest === null || Math.abs(this - rawValue) < Math.abs(closest - rawValue)) { - return closest = this; - } - }); - return closest; - } else if (this.settings.step) { - maxSteps = (range.max - range.min) / this.settings.step; - steps = Math.floor((rawValue - range.min) / this.settings.step); - if ((rawValue - range.min) % this.settings.step > this.settings.step / 2 && steps < maxSteps) { - steps += 1; - } - return steps * this.settings.step + range.min; - } else { - return rawValue; - } - }; - - SimpleSlider.prototype.valueToRatio = function(value) { - var allowedVal, closest, closestIdx, idx, range, _i, _len, _ref; - if (this.settings.equalSteps) { - _ref = this.settings.allowedValues; - for (idx = _i = 0, _len = _ref.length; _i < _len; idx = ++_i) { - allowedVal = _ref[idx]; - if (!(typeof closest !== "undefined" && closest !== null) || Math.abs(allowedVal - value) < Math.abs(closest - value)) { - closest = allowedVal; - closestIdx = idx; - } - } - if (this.settings.snapMid) { - return (closestIdx + 0.5) / this.settings.allowedValues.length; - } else { - return closestIdx / (this.settings.allowedValues.length - 1); - } - } else { - range = this.getRange(); - return (value - range.min) / (range.max - range.min); - } - }; - - SimpleSlider.prototype.ratioToValue = function(ratio) { - var idx, range, rawValue, step, steps; - if (this.settings.equalSteps) { - steps = this.settings.allowedValues.length; - step = Math.round(ratio * steps - 0.5); - idx = Math.min(step, this.settings.allowedValues.length - 1); - return this.settings.allowedValues[idx]; - } else { - range = this.getRange(); - rawValue = ratio * (range.max - range.min) + range.min; - return this.nearestValidValue(rawValue); - } - }; - - SimpleSlider.prototype.valueChanged = function(value, ratio, trigger) { - var eventData; - if (value.toString() === this.value.toString()) { - return; - } - this.value = value; - eventData = { - value: value, - ratio: ratio, - position: ratio * this.slider.outerWidth(), - trigger: trigger, - el: this.slider - }; - return this.input.val(value).trigger($.Event("change", eventData)).trigger("slider:changed", eventData); - }; - - return SimpleSlider; - - })(); - $.extend($.fn, { - simpleSlider: function() { - var params, publicMethods, settingsOrMethod; - settingsOrMethod = arguments[0], params = 2 <= arguments.length ? __slice.call(arguments, 1) : []; - publicMethods = ["setRatio", "setValue", "setDisabled", ]; - return $(this).each(function() { - var obj, settings; - if (settingsOrMethod && __indexOf.call(publicMethods, settingsOrMethod) >= 0) { - obj = $(this).data("slider-object"); - return obj[settingsOrMethod].apply(obj, params); - } else { - settings = settingsOrMethod; - return $(this).data("slider-object", new SimpleSlider($(this), settings)); - } - }); - } - }); - - /* - return $(function() { - return $("[data-slider]").each(function() { - var $el, allowedValues, settings, x; - $el = $(this); - return $el.simpleSlider(); - }); - }); - */ -})(this.jQuery || this.Zepto, this); diff --git a/circle/dashboard/static/dashboard/loopj-jquery-simple-slider/js/simple-slider.min.js b/circle/dashboard/static/dashboard/loopj-jquery-simple-slider/js/simple-slider.min.js deleted file mode 100644 index fbdb6e3..0000000 --- a/circle/dashboard/static/dashboard/loopj-jquery-simple-slider/js/simple-slider.min.js +++ /dev/null @@ -1,11 +0,0 @@ -/* - * jQuery Simple Slider: Unobtrusive Numerical Slider - * Version 1.0.0 - * - * Copyright (c) 2013 James Smith (http://loopj.com) - * - * Licensed under the MIT license (http://mit-license.org/) - * - */ - -var __slice=[].slice,__indexOf=[].indexOf||function(c){for(var b=0,a=this.length;b").addClass("slider"+(this.settings.classSuffix||"")).css({position:"relative",userSelect:"none",boxSizing:"border-box"}).insertBefore(this.input);if(this.input.attr("id")){this.slider.attr("id",this.input.attr("id")+"-slider")}this.track=this.createDivElement("track").css({width:"100%"});if(this.settings.highlight){this.highlightTrack=this.createDivElement("highlight-track").css({width:"0"})}this.dragger=this.createDivElement("dragger");this.slider.css({minHeight:this.dragger.outerHeight(),marginLeft:this.dragger.outerWidth()/2,marginRight:this.dragger.outerWidth()/2});this.track.css({marginTop:this.track.outerHeight()/-2});if(this.settings.highlight){this.highlightTrack.css({marginTop:this.track.outerHeight()/-2})}this.dragger.css({marginTop:this.dragger.outerWidth()/-2,marginLeft:this.dragger.outerWidth()/-2});this.track.mousedown(function(i){return h.trackEvent(i)});if(this.settings.highlight){this.highlightTrack.mousedown(function(i){return h.trackEvent(i)})}this.dragger.mousedown(function(i){if(i.which!==1){return}h.dragging=true;h.dragger.addClass("dragging");h.domDrag(i.pageX,i.pageY);return false});c("body").mousemove(function(i){if(h.dragging){h.domDrag(i.pageX,i.pageY);return c("body").css({cursor:"pointer"})}}).mouseup(function(i){if(h.dragging){h.dragging=false;h.dragger.removeClass("dragging");return c("body").css({cursor:"auto"})}});this.pagePos=0;if(this.input.val()===""){this.value=this.getRange().min;this.input.val(this.value)}else{this.value=this.nearestValidValue(this.input.val())}this.setSliderPositionFromValue(this.value);g=this.valueToRatio(this.value);if(this.settings.showScale){this.scale=this.createDivElement("scale");this.minScale=this.createSpanElement("min-scale",this.scale);this.maxScale=this.createSpanElement("max-scale",this.scale);range=this.getRange();this.minScale.html(range.min);this.maxScale.html(range.max);this.scale.css("marginTop",function(i,j){return(parseInt(j,10)+this.previousSibling.offsetHeight/2)+"px"})}this.input.trigger("slider:ready",{value:this.value,ratio:g,position:g*this.slider.outerWidth(),el:this.slider})}d.prototype.loadDataOptions=function(){var e={};allowedValues=this.input.data("slider-values");if(allowedValues){e.allowedValues=(function(){var i,g,h,f;h=allowedValues.split(",");f=[];for(i=0,g=h.length;i").addClass(f).css({position:"absolute",top:"50%",userSelect:"none",cursor:"pointer"}).appendTo(this.slider);return e};d.prototype.createSpanElement=function(g,e){var f;f=c("").addClass(g).appendTo(e);return f};d.prototype.setRatio=function(e){var f;e=Math.min(1,e);e=Math.max(0,e);f=this.ratioToValue(e);this.setSliderPositionFromValue(f);return this.valueChanged(f,e,"setRatio")};d.prototype.setValue=function(f){var e;f=this.nearestValidValue(f);e=this.valueToRatio(f);this.setSliderPositionFromValue(f);return this.valueChanged(f,e,"setValue")};d.prototype.trackEvent=function(f){if(f.which!==1){return}this.domDrag(f.pageX,f.pageY,true);this.dragging=true;return false};d.prototype.domDrag=function(i,g,e){var f,h,j;if(e==null){e=false}f=i-this.slider.offset().left;f=Math.min(this.slider.outerWidth(),f);f=Math.max(0,f);if(this.pagePos!==f){this.pagePos=f;h=f/this.slider.outerWidth();j=this.ratioToValue(h);this.valueChanged(j,h,"domDrag");if(this.settings.snap){return this.setSliderPositionFromValue(j,e)}else{return this.setSliderPosition(f,e)}}};d.prototype.setSliderPosition=function(e,f){if(f==null){f=false}if(f&&this.settings.animate){this.dragger.animate({left:e},200);if(this.settings.highlight){return this.highlightTrack.animate({width:e},200)}}else{this.dragger.css({left:e});if(this.settings.highlight){return this.highlightTrack.css({width:e})}}};d.prototype.setSliderPositionFromValue=function(g,e){var f;if(e==null){e=false}f=this.valueToRatio(g);return this.setSliderPosition(f*this.slider.outerWidth(),e)};d.prototype.getRange=function(){if(this.settings.allowedValues){return{min:Math.min.apply(Math,this.settings.allowedValues),max:Math.max.apply(Math,this.settings.allowedValues)}}else{if(this.settings.range){return{min:parseFloat(this.settings.range[0]),max:parseFloat(this.settings.range[1])}}else{return{min:0,max:1}}}};d.prototype.nearestValidValue=function(i){var h,g,f,e;f=this.getRange();i=Math.min(f.max,i);i=Math.max(f.min,i);if(this.settings.allowedValues){h=null;c.each(this.settings.allowedValues,function(){if(h===null||Math.abs(this-i)this.settings.step/2&&e=0){h=c(this).data("slider-object");return h[f].apply(h,e)}else{g=f;return c(this).data("slider-object",new b(c(this),g))}})}});return c(function(){return c("[data-slider]").each(function(){var e,g,f,d;e=c(this);return e.simpleSlider()})})})(this.jQuery||this.Zepto,this); diff --git a/circle/dashboard/static/dashboard/node-details.js b/circle/dashboard/static/dashboard/node-details.js index 832a33c..9725ce6 100644 --- a/circle/dashboard/static/dashboard/node-details.js +++ b/circle/dashboard/static/dashboard/node-details.js @@ -17,7 +17,7 @@ $(function() { success: function(data, textStatus, xhr) { $("#node-details-h1-name").text(data['new_name']).show(); $('#node-details-rename').hide(); - // addMessage(data['message'], "success"); + // addMessage(data.message, "success"); }, error: function(xhr, textStatus, error) { addMessage("Error during renaming!", "danger"); @@ -34,7 +34,7 @@ $(function() { $('.node-enable').click(function() { var node_pk = $(this).data('node-pk'); var dir = window.location.pathname.indexOf('list') == -1; - addModalConfirmation(changeNodeStatus, + addModalConfirmation(changeNodeStatus, { 'url': '/dashboard/node/status/' + node_pk + '/', 'data': [], 'pk': node_pk, @@ -51,17 +51,17 @@ $(function() { $.ajax({ type: 'POST', url: location.href, - headers: {"X-CSRFToken": getCookie('csrftoken')}, + headers: {"X-CSRFToken": getCookie('csrftoken')}, data: {'to_remove': to_remove}, success: function(re) { - if(re['message'].toLowerCase() == "success") { + if(re.message.toLowerCase() == "success") { $(clicked).closest(".label").fadeOut(500, function() { $(this).remove(); }); } }, error: function() { - addMessage(re['message'], 'danger'); + addMessage(re.message, 'danger'); } }); @@ -73,18 +73,18 @@ $(function() { function changeNodeStatus(data) { $.ajax({ type: 'POST', - url: data['url'], + url: data.url, headers: {"X-CSRFToken": getCookie('csrftoken')}, success: function(re, textStatus, xhr) { - if(!data['redirect']) { + if(!data.redirect) { selected = []; - addMessage(re['message'], 'success'); + addMessage(re.message, 'success'); } else { window.location.replace('/dashboard'); } }, error: function(xhr, textStatus, error) { - addMessage('Uh oh :(', 'danger') + addMessage('Uh oh :(', 'danger'); } }); } diff --git a/circle/dashboard/static/dashboard/node-list.js b/circle/dashboard/static/dashboard/node-list.js index 9fbea33..fcc3283 100644 --- a/circle/dashboard/static/dashboard/node-list.js +++ b/circle/dashboard/static/dashboard/node-list.js @@ -4,19 +4,16 @@ $(function() { }); // find disabled nodes, set danger (red) on the rows - function colortable() + function colortable() { - var tr= $('.false').closest("tr"); - tr.addClass('danger'); - var tr= $('.true').closest("tr"); - tr.removeClass('danger'); + $('.false').closest("tr").addClass('danger'); + $('.true').closest("tr").removeClass('danger'); } - function statuschangeSuccess(tr){ var tspan=tr.children('.enabled').children(); var buttons=tr.children('.actions').children('.btn-group').children('.dropdown-menu').children('li').children('.node-enable'); - + buttons.each(function(index){ if ($(this).css("display")=="block"){ $(this).css("display","none"); @@ -24,12 +21,12 @@ $(function() { else{ $(this).css("display","block"); } - }); + }); if(tspan.hasClass("false")){ tspan.removeClass("false"); tspan.addClass("true"); tspan.text("✔"); - } + } else{ tspan.removeClass("true"); tspan.addClass("false"); diff --git a/circle/dashboard/static/dashboard/novnc/base64.js b/circle/dashboard/static/dashboard/novnc/base64.js deleted file mode 100644 index 5a6890a..0000000 --- a/circle/dashboard/static/dashboard/novnc/base64.js +++ /dev/null @@ -1,115 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -// From: http://hg.mozilla.org/mozilla-central/raw-file/ec10630b1a54/js/src/devtools/jint/sunspider/string-base64.js - -/*jslint white: false, bitwise: false, plusplus: false */ -/*global console */ - -var Base64 = { - -/* Convert data (an array of integers) to a Base64 string. */ -toBase64Table : 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='.split(''), -base64Pad : '=', - -encode: function (data) { - "use strict"; - var result = ''; - var toBase64Table = Base64.toBase64Table; - var length = data.length - var lengthpad = (length%3); - var i = 0, j = 0; - // Convert every three bytes to 4 ascii characters. - /* BEGIN LOOP */ - for (i = 0; i < (length - 2); i += 3) { - result += toBase64Table[data[i] >> 2]; - result += toBase64Table[((data[i] & 0x03) << 4) + (data[i+1] >> 4)]; - result += toBase64Table[((data[i+1] & 0x0f) << 2) + (data[i+2] >> 6)]; - result += toBase64Table[data[i+2] & 0x3f]; - } - /* END LOOP */ - - // Convert the remaining 1 or 2 bytes, pad out to 4 characters. - if (lengthpad === 2) { - j = length - lengthpad; - result += toBase64Table[data[j] >> 2]; - result += toBase64Table[((data[j] & 0x03) << 4) + (data[j+1] >> 4)]; - result += toBase64Table[(data[j+1] & 0x0f) << 2]; - result += toBase64Table[64]; - } else if (lengthpad === 1) { - j = length - lengthpad; - result += toBase64Table[data[j] >> 2]; - result += toBase64Table[(data[j] & 0x03) << 4]; - result += toBase64Table[64]; - result += toBase64Table[64]; - } - - return result; -}, - -/* Convert Base64 data to a string */ -toBinaryTable : [ - -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, - -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, - -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63, - 52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1, 0,-1,-1, - -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14, - 15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1, - -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40, - 41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1 -], - -decode: function (data, offset) { - "use strict"; - offset = typeof(offset) !== 'undefined' ? offset : 0; - var toBinaryTable = Base64.toBinaryTable; - var base64Pad = Base64.base64Pad; - var result, result_length, idx, i, c, padding; - var leftbits = 0; // number of bits decoded, but yet to be appended - var leftdata = 0; // bits decoded, but yet to be appended - var data_length = data.indexOf('=') - offset; - - if (data_length < 0) { data_length = data.length - offset; } - - /* Every four characters is 3 resulting numbers */ - result_length = (data_length >> 2) * 3 + Math.floor((data_length%4)/1.5); - result = new Array(result_length); - - // Convert one by one. - /* BEGIN LOOP */ - for (idx = 0, i = offset; i < data.length; i++) { - c = toBinaryTable[data.charCodeAt(i) & 0x7f]; - padding = (data.charAt(i) === base64Pad); - // Skip illegal characters and whitespace - if (c === -1) { - console.error("Illegal character code " + data.charCodeAt(i) + " at position " + i); - continue; - } - - // Collect data into leftdata, update bitcount - leftdata = (leftdata << 6) | c; - leftbits += 6; - - // If we have 8 or more bits, append 8 bits to the result - if (leftbits >= 8) { - leftbits -= 8; - // Append if not padding. - if (!padding) { - result[idx++] = (leftdata >> leftbits) & 0xff; - } - leftdata &= (1 << leftbits) - 1; - } - } - /* END LOOP */ - - // If there are any bits left, the base64 string was corrupted - if (leftbits) { - throw {name: 'Base64-Error', - message: 'Corrupted base64 string'}; - } - - return result; -} - -}; /* End of Base64 namespace */ diff --git a/circle/dashboard/static/dashboard/novnc/des.js b/circle/dashboard/static/dashboard/novnc/des.js deleted file mode 100644 index 1f95285..0000000 --- a/circle/dashboard/static/dashboard/novnc/des.js +++ /dev/null @@ -1,273 +0,0 @@ -/* - * Ported from Flashlight VNC ActionScript implementation: - * http://www.wizhelp.com/flashlight-vnc/ - * - * Full attribution follows: - * - * ------------------------------------------------------------------------- - * - * This DES class has been extracted from package Acme.Crypto for use in VNC. - * The unnecessary odd parity code has been removed. - * - * These changes are: - * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - - * DesCipher - the DES encryption method - * - * The meat of this code is by Dave Zimmerman , and is: - * - * Copyright (c) 1996 Widget Workshop, Inc. All Rights Reserved. - * - * Permission to use, copy, modify, and distribute this software - * and its documentation for NON-COMMERCIAL or COMMERCIAL purposes and - * without fee is hereby granted, provided that this copyright notice is kept - * intact. - * - * WIDGET WORKSHOP MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY - * OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED - * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A - * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. WIDGET WORKSHOP SHALL NOT BE LIABLE - * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR - * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. - * - * THIS SOFTWARE IS NOT DESIGNED OR INTENDED FOR USE OR RESALE AS ON-LINE - * CONTROL EQUIPMENT IN HAZARDOUS ENVIRONMENTS REQUIRING FAIL-SAFE - * PERFORMANCE, SUCH AS IN THE OPERATION OF NUCLEAR FACILITIES, AIRCRAFT - * NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL, DIRECT LIFE - * SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH THE FAILURE OF THE - * SOFTWARE COULD LEAD DIRECTLY TO DEATH, PERSONAL INJURY, OR SEVERE - * PHYSICAL OR ENVIRONMENTAL DAMAGE ("HIGH RISK ACTIVITIES"). WIDGET WORKSHOP - * SPECIFICALLY DISCLAIMS ANY EXPRESS OR IMPLIED WARRANTY OF FITNESS FOR - * HIGH RISK ACTIVITIES. - * - * - * The rest is: - * - * Copyright (C) 1996 by Jef Poskanzer . All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 THE AUTHOR OR CONTRIBUTORS 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. - * - * Visit the ACME Labs Java page for up-to-date versions of this and other - * fine Java utilities: http://www.acme.com/java/ - */ - -"use strict"; -/*jslint white: false, bitwise: false, plusplus: false */ - -function DES(passwd) { - -// Tables, permutations, S-boxes, etc. -var PC2 = [13,16,10,23, 0, 4, 2,27,14, 5,20, 9,22,18,11, 3, - 25, 7,15, 6,26,19,12, 1,40,51,30,36,46,54,29,39, - 50,44,32,47,43,48,38,55,33,52,45,41,49,35,28,31 ], - totrot = [ 1, 2, 4, 6, 8,10,12,14,15,17,19,21,23,25,27,28], - z = 0x0, a,b,c,d,e,f, SP1,SP2,SP3,SP4,SP5,SP6,SP7,SP8, - keys = []; - -a=1<<16; b=1<<24; c=a|b; d=1<<2; e=1<<10; f=d|e; -SP1 = [c|e,z|z,a|z,c|f,c|d,a|f,z|d,a|z,z|e,c|e,c|f,z|e,b|f,c|d,b|z,z|d, - z|f,b|e,b|e,a|e,a|e,c|z,c|z,b|f,a|d,b|d,b|d,a|d,z|z,z|f,a|f,b|z, - a|z,c|f,z|d,c|z,c|e,b|z,b|z,z|e,c|d,a|z,a|e,b|d,z|e,z|d,b|f,a|f, - c|f,a|d,c|z,b|f,b|d,z|f,a|f,c|e,z|f,b|e,b|e,z|z,a|d,a|e,z|z,c|d]; -a=1<<20; b=1<<31; c=a|b; d=1<<5; e=1<<15; f=d|e; -SP2 = [c|f,b|e,z|e,a|f,a|z,z|d,c|d,b|f,b|d,c|f,c|e,b|z,b|e,a|z,z|d,c|d, - a|e,a|d,b|f,z|z,b|z,z|e,a|f,c|z,a|d,b|d,z|z,a|e,z|f,c|e,c|z,z|f, - z|z,a|f,c|d,a|z,b|f,c|z,c|e,z|e,c|z,b|e,z|d,c|f,a|f,z|d,z|e,b|z, - z|f,c|e,a|z,b|d,a|d,b|f,b|d,a|d,a|e,z|z,b|e,z|f,b|z,c|d,c|f,a|e]; -a=1<<17; b=1<<27; c=a|b; d=1<<3; e=1<<9; f=d|e; -SP3 = [z|f,c|e,z|z,c|d,b|e,z|z,a|f,b|e,a|d,b|d,b|d,a|z,c|f,a|d,c|z,z|f, - b|z,z|d,c|e,z|e,a|e,c|z,c|d,a|f,b|f,a|e,a|z,b|f,z|d,c|f,z|e,b|z, - c|e,b|z,a|d,z|f,a|z,c|e,b|e,z|z,z|e,a|d,c|f,b|e,b|d,z|e,z|z,c|d, - b|f,a|z,b|z,c|f,z|d,a|f,a|e,b|d,c|z,b|f,z|f,c|z,a|f,z|d,c|d,a|e]; -a=1<<13; b=1<<23; c=a|b; d=1<<0; e=1<<7; f=d|e; -SP4 = [c|d,a|f,a|f,z|e,c|e,b|f,b|d,a|d,z|z,c|z,c|z,c|f,z|f,z|z,b|e,b|d, - z|d,a|z,b|z,c|d,z|e,b|z,a|d,a|e,b|f,z|d,a|e,b|e,a|z,c|e,c|f,z|f, - b|e,b|d,c|z,c|f,z|f,z|z,z|z,c|z,a|e,b|e,b|f,z|d,c|d,a|f,a|f,z|e, - c|f,z|f,z|d,a|z,b|d,a|d,c|e,b|f,a|d,a|e,b|z,c|d,z|e,b|z,a|z,c|e]; -a=1<<25; b=1<<30; c=a|b; d=1<<8; e=1<<19; f=d|e; -SP5 = [z|d,a|f,a|e,c|d,z|e,z|d,b|z,a|e,b|f,z|e,a|d,b|f,c|d,c|e,z|f,b|z, - a|z,b|e,b|e,z|z,b|d,c|f,c|f,a|d,c|e,b|d,z|z,c|z,a|f,a|z,c|z,z|f, - z|e,c|d,z|d,a|z,b|z,a|e,c|d,b|f,a|d,b|z,c|e,a|f,b|f,z|d,a|z,c|e, - c|f,z|f,c|z,c|f,a|e,z|z,b|e,c|z,z|f,a|d,b|d,z|e,z|z,b|e,a|f,b|d]; -a=1<<22; b=1<<29; c=a|b; d=1<<4; e=1<<14; f=d|e; -SP6 = [b|d,c|z,z|e,c|f,c|z,z|d,c|f,a|z,b|e,a|f,a|z,b|d,a|d,b|e,b|z,z|f, - z|z,a|d,b|f,z|e,a|e,b|f,z|d,c|d,c|d,z|z,a|f,c|e,z|f,a|e,c|e,b|z, - b|e,z|d,c|d,a|e,c|f,a|z,z|f,b|d,a|z,b|e,b|z,z|f,b|d,c|f,a|e,c|z, - a|f,c|e,z|z,c|d,z|d,z|e,c|z,a|f,z|e,a|d,b|f,z|z,c|e,b|z,a|d,b|f]; -a=1<<21; b=1<<26; c=a|b; d=1<<1; e=1<<11; f=d|e; -SP7 = [a|z,c|d,b|f,z|z,z|e,b|f,a|f,c|e,c|f,a|z,z|z,b|d,z|d,b|z,c|d,z|f, - b|e,a|f,a|d,b|e,b|d,c|z,c|e,a|d,c|z,z|e,z|f,c|f,a|e,z|d,b|z,a|e, - b|z,a|e,a|z,b|f,b|f,c|d,c|d,z|d,a|d,b|z,b|e,a|z,c|e,z|f,a|f,c|e, - z|f,b|d,c|f,c|z,a|e,z|z,z|d,c|f,z|z,a|f,c|z,z|e,b|d,b|e,z|e,a|d]; -a=1<<18; b=1<<28; c=a|b; d=1<<6; e=1<<12; f=d|e; -SP8 = [b|f,z|e,a|z,c|f,b|z,b|f,z|d,b|z,a|d,c|z,c|f,a|e,c|e,a|f,z|e,z|d, - c|z,b|d,b|e,z|f,a|e,a|d,c|d,c|e,z|f,z|z,z|z,c|d,b|d,b|e,a|f,a|z, - a|f,a|z,c|e,z|e,z|d,c|d,z|e,a|f,b|e,z|d,b|d,c|z,c|d,b|z,a|z,b|f, - z|z,c|f,a|d,b|d,c|z,b|e,b|f,z|z,c|f,a|e,a|e,z|f,z|f,a|d,b|z,c|e]; - -// Set the key. -function setKeys(keyBlock) { - var i, j, l, m, n, o, pc1m = [], pcr = [], kn = [], - raw0, raw1, rawi, KnLi; - - for (j = 0, l = 56; j < 56; ++j, l-=8) { - l += l<-5 ? 65 : l<-3 ? 31 : l<-1 ? 63 : l===27 ? 35 : 0; // PC1 - m = l & 0x7; - pc1m[j] = ((keyBlock[l >>> 3] & (1<>> 10; - keys[KnLi] |= (raw1 & 0x00000fc0) >>> 6; - ++KnLi; - keys[KnLi] = (raw0 & 0x0003f000) << 12; - keys[KnLi] |= (raw0 & 0x0000003f) << 16; - keys[KnLi] |= (raw1 & 0x0003f000) >>> 4; - keys[KnLi] |= (raw1 & 0x0000003f); - ++KnLi; - } -} - -// Encrypt 8 bytes of text -function enc8(text) { - var i = 0, b = text.slice(), fval, keysi = 0, - l, r, x; // left, right, accumulator - - // Squash 8 bytes to 2 ints - l = b[i++]<<24 | b[i++]<<16 | b[i++]<<8 | b[i++]; - r = b[i++]<<24 | b[i++]<<16 | b[i++]<<8 | b[i++]; - - x = ((l >>> 4) ^ r) & 0x0f0f0f0f; - r ^= x; - l ^= (x << 4); - x = ((l >>> 16) ^ r) & 0x0000ffff; - r ^= x; - l ^= (x << 16); - x = ((r >>> 2) ^ l) & 0x33333333; - l ^= x; - r ^= (x << 2); - x = ((r >>> 8) ^ l) & 0x00ff00ff; - l ^= x; - r ^= (x << 8); - r = (r << 1) | ((r >>> 31) & 1); - x = (l ^ r) & 0xaaaaaaaa; - l ^= x; - r ^= x; - l = (l << 1) | ((l >>> 31) & 1); - - for (i = 0; i < 8; ++i) { - x = (r << 28) | (r >>> 4); - x ^= keys[keysi++]; - fval = SP7[x & 0x3f]; - fval |= SP5[(x >>> 8) & 0x3f]; - fval |= SP3[(x >>> 16) & 0x3f]; - fval |= SP1[(x >>> 24) & 0x3f]; - x = r ^ keys[keysi++]; - fval |= SP8[x & 0x3f]; - fval |= SP6[(x >>> 8) & 0x3f]; - fval |= SP4[(x >>> 16) & 0x3f]; - fval |= SP2[(x >>> 24) & 0x3f]; - l ^= fval; - x = (l << 28) | (l >>> 4); - x ^= keys[keysi++]; - fval = SP7[x & 0x3f]; - fval |= SP5[(x >>> 8) & 0x3f]; - fval |= SP3[(x >>> 16) & 0x3f]; - fval |= SP1[(x >>> 24) & 0x3f]; - x = l ^ keys[keysi++]; - fval |= SP8[x & 0x0000003f]; - fval |= SP6[(x >>> 8) & 0x3f]; - fval |= SP4[(x >>> 16) & 0x3f]; - fval |= SP2[(x >>> 24) & 0x3f]; - r ^= fval; - } - - r = (r << 31) | (r >>> 1); - x = (l ^ r) & 0xaaaaaaaa; - l ^= x; - r ^= x; - l = (l << 31) | (l >>> 1); - x = ((l >>> 8) ^ r) & 0x00ff00ff; - r ^= x; - l ^= (x << 8); - x = ((l >>> 2) ^ r) & 0x33333333; - r ^= x; - l ^= (x << 2); - x = ((r >>> 16) ^ l) & 0x0000ffff; - l ^= x; - r ^= (x << 16); - x = ((r >>> 4) ^ l) & 0x0f0f0f0f; - l ^= x; - r ^= (x << 4); - - // Spread ints to bytes - x = [r, l]; - for (i = 0; i < 8; i++) { - b[i] = (x[i>>>2] >>> (8*(3 - (i%4)))) % 256; - if (b[i] < 0) { b[i] += 256; } // unsigned - } - return b; -} - -// Encrypt 16 bytes of text using passwd as key -function encrypt(t) { - return enc8(t.slice(0,8)).concat(enc8(t.slice(8,16))); -} - -setKeys(passwd); // Setup keys -return {'encrypt': encrypt}; // Public interface - -} // function DES diff --git a/circle/dashboard/static/dashboard/novnc/display.js b/circle/dashboard/static/dashboard/novnc/display.js deleted file mode 100644 index 9f2d6b8..0000000 --- a/circle/dashboard/static/dashboard/novnc/display.js +++ /dev/null @@ -1,770 +0,0 @@ -/* - * noVNC: HTML5 VNC client - * Copyright (C) 2012 Joel Martin - * Licensed under MPL 2.0 (see LICENSE.txt) - * - * See README.md for usage and integration instructions. - */ - -/*jslint browser: true, white: false, bitwise: false */ -/*global Util, Base64, changeCursor */ - -function Display(defaults) { -"use strict"; - -var that = {}, // Public API methods - conf = {}, // Configuration attributes - - // Private Display namespace variables - c_ctx = null, - c_forceCanvas = false, - - // Queued drawing actions for in-order rendering - renderQ = [], - - // Predefine function variables (jslint) - imageDataGet, rgbImageData, bgrxImageData, cmapImageData, - setFillColor, rescale, scan_renderQ, - - // The full frame buffer (logical canvas) size - fb_width = 0, - fb_height = 0, - // The visible "physical canvas" viewport - viewport = {'x': 0, 'y': 0, 'w' : 0, 'h' : 0 }, - cleanRect = {'x1': 0, 'y1': 0, 'x2': -1, 'y2': -1}, - - c_prevStyle = "", - tile = null, - tile16x16 = null, - tile_x = 0, - tile_y = 0; - - -// Configuration attributes -Util.conf_defaults(conf, that, defaults, [ - ['target', 'wo', 'dom', null, 'Canvas element for rendering'], - ['context', 'ro', 'raw', null, 'Canvas 2D context for rendering (read-only)'], - ['logo', 'rw', 'raw', null, 'Logo to display when cleared: {"width": width, "height": height, "data": data}'], - ['true_color', 'rw', 'bool', true, 'Use true-color pixel data'], - ['colourMap', 'rw', 'arr', [], 'Colour map array (when not true-color)'], - ['scale', 'rw', 'float', 1.0, 'Display area scale factor 0.0 - 1.0'], - ['viewport', 'rw', 'bool', false, 'Use a viewport set with viewportChange()'], - ['width', 'rw', 'int', null, 'Display area width'], - ['height', 'rw', 'int', null, 'Display area height'], - - ['render_mode', 'ro', 'str', '', 'Canvas rendering mode (read-only)'], - - ['prefer_js', 'rw', 'str', null, 'Prefer Javascript over canvas methods'], - ['cursor_uri', 'rw', 'raw', null, 'Can we render cursor using data URI'] - ]); - -// Override some specific getters/setters -that.get_context = function () { return c_ctx; }; - -that.set_scale = function(scale) { rescale(scale); }; - -that.set_width = function (val) { that.resize(val, fb_height); }; -that.get_width = function() { return fb_width; }; - -that.set_height = function (val) { that.resize(fb_width, val); }; -that.get_height = function() { return fb_height; }; - - - -// -// Private functions -// - -// Create the public API interface -function constructor() { - Util.Debug(">> Display.constructor"); - - var c, func, i, curDat, curSave, - has_imageData = false, UE = Util.Engine; - - if (! conf.target) { throw("target must be set"); } - - if (typeof conf.target === 'string') { - throw("target must be a DOM element"); - } - - c = conf.target; - - if (! c.getContext) { throw("no getContext method"); } - - if (! c_ctx) { c_ctx = c.getContext('2d'); } - - Util.Debug("User Agent: " + navigator.userAgent); - if (UE.gecko) { Util.Debug("Browser: gecko " + UE.gecko); } - if (UE.webkit) { Util.Debug("Browser: webkit " + UE.webkit); } - if (UE.trident) { Util.Debug("Browser: trident " + UE.trident); } - if (UE.presto) { Util.Debug("Browser: presto " + UE.presto); } - - that.clear(); - - // Check canvas features - if ('createImageData' in c_ctx) { - conf.render_mode = "canvas rendering"; - } else { - throw("Canvas does not support createImageData"); - } - if (conf.prefer_js === null) { - Util.Info("Prefering javascript operations"); - conf.prefer_js = true; - } - - // Initialize cached tile imageData - tile16x16 = c_ctx.createImageData(16, 16); - - /* - * Determine browser support for setting the cursor via data URI - * scheme - */ - curDat = []; - for (i=0; i < 8 * 8 * 4; i += 1) { - curDat.push(255); - } - try { - curSave = c.style.cursor; - changeCursor(conf.target, curDat, curDat, 2, 2, 8, 8); - if (c.style.cursor) { - if (conf.cursor_uri === null) { - conf.cursor_uri = true; - } - Util.Info("Data URI scheme cursor supported"); - } else { - if (conf.cursor_uri === null) { - conf.cursor_uri = false; - } - Util.Warn("Data URI scheme cursor not supported"); - } - c.style.cursor = curSave; - } catch (exc2) { - Util.Error("Data URI scheme cursor test exception: " + exc2); - conf.cursor_uri = false; - } - - Util.Debug("<< Display.constructor"); - return that ; -} - -rescale = function(factor) { - var c, tp, x, y, - properties = ['transform', 'WebkitTransform', 'MozTransform', null]; - c = conf.target; - tp = properties.shift(); - while (tp) { - if (typeof c.style[tp] !== 'undefined') { - break; - } - tp = properties.shift(); - } - - if (tp === null) { - Util.Debug("No scaling support"); - return; - } - - - if (typeof(factor) === "undefined") { - factor = conf.scale; - } else if (factor > 1.0) { - factor = 1.0; - } else if (factor < 0.1) { - factor = 0.1; - } - - if (conf.scale === factor) { - //Util.Debug("Display already scaled to '" + factor + "'"); - return; - } - - conf.scale = factor; - x = c.width - c.width * factor; - y = c.height - c.height * factor; - c.style[tp] = "scale(" + conf.scale + ") translate(-" + x + "px, -" + y + "px)"; -}; - -setFillColor = function(color) { - var bgr, newStyle; - if (conf.true_color) { - bgr = color; - } else { - bgr = conf.colourMap[color[0]]; - } - newStyle = "rgb(" + bgr[2] + "," + bgr[1] + "," + bgr[0] + ")"; - if (newStyle !== c_prevStyle) { - c_ctx.fillStyle = newStyle; - c_prevStyle = newStyle; - } -}; - - -// -// Public API interface functions -// - -// Shift and/or resize the visible viewport -that.viewportChange = function(deltaX, deltaY, width, height) { - var c = conf.target, v = viewport, cr = cleanRect, - saveImg = null, saveStyle, x1, y1, vx2, vy2, w, h; - - if (!conf.viewport) { - Util.Debug("Setting viewport to full display region"); - deltaX = -v.w; // Clamped later if out of bounds - deltaY = -v.h; // Clamped later if out of bounds - width = fb_width; - height = fb_height; - } - - if (typeof(deltaX) === "undefined") { deltaX = 0; } - if (typeof(deltaY) === "undefined") { deltaY = 0; } - if (typeof(width) === "undefined") { width = v.w; } - if (typeof(height) === "undefined") { height = v.h; } - - // Size change - - if (width > fb_width) { width = fb_width; } - if (height > fb_height) { height = fb_height; } - - if ((v.w !== width) || (v.h !== height)) { - // Change width - if ((width < v.w) && (cr.x2 > v.x + width -1)) { - cr.x2 = v.x + width - 1; - } - v.w = width; - - // Change height - if ((height < v.h) && (cr.y2 > v.y + height -1)) { - cr.y2 = v.y + height - 1; - } - v.h = height; - - - if (v.w > 0 && v.h > 0 && c.width > 0 && c.height > 0) { - saveImg = c_ctx.getImageData(0, 0, - (c.width < v.w) ? c.width : v.w, - (c.height < v.h) ? c.height : v.h); - } - - c.width = v.w; - c.height = v.h; - - if (saveImg) { - c_ctx.putImageData(saveImg, 0, 0); - } - } - - vx2 = v.x + v.w - 1; - vy2 = v.y + v.h - 1; - - - // Position change - - if ((deltaX < 0) && ((v.x + deltaX) < 0)) { - deltaX = - v.x; - } - if ((vx2 + deltaX) >= fb_width) { - deltaX -= ((vx2 + deltaX) - fb_width + 1); - } - - if ((v.y + deltaY) < 0) { - deltaY = - v.y; - } - if ((vy2 + deltaY) >= fb_height) { - deltaY -= ((vy2 + deltaY) - fb_height + 1); - } - - if ((deltaX === 0) && (deltaY === 0)) { - //Util.Debug("skipping viewport change"); - return; - } - Util.Debug("viewportChange deltaX: " + deltaX + ", deltaY: " + deltaY); - - v.x += deltaX; - vx2 += deltaX; - v.y += deltaY; - vy2 += deltaY; - - // Update the clean rectangle - if (v.x > cr.x1) { - cr.x1 = v.x; - } - if (vx2 < cr.x2) { - cr.x2 = vx2; - } - if (v.y > cr.y1) { - cr.y1 = v.y; - } - if (vy2 < cr.y2) { - cr.y2 = vy2; - } - - if (deltaX < 0) { - // Shift viewport left, redraw left section - x1 = 0; - w = - deltaX; - } else { - // Shift viewport right, redraw right section - x1 = v.w - deltaX; - w = deltaX; - } - if (deltaY < 0) { - // Shift viewport up, redraw top section - y1 = 0; - h = - deltaY; - } else { - // Shift viewport down, redraw bottom section - y1 = v.h - deltaY; - h = deltaY; - } - - // Copy the valid part of the viewport to the shifted location - saveStyle = c_ctx.fillStyle; - c_ctx.fillStyle = "rgb(255,255,255)"; - if (deltaX !== 0) { - //that.copyImage(0, 0, -deltaX, 0, v.w, v.h); - //that.fillRect(x1, 0, w, v.h, [255,255,255]); - c_ctx.drawImage(c, 0, 0, v.w, v.h, -deltaX, 0, v.w, v.h); - c_ctx.fillRect(x1, 0, w, v.h); - } - if (deltaY !== 0) { - //that.copyImage(0, 0, 0, -deltaY, v.w, v.h); - //that.fillRect(0, y1, v.w, h, [255,255,255]); - c_ctx.drawImage(c, 0, 0, v.w, v.h, 0, -deltaY, v.w, v.h); - c_ctx.fillRect(0, y1, v.w, h); - } - c_ctx.fillStyle = saveStyle; -}; - - -// Return a map of clean and dirty areas of the viewport and reset the -// tracking of clean and dirty areas. -// -// Returns: {'cleanBox': {'x': x, 'y': y, 'w': w, 'h': h}, -// 'dirtyBoxes': [{'x': x, 'y': y, 'w': w, 'h': h}, ...]} -that.getCleanDirtyReset = function() { - var v = viewport, c = cleanRect, cleanBox, dirtyBoxes = [], - vx2 = v.x + v.w - 1, vy2 = v.y + v.h - 1; - - - // Copy the cleanRect - cleanBox = {'x': c.x1, 'y': c.y1, - 'w': c.x2 - c.x1 + 1, 'h': c.y2 - c.y1 + 1}; - - if ((c.x1 >= c.x2) || (c.y1 >= c.y2)) { - // Whole viewport is dirty - dirtyBoxes.push({'x': v.x, 'y': v.y, 'w': v.w, 'h': v.h}); - } else { - // Redraw dirty regions - if (v.x < c.x1) { - // left side dirty region - dirtyBoxes.push({'x': v.x, 'y': v.y, - 'w': c.x1 - v.x + 1, 'h': v.h}); - } - if (vx2 > c.x2) { - // right side dirty region - dirtyBoxes.push({'x': c.x2 + 1, 'y': v.y, - 'w': vx2 - c.x2, 'h': v.h}); - } - if (v.y < c.y1) { - // top/middle dirty region - dirtyBoxes.push({'x': c.x1, 'y': v.y, - 'w': c.x2 - c.x1 + 1, 'h': c.y1 - v.y}); - } - if (vy2 > c.y2) { - // bottom/middle dirty region - dirtyBoxes.push({'x': c.x1, 'y': c.y2 + 1, - 'w': c.x2 - c.x1 + 1, 'h': vy2 - c.y2}); - } - } - - // Reset the cleanRect to the whole viewport - cleanRect = {'x1': v.x, 'y1': v.y, - 'x2': v.x + v.w - 1, 'y2': v.y + v.h - 1}; - - return {'cleanBox': cleanBox, 'dirtyBoxes': dirtyBoxes}; -}; - -// Translate viewport coordinates to absolute coordinates -that.absX = function(x) { - return x + viewport.x; -}; -that.absY = function(y) { - return y + viewport.y; -}; - - -that.resize = function(width, height) { - c_prevStyle = ""; - - fb_width = width; - fb_height = height; - - rescale(conf.scale); - that.viewportChange(); -}; - -that.clear = function() { - - if (conf.logo) { - that.resize(conf.logo.width, conf.logo.height); - that.blitStringImage(conf.logo.data, 0, 0); - } else { - that.resize(640, 20); - c_ctx.clearRect(0, 0, viewport.w, viewport.h); - } - - renderQ = []; - - // No benefit over default ("source-over") in Chrome and firefox - //c_ctx.globalCompositeOperation = "copy"; -}; - -that.fillRect = function(x, y, width, height, color) { - setFillColor(color); - c_ctx.fillRect(x - viewport.x, y - viewport.y, width, height); -}; - -that.copyImage = function(old_x, old_y, new_x, new_y, w, h) { - var x1 = old_x - viewport.x, y1 = old_y - viewport.y, - x2 = new_x - viewport.x, y2 = new_y - viewport.y; - c_ctx.drawImage(conf.target, x1, y1, w, h, x2, y2, w, h); -}; - - -// Start updating a tile -that.startTile = function(x, y, width, height, color) { - var data, bgr, red, green, blue, i; - tile_x = x; - tile_y = y; - if ((width === 16) && (height === 16)) { - tile = tile16x16; - } else { - tile = c_ctx.createImageData(width, height); - } - data = tile.data; - if (conf.prefer_js) { - if (conf.true_color) { - bgr = color; - } else { - bgr = conf.colourMap[color[0]]; - } - red = bgr[2]; - green = bgr[1]; - blue = bgr[0]; - for (i = 0; i < (width * height * 4); i+=4) { - data[i ] = red; - data[i + 1] = green; - data[i + 2] = blue; - data[i + 3] = 255; - } - } else { - that.fillRect(x, y, width, height, color); - } -}; - -// Update sub-rectangle of the current tile -that.subTile = function(x, y, w, h, color) { - var data, p, bgr, red, green, blue, width, j, i, xend, yend; - if (conf.prefer_js) { - data = tile.data; - width = tile.width; - if (conf.true_color) { - bgr = color; - } else { - bgr = conf.colourMap[color[0]]; - } - red = bgr[2]; - green = bgr[1]; - blue = bgr[0]; - xend = x + w; - yend = y + h; - for (j = y; j < yend; j += 1) { - for (i = x; i < xend; i += 1) { - p = (i + (j * width) ) * 4; - data[p ] = red; - data[p + 1] = green; - data[p + 2] = blue; - data[p + 3] = 255; - } - } - } else { - that.fillRect(tile_x + x, tile_y + y, w, h, color); - } -}; - -// Draw the current tile to the screen -that.finishTile = function() { - if (conf.prefer_js) { - c_ctx.putImageData(tile, tile_x - viewport.x, tile_y - viewport.y); - } - // else: No-op, if not prefer_js then already done by setSubTile -}; - -rgbImageData = function(x, y, vx, vy, width, height, arr, offset) { - var img, i, j, data; - /* - if ((x - v.x >= v.w) || (y - v.y >= v.h) || - (x - v.x + width < 0) || (y - v.y + height < 0)) { - // Skipping because outside of viewport - return; - } - */ - img = c_ctx.createImageData(width, height); - data = img.data; - for (i=0, j=offset; i < (width * height * 4); i=i+4, j=j+3) { - data[i ] = arr[j ]; - data[i + 1] = arr[j + 1]; - data[i + 2] = arr[j + 2]; - data[i + 3] = 255; // Set Alpha - } - c_ctx.putImageData(img, x - vx, y - vy); -}; - -bgrxImageData = function(x, y, vx, vy, width, height, arr, offset) { - var img, i, j, data; - /* - if ((x - v.x >= v.w) || (y - v.y >= v.h) || - (x - v.x + width < 0) || (y - v.y + height < 0)) { - // Skipping because outside of viewport - return; - } - */ - img = c_ctx.createImageData(width, height); - data = img.data; - for (i=0, j=offset; i < (width * height * 4); i=i+4, j=j+4) { - data[i ] = arr[j + 2]; - data[i + 1] = arr[j + 1]; - data[i + 2] = arr[j ]; - data[i + 3] = 255; // Set Alpha - } - c_ctx.putImageData(img, x - vx, y - vy); -}; - -cmapImageData = function(x, y, vx, vy, width, height, arr, offset) { - var img, i, j, data, bgr, cmap; - img = c_ctx.createImageData(width, height); - data = img.data; - cmap = conf.colourMap; - for (i=0, j=offset; i < (width * height * 4); i+=4, j+=1) { - bgr = cmap[arr[j]]; - data[i ] = bgr[2]; - data[i + 1] = bgr[1]; - data[i + 2] = bgr[0]; - data[i + 3] = 255; // Set Alpha - } - c_ctx.putImageData(img, x - vx, y - vy); -}; - -that.blitImage = function(x, y, width, height, arr, offset) { - if (conf.true_color) { - bgrxImageData(x, y, viewport.x, viewport.y, width, height, arr, offset); - } else { - cmapImageData(x, y, viewport.x, viewport.y, width, height, arr, offset); - } -}; - -that.blitRgbImage = function(x, y, width, height, arr, offset) { - if (conf.true_color) { - rgbImageData(x, y, viewport.x, viewport.y, width, height, arr, offset); - } else { - // prolly wrong... - cmapImageData(x, y, viewport.x, viewport.y, width, height, arr, offset); - } -}; - -that.blitStringImage = function(str, x, y) { - var img = new Image(); - img.onload = function () { - c_ctx.drawImage(img, x - viewport.x, y - viewport.y); - }; - img.src = str; -}; - -// Wrap ctx.drawImage but relative to viewport -that.drawImage = function(img, x, y) { - c_ctx.drawImage(img, x - viewport.x, y - viewport.y); -}; - -that.renderQ_push = function(action) { - renderQ.push(action); - if (renderQ.length === 1) { - // If this can be rendered immediately it will be, otherwise - // the scanner will start polling the queue (every - // requestAnimationFrame interval) - scan_renderQ(); - } -}; - -scan_renderQ = function() { - var a, ready = true; - while (ready && renderQ.length > 0) { - a = renderQ[0]; - switch (a.type) { - case 'copy': - that.copyImage(a.old_x, a.old_y, a.x, a.y, a.width, a.height); - break; - case 'fill': - that.fillRect(a.x, a.y, a.width, a.height, a.color); - break; - case 'blit': - that.blitImage(a.x, a.y, a.width, a.height, a.data, 0); - break; - case 'blitRgb': - that.blitRgbImage(a.x, a.y, a.width, a.height, a.data, 0); - break; - case 'img': - if (a.img.complete) { - that.drawImage(a.img, a.x, a.y); - } else { - // We need to wait for this image to 'load' - // to keep things in-order - ready = false; - } - break; - } - if (ready) { - a = renderQ.shift(); - } - } - if (renderQ.length > 0) { - requestAnimFrame(scan_renderQ); - } -}; - - -that.changeCursor = function(pixels, mask, hotx, hoty, w, h) { - if (conf.cursor_uri === false) { - Util.Warn("changeCursor called but no cursor data URI support"); - return; - } - - if (conf.true_color) { - changeCursor(conf.target, pixels, mask, hotx, hoty, w, h); - } else { - changeCursor(conf.target, pixels, mask, hotx, hoty, w, h, conf.colourMap); - } -}; - -that.defaultCursor = function() { - conf.target.style.cursor = "default"; -}; - -return constructor(); // Return the public API interface - -} // End of Display() - - -/* Set CSS cursor property using data URI encoded cursor file */ -function changeCursor(target, pixels, mask, hotx, hoty, w0, h0, cmap) { - "use strict"; - var cur = [], rgb, IHDRsz, RGBsz, ANDsz, XORsz, url, idx, alpha, x, y; - //Util.Debug(">> changeCursor, x: " + hotx + ", y: " + hoty + ", w0: " + w0 + ", h0: " + h0); - - var w = w0; - var h = h0; - if (h < w) - h = w; // increase h to make it square - else - w = h; // increace w to make it square - - // Push multi-byte little-endian values - cur.push16le = function (num) { - this.push((num ) & 0xFF, - (num >> 8) & 0xFF ); - }; - cur.push32le = function (num) { - this.push((num ) & 0xFF, - (num >> 8) & 0xFF, - (num >> 16) & 0xFF, - (num >> 24) & 0xFF ); - }; - - IHDRsz = 40; - RGBsz = w * h * 4; - XORsz = Math.ceil( (w * h) / 8.0 ); - ANDsz = Math.ceil( (w * h) / 8.0 ); - - // Main header - cur.push16le(0); // 0: Reserved - cur.push16le(2); // 2: .CUR type - cur.push16le(1); // 4: Number of images, 1 for non-animated ico - - // Cursor #1 header (ICONDIRENTRY) - cur.push(w); // 6: width - cur.push(h); // 7: height - cur.push(0); // 8: colors, 0 -> true-color - cur.push(0); // 9: reserved - cur.push16le(hotx); // 10: hotspot x coordinate - cur.push16le(hoty); // 12: hotspot y coordinate - cur.push32le(IHDRsz + RGBsz + XORsz + ANDsz); - // 14: cursor data byte size - cur.push32le(22); // 18: offset of cursor data in the file - - - // Cursor #1 InfoHeader (ICONIMAGE/BITMAPINFO) - cur.push32le(IHDRsz); // 22: Infoheader size - cur.push32le(w); // 26: Cursor width - cur.push32le(h*2); // 30: XOR+AND height - cur.push16le(1); // 34: number of planes - cur.push16le(32); // 36: bits per pixel - cur.push32le(0); // 38: Type of compression - - cur.push32le(XORsz + ANDsz); // 43: Size of Image - // Gimp leaves this as 0 - - cur.push32le(0); // 46: reserved - cur.push32le(0); // 50: reserved - cur.push32le(0); // 54: reserved - cur.push32le(0); // 58: reserved - - // 62: color data (RGBQUAD icColors[]) - for (y = h-1; y >= 0; y -= 1) { - for (x = 0; x < w; x += 1) { - if (x >= w0 || y >= h0) { - cur.push(0); // blue - cur.push(0); // green - cur.push(0); // red - cur.push(0); // alpha - } else { - idx = y * Math.ceil(w0 / 8) + Math.floor(x/8); - alpha = (mask[idx] << (x % 8)) & 0x80 ? 255 : 0; - if (cmap) { - idx = (w0 * y) + x; - rgb = cmap[pixels[idx]]; - cur.push(rgb[2]); // blue - cur.push(rgb[1]); // green - cur.push(rgb[0]); // red - cur.push(alpha); // alpha - } else { - idx = ((w0 * y) + x) * 4; - cur.push(pixels[idx + 2]); // blue - cur.push(pixels[idx + 1]); // green - cur.push(pixels[idx ]); // red - cur.push(alpha); // alpha - } - } - } - } - - // XOR/bitmask data (BYTE icXOR[]) - // (ignored, just needs to be right size) - for (y = 0; y < h; y += 1) { - for (x = 0; x < Math.ceil(w / 8); x += 1) { - cur.push(0x00); - } - } - - // AND/bitmask data (BYTE icAND[]) - // (ignored, just needs to be right size) - for (y = 0; y < h; y += 1) { - for (x = 0; x < Math.ceil(w / 8); x += 1) { - cur.push(0x00); - } - } - - url = "data:image/x-icon;base64," + Base64.encode(cur); - target.style.cursor = "url(" + url + ") " + hotx + " " + hoty + ", default"; - //Util.Debug("<< changeCursor, cur.length: " + cur.length); -} diff --git a/circle/dashboard/static/dashboard/novnc/input.js b/circle/dashboard/static/dashboard/novnc/input.js deleted file mode 100644 index 8f0c650..0000000 --- a/circle/dashboard/static/dashboard/novnc/input.js +++ /dev/null @@ -1,1980 +0,0 @@ -/* - * noVNC: HTML5 VNC client - * Copyright (C) 2012 Joel Martin - * Copyright (C) 2013 Samuel Mannehed for Cendio AB - * Licensed under MPL 2.0 or any later version (see LICENSE.txt) - */ - -/*jslint browser: true, white: false, bitwise: false */ -/*global window, Util */ - - -// -// Keyboard event handler -// - -function Keyboard(defaults) { -"use strict"; - -var that = {}, // Public API methods - conf = {}, // Configuration attributes - - keyDownList = []; // List of depressed keys - // (even if they are happy) - -// Configuration attributes -Util.conf_defaults(conf, that, defaults, [ - ['target', 'wo', 'dom', document, 'DOM element that captures keyboard input'], - ['focused', 'rw', 'bool', true, 'Capture and send key events'], - - ['onKeyPress', 'rw', 'func', null, 'Handler for key press/release'] - ]); - - -// -// Private functions -// - -// From the event keyCode return the keysym value for keys that need -// to be suppressed otherwise they may trigger unintended browser -// actions -function getKeysymSpecial(evt) { - var keysym = null; - - switch ( evt.keyCode ) { - // These generate a keyDown and keyPress in Firefox and Opera - case 8 : keysym = 0xFF08; break; // BACKSPACE - case 13 : keysym = 0xFF0D; break; // ENTER - - // This generates a keyDown and keyPress in Opera - case 9 : keysym = 0xFF09; break; // TAB - default : break; - } - - if (evt.type === 'keydown') { - switch ( evt.keyCode ) { - case 27 : keysym = 0xFF1B; break; // ESCAPE - case 46 : keysym = 0xFFFF; break; // DELETE - - case 36 : keysym = 0xFF50; break; // HOME - case 35 : keysym = 0xFF57; break; // END - case 33 : keysym = 0xFF55; break; // PAGE_UP - case 34 : keysym = 0xFF56; break; // PAGE_DOWN - case 45 : keysym = 0xFF63; break; // INSERT - // '-' during keyPress - case 37 : keysym = 0xFF51; break; // LEFT - case 38 : keysym = 0xFF52; break; // UP - case 39 : keysym = 0xFF53; break; // RIGHT - case 40 : keysym = 0xFF54; break; // DOWN - case 16 : keysym = 0xFFE1; break; // SHIFT - case 17 : keysym = 0xFFE3; break; // CONTROL - //case 18 : keysym = 0xFFE7; break; // Left Meta (Mac Option) - case 18 : keysym = 0xFFE9; break; // Left ALT (Mac Command) - - case 112 : keysym = 0xFFBE; break; // F1 - case 113 : keysym = 0xFFBF; break; // F2 - case 114 : keysym = 0xFFC0; break; // F3 - case 115 : keysym = 0xFFC1; break; // F4 - case 116 : keysym = 0xFFC2; break; // F5 - case 117 : keysym = 0xFFC3; break; // F6 - case 118 : keysym = 0xFFC4; break; // F7 - case 119 : keysym = 0xFFC5; break; // F8 - case 120 : keysym = 0xFFC6; break; // F9 - case 121 : keysym = 0xFFC7; break; // F10 - case 122 : keysym = 0xFFC8; break; // F11 - case 123 : keysym = 0xFFC9; break; // F12 - - case 225 : keysym = 0xFE03; break; // AltGr - case 91 : keysym = 0xFFEC; break; // Super_R (Win Key) - case 93 : keysym = 0xFF67; break; // Menu (Win Menu) - - default : break; - } - } - - if ((!keysym) && (evt.ctrlKey || evt.altKey)) { - if ((typeof(evt.which) !== "undefined") && (evt.which > 0)) { - keysym = evt.which; - } else { - // IE9 always - // Firefox and Opera when ctrl/alt + special - Util.Warn("which not set, using keyCode"); - keysym = evt.keyCode; - } - - /* Remap symbols */ - switch (keysym) { - case 186 : keysym = 59; break; // ; (IE) - case 187 : keysym = 61; break; // = (IE) - case 188 : keysym = 44; break; // , (Mozilla, IE) - case 109 : // - (Mozilla, Opera) - if (Util.Engine.gecko || Util.Engine.presto) { - keysym = 45; } - break; - case 173 : // - (Mozilla) - if (Util.Engine.gecko) { - keysym = 45; } - break; - case 189 : keysym = 45; break; // - (IE) - case 190 : keysym = 46; break; // . (Mozilla, IE) - case 191 : keysym = 47; break; // / (Mozilla, IE) - case 192 : keysym = 96; break; // ` (Mozilla, IE) - case 219 : keysym = 91; break; // [ (Mozilla, IE) - case 220 : keysym = 92; break; // \ (Mozilla, IE) - case 221 : keysym = 93; break; // ] (Mozilla, IE) - case 222 : keysym = 39; break; // ' (Mozilla, IE) - } - - /* Remap shifted and unshifted keys */ - if (!!evt.shiftKey) { - switch (keysym) { - case 48 : keysym = 41 ; break; // ) (shifted 0) - case 49 : keysym = 33 ; break; // ! (shifted 1) - case 50 : keysym = 64 ; break; // @ (shifted 2) - case 51 : keysym = 35 ; break; // # (shifted 3) - case 52 : keysym = 36 ; break; // $ (shifted 4) - case 53 : keysym = 37 ; break; // % (shifted 5) - case 54 : keysym = 94 ; break; // ^ (shifted 6) - case 55 : keysym = 38 ; break; // & (shifted 7) - case 56 : keysym = 42 ; break; // * (shifted 8) - case 57 : keysym = 40 ; break; // ( (shifted 9) - - case 59 : keysym = 58 ; break; // : (shifted `) - case 61 : keysym = 43 ; break; // + (shifted ;) - case 44 : keysym = 60 ; break; // < (shifted ,) - case 45 : keysym = 95 ; break; // _ (shifted -) - case 46 : keysym = 62 ; break; // > (shifted .) - case 47 : keysym = 63 ; break; // ? (shifted /) - case 96 : keysym = 126; break; // ~ (shifted `) - case 91 : keysym = 123; break; // { (shifted [) - case 92 : keysym = 124; break; // | (shifted \) - case 93 : keysym = 125; break; // } (shifted ]) - case 39 : keysym = 34 ; break; // " (shifted ') - } - } else if ((keysym >= 65) && (keysym <=90)) { - /* Remap unshifted A-Z */ - keysym += 32; - } else if (evt.keyLocation === 3) { - // numpad keys - switch (keysym) { - case 96 : keysym = 48; break; // 0 - case 97 : keysym = 49; break; // 1 - case 98 : keysym = 50; break; // 2 - case 99 : keysym = 51; break; // 3 - case 100: keysym = 52; break; // 4 - case 101: keysym = 53; break; // 5 - case 102: keysym = 54; break; // 6 - case 103: keysym = 55; break; // 7 - case 104: keysym = 56; break; // 8 - case 105: keysym = 57; break; // 9 - case 109: keysym = 45; break; // - - case 110: keysym = 46; break; // . - case 111: keysym = 47; break; // / - } - } - } - - return keysym; -} - -/* Translate DOM keyPress event to keysym value */ -function getKeysym(evt) { - var keysym, msg; - - if (typeof(evt.which) !== "undefined") { - // WebKit, Firefox, Opera - keysym = evt.which; - } else { - // IE9 - Util.Warn("which not set, using keyCode"); - keysym = evt.keyCode; - } - - if ((keysym > 255) && (keysym < 0xFF00)) { - msg = "Mapping character code " + keysym; - // Map Unicode outside Latin 1 to X11 keysyms - keysym = unicodeTable[keysym]; - if (typeof(keysym) === 'undefined') { - keysym = 0; - } - Util.Debug(msg + " to " + keysym); - } - - return keysym; -} - -function show_keyDownList(kind) { - var c; - var msg = "keyDownList (" + kind + "):\n"; - for (c = 0; c < keyDownList.length; c++) { - msg = msg + " " + c + " - keyCode: " + keyDownList[c].keyCode + - " - which: " + keyDownList[c].which + "\n"; - } - Util.Debug(msg); -} - -function copyKeyEvent(evt) { - var members = ['type', 'keyCode', 'charCode', 'which', - 'altKey', 'ctrlKey', 'shiftKey', - 'keyLocation', 'keyIdentifier'], i, obj = {}; - for (i = 0; i < members.length; i++) { - if (typeof(evt[members[i]]) !== "undefined") { - obj[members[i]] = evt[members[i]]; - } - } - return obj; -} - -function pushKeyEvent(fevt) { - keyDownList.push(fevt); -} - -function getKeyEvent(keyCode, pop) { - var i, fevt = null; - for (i = keyDownList.length-1; i >= 0; i--) { - if (keyDownList[i].keyCode === keyCode) { - if ((typeof(pop) !== "undefined") && (pop)) { - fevt = keyDownList.splice(i, 1)[0]; - } else { - fevt = keyDownList[i]; - } - break; - } - } - return fevt; -} - -function ignoreKeyEvent(evt) { - // Blarg. Some keys have a different keyCode on keyDown vs keyUp - if (evt.keyCode === 229) { - // French AZERTY keyboard dead key. - // Lame thing is that the respective keyUp is 219 so we can't - // properly ignore the keyUp event - return true; - } - return false; -} - - -// -// Key Event Handling: -// -// There are several challenges when dealing with key events: -// - The meaning and use of keyCode, charCode and which depends on -// both the browser and the event type (keyDown/Up vs keyPress). -// - We cannot automatically determine the keyboard layout -// - The keyDown and keyUp events have a keyCode value that has not -// been translated by modifier keys. -// - The keyPress event has a translated (for layout and modifiers) -// character code but the attribute containing it differs. keyCode -// contains the translated value in WebKit (Chrome/Safari), Opera -// 11 and IE9. charCode contains the value in WebKit and Firefox. -// The which attribute contains the value on WebKit, Firefox and -// Opera 11. -// - The keyDown/Up keyCode value indicates (sort of) the physical -// key was pressed but only for standard US layout. On a US -// keyboard, the '-' and '_' characters are on the same key and -// generate a keyCode value of 189. But on an AZERTY keyboard even -// though they are different physical keys they both still -// generate a keyCode of 189! -// - To prevent a key event from propagating to the browser and -// causing unwanted default actions (such as closing a tab, -// opening a menu, shifting focus, etc) we must suppress this -// event in both keyDown and keyPress because not all key strokes -// generate on a keyPress event. Also, in WebKit and IE9 -// suppressing the keyDown prevents a keyPress but other browsers -// still generated a keyPress even if keyDown is suppressed. -// -// For safe key events, we wait until the keyPress event before -// reporting a key down event. For unsafe key events, we report a key -// down event when the keyDown event fires and we suppress any further -// actions (including keyPress). -// -// In order to report a key up event that matches what we reported -// for the key down event, we keep a list of keys that are currently -// down. When the keyDown event happens, we add the key event to the -// list. If it is a safe key event, then we update the which attribute -// in the most recent item on the list when we received a keyPress -// event (keyPress should immediately follow keyDown). When we -// received a keyUp event we search for the event on the list with -// a matching keyCode and we report the character code using the value -// in the 'which' attribute that was stored with that key. -// - -function onKeyDown(e) { - if (! conf.focused) { - return true; - } - var fevt = null, evt = (e ? e : window.event), - keysym = null, suppress = false; - //Util.Debug("onKeyDown kC:" + evt.keyCode + " cC:" + evt.charCode + " w:" + evt.which); - - fevt = copyKeyEvent(evt); - - keysym = getKeysymSpecial(evt); - // Save keysym decoding for use in keyUp - fevt.keysym = keysym; - if (keysym) { - // If it is a key or key combination that might trigger - // browser behaviors or it has no corresponding keyPress - // event, then send it immediately - if (conf.onKeyPress && !ignoreKeyEvent(evt)) { - Util.Debug("onKeyPress down, keysym: " + keysym + - " (onKeyDown key: " + evt.keyCode + - ", which: " + evt.which + ")"); - conf.onKeyPress(keysym, 1, evt); - } - suppress = true; - } - - if (! ignoreKeyEvent(evt)) { - // Add it to the list of depressed keys - pushKeyEvent(fevt); - //show_keyDownList('down'); - } - - if (suppress) { - // Suppress bubbling/default actions - Util.stopEvent(e); - return false; - } else { - // Allow the event to bubble and become a keyPress event which - // will have the character code translated - return true; - } -} - -function onKeyPress(e) { - if (! conf.focused) { - return true; - } - var evt = (e ? e : window.event), - kdlen = keyDownList.length, keysym = null; - //Util.Debug("onKeyPress kC:" + evt.keyCode + " cC:" + evt.charCode + " w:" + evt.which); - - if (((evt.which !== "undefined") && (evt.which === 0)) || - (getKeysymSpecial(evt))) { - // Firefox and Opera generate a keyPress event even if keyDown - // is suppressed. But the keys we want to suppress will have - // either: - // - the which attribute set to 0 - // - getKeysymSpecial() will identify it - Util.Debug("Ignoring special key in keyPress"); - Util.stopEvent(e); - return false; - } - - keysym = getKeysym(evt); - - // Modify the the which attribute in the depressed keys list so - // that the keyUp event will be able to have the character code - // translation available. - if (kdlen > 0) { - keyDownList[kdlen-1].keysym = keysym; - } else { - Util.Warn("keyDownList empty when keyPress triggered"); - } - - //show_keyDownList('press'); - - // Send the translated keysym - if (conf.onKeyPress && (keysym > 0)) { - Util.Debug("onKeyPress down, keysym: " + keysym + - " (onKeyPress key: " + evt.keyCode + - ", which: " + evt.which + ")"); - conf.onKeyPress(keysym, 1, evt); - } - - // Stop keypress events just in case - Util.stopEvent(e); - return false; -} - -function onKeyUp(e) { - if (! conf.focused) { - return true; - } - var fevt = null, evt = (e ? e : window.event), keysym; - //Util.Debug("onKeyUp kC:" + evt.keyCode + " cC:" + evt.charCode + " w:" + evt.which); - - fevt = getKeyEvent(evt.keyCode, true); - - if (fevt) { - keysym = fevt.keysym; - } else { - Util.Warn("Key event (keyCode = " + evt.keyCode + - ") not found on keyDownList"); - keysym = 0; - } - - //show_keyDownList('up'); - - if (conf.onKeyPress && (keysym > 0)) { - //Util.Debug("keyPress up, keysym: " + keysym + - // " (key: " + evt.keyCode + ", which: " + evt.which + ")"); - Util.Debug("onKeyPress up, keysym: " + keysym + - " (onKeyPress key: " + evt.keyCode + - ", which: " + evt.which + ")"); - conf.onKeyPress(keysym, 0, evt); - } - Util.stopEvent(e); - return false; -} - -function allKeysUp() { - Util.Debug(">> Keyboard.allKeysUp"); - if (keyDownList.length > 0) { - Util.Info("Releasing pressed/down keys"); - } - var i, keysym, fevt = null; - for (i = keyDownList.length-1; i >= 0; i--) { - fevt = keyDownList.splice(i, 1)[0]; - keysym = fevt.keysym; - if (conf.onKeyPress && (keysym > 0)) { - Util.Debug("allKeysUp, keysym: " + keysym + - " (keyCode: " + fevt.keyCode + - ", which: " + fevt.which + ")"); - conf.onKeyPress(keysym, 0, fevt); - } - } - Util.Debug("<< Keyboard.allKeysUp"); - return; -} - -// -// Public API interface functions -// - -that.grab = function() { - //Util.Debug(">> Keyboard.grab"); - var c = conf.target; - - Util.addEvent(c, 'keydown', onKeyDown); - Util.addEvent(c, 'keyup', onKeyUp); - Util.addEvent(c, 'keypress', onKeyPress); - - // Release (key up) if window loses focus - Util.addEvent(window, 'blur', allKeysUp); - - //Util.Debug("<< Keyboard.grab"); -}; - -that.ungrab = function() { - //Util.Debug(">> Keyboard.ungrab"); - var c = conf.target; - - Util.removeEvent(c, 'keydown', onKeyDown); - Util.removeEvent(c, 'keyup', onKeyUp); - Util.removeEvent(c, 'keypress', onKeyPress); - Util.removeEvent(window, 'blur', allKeysUp); - - // Release (key up) all keys that are in a down state - allKeysUp(); - - //Util.Debug(">> Keyboard.ungrab"); -}; - -return that; // Return the public API interface - -} // End of Keyboard() - - -// -// Mouse event handler -// - -function Mouse(defaults) { -"use strict"; - -var that = {}, // Public API methods - conf = {}, // Configuration attributes - mouseCaptured = false; - -var doubleClickTimer = null, - lastTouchPos = null; - -// Configuration attributes -Util.conf_defaults(conf, that, defaults, [ - ['target', 'ro', 'dom', document, 'DOM element that captures mouse input'], - ['focused', 'rw', 'bool', true, 'Capture and send mouse clicks/movement'], - ['scale', 'rw', 'float', 1.0, 'Viewport scale factor 0.0 - 1.0'], - - ['onMouseButton', 'rw', 'func', null, 'Handler for mouse button click/release'], - ['onMouseMove', 'rw', 'func', null, 'Handler for mouse movement'], - ['touchButton', 'rw', 'int', 1, 'Button mask (1, 2, 4) for touch devices (0 means ignore clicks)'] - ]); - -function captureMouse() { - // capturing the mouse ensures we get the mouseup event - if (conf.target.setCapture) { - conf.target.setCapture(); - } - - // some browsers give us mouseup events regardless, - // so if we never captured the mouse, we can disregard the event - mouseCaptured = true; -} - -function releaseMouse() { - if (conf.target.releaseCapture) { - conf.target.releaseCapture(); - } - mouseCaptured = false; -} -// -// Private functions -// - -function resetDoubleClickTimer() { - doubleClickTimer = null; -} - -function onMouseButton(e, down) { - var evt, pos, bmask; - if (! conf.focused) { - return true; - } - evt = (e ? e : window.event); - pos = Util.getEventPosition(e, conf.target, conf.scale); - - if (e.touches || e.changedTouches) { - // Touch device - - // When two touches occur within 500 ms of each other and are - // closer than 20 pixels together a double click is triggered. - if (down == 1) { - if (doubleClickTimer == null) { - lastTouchPos = pos; - } else { - clearTimeout(doubleClickTimer); - - // When the distance between the two touches is small enough - // force the position of the latter touch to the position of - // the first. - - var xs = lastTouchPos.x - pos.x; - var ys = lastTouchPos.y - pos.y; - var d = Math.sqrt((xs * xs) + (ys * ys)); - - // The goal is to trigger on a certain physical width, the - // devicePixelRatio brings us a bit closer but is not optimal. - if (d < 20 * window.devicePixelRatio) { - pos = lastTouchPos; - } - } - doubleClickTimer = setTimeout(resetDoubleClickTimer, 500); - } - bmask = conf.touchButton; - // If bmask is set - } else if (evt.which) { - /* everything except IE */ - bmask = 1 << evt.button; - } else { - /* IE including 9 */ - bmask = (evt.button & 0x1) + // Left - (evt.button & 0x2) * 2 + // Right - (evt.button & 0x4) / 2; // Middle - } - //Util.Debug("mouse " + pos.x + "," + pos.y + " down: " + down + - // " bmask: " + bmask + "(evt.button: " + evt.button + ")"); - if (conf.onMouseButton) { - Util.Debug("onMouseButton " + (down ? "down" : "up") + - ", x: " + pos.x + ", y: " + pos.y + ", bmask: " + bmask); - conf.onMouseButton(pos.x, pos.y, down, bmask); - } - Util.stopEvent(e); - return false; -} - -function onMouseDown(e) { - captureMouse(); - onMouseButton(e, 1); -} - -function onMouseUp(e) { - if (!mouseCaptured) { - return; - } - - onMouseButton(e, 0); - releaseMouse(); -} - -function onMouseWheel(e) { - var evt, pos, bmask, wheelData; - if (! conf.focused) { - return true; - } - evt = (e ? e : window.event); - pos = Util.getEventPosition(e, conf.target, conf.scale); - wheelData = evt.detail ? evt.detail * -1 : evt.wheelDelta / 40; - if (wheelData > 0) { - bmask = 1 << 3; - } else { - bmask = 1 << 4; - } - //Util.Debug('mouse scroll by ' + wheelData + ':' + pos.x + "," + pos.y); - if (conf.onMouseButton) { - conf.onMouseButton(pos.x, pos.y, 1, bmask); - conf.onMouseButton(pos.x, pos.y, 0, bmask); - } - Util.stopEvent(e); - return false; -} - -function onMouseMove(e) { - var evt, pos; - if (! conf.focused) { - return true; - } - evt = (e ? e : window.event); - pos = Util.getEventPosition(e, conf.target, conf.scale); - //Util.Debug('mouse ' + evt.which + '/' + evt.button + ' up:' + pos.x + "," + pos.y); - if (conf.onMouseMove) { - conf.onMouseMove(pos.x, pos.y); - } - Util.stopEvent(e); - return false; -} - -function onMouseDisable(e) { - var evt, pos; - if (! conf.focused) { - return true; - } - evt = (e ? e : window.event); - pos = Util.getEventPosition(e, conf.target, conf.scale); - /* Stop propagation if inside canvas area */ - if ((pos.realx >= 0) && (pos.realy >= 0) && - (pos.realx < conf.target.offsetWidth) && - (pos.realy < conf.target.offsetHeight)) { - //Util.Debug("mouse event disabled"); - Util.stopEvent(e); - return false; - } - //Util.Debug("mouse event not disabled"); - return true; -} - -// -// Public API interface functions -// - -that.grab = function() { - //Util.Debug(">> Mouse.grab"); - var c = conf.target; - - if ('ontouchstart' in document.documentElement) { - Util.addEvent(c, 'touchstart', onMouseDown); - Util.addEvent(window, 'touchend', onMouseUp); - Util.addEvent(c, 'touchend', onMouseUp); - Util.addEvent(c, 'touchmove', onMouseMove); - } else { - Util.addEvent(c, 'mousedown', onMouseDown); - Util.addEvent(window, 'mouseup', onMouseUp); - Util.addEvent(c, 'mouseup', onMouseUp); - Util.addEvent(c, 'mousemove', onMouseMove); - Util.addEvent(c, (Util.Engine.gecko) ? 'DOMMouseScroll' : 'mousewheel', - onMouseWheel); - } - - /* Work around right and middle click browser behaviors */ - Util.addEvent(document, 'click', onMouseDisable); - Util.addEvent(document.body, 'contextmenu', onMouseDisable); - - //Util.Debug("<< Mouse.grab"); -}; - -that.ungrab = function() { - //Util.Debug(">> Mouse.ungrab"); - var c = conf.target; - - if ('ontouchstart' in document.documentElement) { - Util.removeEvent(c, 'touchstart', onMouseDown); - Util.removeEvent(window, 'touchend', onMouseUp); - Util.removeEvent(c, 'touchend', onMouseUp); - Util.removeEvent(c, 'touchmove', onMouseMove); - } else { - Util.removeEvent(c, 'mousedown', onMouseDown); - Util.removeEvent(window, 'mouseup', onMouseUp); - Util.removeEvent(c, 'mouseup', onMouseUp); - Util.removeEvent(c, 'mousemove', onMouseMove); - Util.removeEvent(c, (Util.Engine.gecko) ? 'DOMMouseScroll' : 'mousewheel', - onMouseWheel); - } - - /* Work around right and middle click browser behaviors */ - Util.removeEvent(document, 'click', onMouseDisable); - Util.removeEvent(document.body, 'contextmenu', onMouseDisable); - - //Util.Debug(">> Mouse.ungrab"); -}; - -return that; // Return the public API interface - -} // End of Mouse() - - -/* - * Browser keypress to X11 keysym for Unicode characters > U+00FF - */ -unicodeTable = { - 0x0104 : 0x01a1, - 0x02D8 : 0x01a2, - 0x0141 : 0x01a3, - 0x013D : 0x01a5, - 0x015A : 0x01a6, - 0x0160 : 0x01a9, - 0x015E : 0x01aa, - 0x0164 : 0x01ab, - 0x0179 : 0x01ac, - 0x017D : 0x01ae, - 0x017B : 0x01af, - 0x0105 : 0x01b1, - 0x02DB : 0x01b2, - 0x0142 : 0x01b3, - 0x013E : 0x01b5, - 0x015B : 0x01b6, - 0x02C7 : 0x01b7, - 0x0161 : 0x01b9, - 0x015F : 0x01ba, - 0x0165 : 0x01bb, - 0x017A : 0x01bc, - 0x02DD : 0x01bd, - 0x017E : 0x01be, - 0x017C : 0x01bf, - 0x0154 : 0x01c0, - 0x0102 : 0x01c3, - 0x0139 : 0x01c5, - 0x0106 : 0x01c6, - 0x010C : 0x01c8, - 0x0118 : 0x01ca, - 0x011A : 0x01cc, - 0x010E : 0x01cf, - 0x0110 : 0x01d0, - 0x0143 : 0x01d1, - 0x0147 : 0x01d2, - 0x0150 : 0x01d5, - 0x0158 : 0x01d8, - 0x016E : 0x01d9, - 0x0170 : 0x01db, - 0x0162 : 0x01de, - 0x0155 : 0x01e0, - 0x0103 : 0x01e3, - 0x013A : 0x01e5, - 0x0107 : 0x01e6, - 0x010D : 0x01e8, - 0x0119 : 0x01ea, - 0x011B : 0x01ec, - 0x010F : 0x01ef, - 0x0111 : 0x01f0, - 0x0144 : 0x01f1, - 0x0148 : 0x01f2, - 0x0151 : 0x01f5, - 0x0171 : 0x01fb, - 0x0159 : 0x01f8, - 0x016F : 0x01f9, - 0x0163 : 0x01fe, - 0x02D9 : 0x01ff, - 0x0126 : 0x02a1, - 0x0124 : 0x02a6, - 0x0130 : 0x02a9, - 0x011E : 0x02ab, - 0x0134 : 0x02ac, - 0x0127 : 0x02b1, - 0x0125 : 0x02b6, - 0x0131 : 0x02b9, - 0x011F : 0x02bb, - 0x0135 : 0x02bc, - 0x010A : 0x02c5, - 0x0108 : 0x02c6, - 0x0120 : 0x02d5, - 0x011C : 0x02d8, - 0x016C : 0x02dd, - 0x015C : 0x02de, - 0x010B : 0x02e5, - 0x0109 : 0x02e6, - 0x0121 : 0x02f5, - 0x011D : 0x02f8, - 0x016D : 0x02fd, - 0x015D : 0x02fe, - 0x0138 : 0x03a2, - 0x0156 : 0x03a3, - 0x0128 : 0x03a5, - 0x013B : 0x03a6, - 0x0112 : 0x03aa, - 0x0122 : 0x03ab, - 0x0166 : 0x03ac, - 0x0157 : 0x03b3, - 0x0129 : 0x03b5, - 0x013C : 0x03b6, - 0x0113 : 0x03ba, - 0x0123 : 0x03bb, - 0x0167 : 0x03bc, - 0x014A : 0x03bd, - 0x014B : 0x03bf, - 0x0100 : 0x03c0, - 0x012E : 0x03c7, - 0x0116 : 0x03cc, - 0x012A : 0x03cf, - 0x0145 : 0x03d1, - 0x014C : 0x03d2, - 0x0136 : 0x03d3, - 0x0172 : 0x03d9, - 0x0168 : 0x03dd, - 0x016A : 0x03de, - 0x0101 : 0x03e0, - 0x012F : 0x03e7, - 0x0117 : 0x03ec, - 0x012B : 0x03ef, - 0x0146 : 0x03f1, - 0x014D : 0x03f2, - 0x0137 : 0x03f3, - 0x0173 : 0x03f9, - 0x0169 : 0x03fd, - 0x016B : 0x03fe, - 0x1E02 : 0x1001e02, - 0x1E03 : 0x1001e03, - 0x1E0A : 0x1001e0a, - 0x1E80 : 0x1001e80, - 0x1E82 : 0x1001e82, - 0x1E0B : 0x1001e0b, - 0x1EF2 : 0x1001ef2, - 0x1E1E : 0x1001e1e, - 0x1E1F : 0x1001e1f, - 0x1E40 : 0x1001e40, - 0x1E41 : 0x1001e41, - 0x1E56 : 0x1001e56, - 0x1E81 : 0x1001e81, - 0x1E57 : 0x1001e57, - 0x1E83 : 0x1001e83, - 0x1E60 : 0x1001e60, - 0x1EF3 : 0x1001ef3, - 0x1E84 : 0x1001e84, - 0x1E85 : 0x1001e85, - 0x1E61 : 0x1001e61, - 0x0174 : 0x1000174, - 0x1E6A : 0x1001e6a, - 0x0176 : 0x1000176, - 0x0175 : 0x1000175, - 0x1E6B : 0x1001e6b, - 0x0177 : 0x1000177, - 0x0152 : 0x13bc, - 0x0153 : 0x13bd, - 0x0178 : 0x13be, - 0x203E : 0x047e, - 0x3002 : 0x04a1, - 0x300C : 0x04a2, - 0x300D : 0x04a3, - 0x3001 : 0x04a4, - 0x30FB : 0x04a5, - 0x30F2 : 0x04a6, - 0x30A1 : 0x04a7, - 0x30A3 : 0x04a8, - 0x30A5 : 0x04a9, - 0x30A7 : 0x04aa, - 0x30A9 : 0x04ab, - 0x30E3 : 0x04ac, - 0x30E5 : 0x04ad, - 0x30E7 : 0x04ae, - 0x30C3 : 0x04af, - 0x30FC : 0x04b0, - 0x30A2 : 0x04b1, - 0x30A4 : 0x04b2, - 0x30A6 : 0x04b3, - 0x30A8 : 0x04b4, - 0x30AA : 0x04b5, - 0x30AB : 0x04b6, - 0x30AD : 0x04b7, - 0x30AF : 0x04b8, - 0x30B1 : 0x04b9, - 0x30B3 : 0x04ba, - 0x30B5 : 0x04bb, - 0x30B7 : 0x04bc, - 0x30B9 : 0x04bd, - 0x30BB : 0x04be, - 0x30BD : 0x04bf, - 0x30BF : 0x04c0, - 0x30C1 : 0x04c1, - 0x30C4 : 0x04c2, - 0x30C6 : 0x04c3, - 0x30C8 : 0x04c4, - 0x30CA : 0x04c5, - 0x30CB : 0x04c6, - 0x30CC : 0x04c7, - 0x30CD : 0x04c8, - 0x30CE : 0x04c9, - 0x30CF : 0x04ca, - 0x30D2 : 0x04cb, - 0x30D5 : 0x04cc, - 0x30D8 : 0x04cd, - 0x30DB : 0x04ce, - 0x30DE : 0x04cf, - 0x30DF : 0x04d0, - 0x30E0 : 0x04d1, - 0x30E1 : 0x04d2, - 0x30E2 : 0x04d3, - 0x30E4 : 0x04d4, - 0x30E6 : 0x04d5, - 0x30E8 : 0x04d6, - 0x30E9 : 0x04d7, - 0x30EA : 0x04d8, - 0x30EB : 0x04d9, - 0x30EC : 0x04da, - 0x30ED : 0x04db, - 0x30EF : 0x04dc, - 0x30F3 : 0x04dd, - 0x309B : 0x04de, - 0x309C : 0x04df, - 0x06F0 : 0x10006f0, - 0x06F1 : 0x10006f1, - 0x06F2 : 0x10006f2, - 0x06F3 : 0x10006f3, - 0x06F4 : 0x10006f4, - 0x06F5 : 0x10006f5, - 0x06F6 : 0x10006f6, - 0x06F7 : 0x10006f7, - 0x06F8 : 0x10006f8, - 0x06F9 : 0x10006f9, - 0x066A : 0x100066a, - 0x0670 : 0x1000670, - 0x0679 : 0x1000679, - 0x067E : 0x100067e, - 0x0686 : 0x1000686, - 0x0688 : 0x1000688, - 0x0691 : 0x1000691, - 0x060C : 0x05ac, - 0x06D4 : 0x10006d4, - 0x0660 : 0x1000660, - 0x0661 : 0x1000661, - 0x0662 : 0x1000662, - 0x0663 : 0x1000663, - 0x0664 : 0x1000664, - 0x0665 : 0x1000665, - 0x0666 : 0x1000666, - 0x0667 : 0x1000667, - 0x0668 : 0x1000668, - 0x0669 : 0x1000669, - 0x061B : 0x05bb, - 0x061F : 0x05bf, - 0x0621 : 0x05c1, - 0x0622 : 0x05c2, - 0x0623 : 0x05c3, - 0x0624 : 0x05c4, - 0x0625 : 0x05c5, - 0x0626 : 0x05c6, - 0x0627 : 0x05c7, - 0x0628 : 0x05c8, - 0x0629 : 0x05c9, - 0x062A : 0x05ca, - 0x062B : 0x05cb, - 0x062C : 0x05cc, - 0x062D : 0x05cd, - 0x062E : 0x05ce, - 0x062F : 0x05cf, - 0x0630 : 0x05d0, - 0x0631 : 0x05d1, - 0x0632 : 0x05d2, - 0x0633 : 0x05d3, - 0x0634 : 0x05d4, - 0x0635 : 0x05d5, - 0x0636 : 0x05d6, - 0x0637 : 0x05d7, - 0x0638 : 0x05d8, - 0x0639 : 0x05d9, - 0x063A : 0x05da, - 0x0640 : 0x05e0, - 0x0641 : 0x05e1, - 0x0642 : 0x05e2, - 0x0643 : 0x05e3, - 0x0644 : 0x05e4, - 0x0645 : 0x05e5, - 0x0646 : 0x05e6, - 0x0647 : 0x05e7, - 0x0648 : 0x05e8, - 0x0649 : 0x05e9, - 0x064A : 0x05ea, - 0x064B : 0x05eb, - 0x064C : 0x05ec, - 0x064D : 0x05ed, - 0x064E : 0x05ee, - 0x064F : 0x05ef, - 0x0650 : 0x05f0, - 0x0651 : 0x05f1, - 0x0652 : 0x05f2, - 0x0653 : 0x1000653, - 0x0654 : 0x1000654, - 0x0655 : 0x1000655, - 0x0698 : 0x1000698, - 0x06A4 : 0x10006a4, - 0x06A9 : 0x10006a9, - 0x06AF : 0x10006af, - 0x06BA : 0x10006ba, - 0x06BE : 0x10006be, - 0x06CC : 0x10006cc, - 0x06D2 : 0x10006d2, - 0x06C1 : 0x10006c1, - 0x0492 : 0x1000492, - 0x0493 : 0x1000493, - 0x0496 : 0x1000496, - 0x0497 : 0x1000497, - 0x049A : 0x100049a, - 0x049B : 0x100049b, - 0x049C : 0x100049c, - 0x049D : 0x100049d, - 0x04A2 : 0x10004a2, - 0x04A3 : 0x10004a3, - 0x04AE : 0x10004ae, - 0x04AF : 0x10004af, - 0x04B0 : 0x10004b0, - 0x04B1 : 0x10004b1, - 0x04B2 : 0x10004b2, - 0x04B3 : 0x10004b3, - 0x04B6 : 0x10004b6, - 0x04B7 : 0x10004b7, - 0x04B8 : 0x10004b8, - 0x04B9 : 0x10004b9, - 0x04BA : 0x10004ba, - 0x04BB : 0x10004bb, - 0x04D8 : 0x10004d8, - 0x04D9 : 0x10004d9, - 0x04E2 : 0x10004e2, - 0x04E3 : 0x10004e3, - 0x04E8 : 0x10004e8, - 0x04E9 : 0x10004e9, - 0x04EE : 0x10004ee, - 0x04EF : 0x10004ef, - 0x0452 : 0x06a1, - 0x0453 : 0x06a2, - 0x0451 : 0x06a3, - 0x0454 : 0x06a4, - 0x0455 : 0x06a5, - 0x0456 : 0x06a6, - 0x0457 : 0x06a7, - 0x0458 : 0x06a8, - 0x0459 : 0x06a9, - 0x045A : 0x06aa, - 0x045B : 0x06ab, - 0x045C : 0x06ac, - 0x0491 : 0x06ad, - 0x045E : 0x06ae, - 0x045F : 0x06af, - 0x2116 : 0x06b0, - 0x0402 : 0x06b1, - 0x0403 : 0x06b2, - 0x0401 : 0x06b3, - 0x0404 : 0x06b4, - 0x0405 : 0x06b5, - 0x0406 : 0x06b6, - 0x0407 : 0x06b7, - 0x0408 : 0x06b8, - 0x0409 : 0x06b9, - 0x040A : 0x06ba, - 0x040B : 0x06bb, - 0x040C : 0x06bc, - 0x0490 : 0x06bd, - 0x040E : 0x06be, - 0x040F : 0x06bf, - 0x044E : 0x06c0, - 0x0430 : 0x06c1, - 0x0431 : 0x06c2, - 0x0446 : 0x06c3, - 0x0434 : 0x06c4, - 0x0435 : 0x06c5, - 0x0444 : 0x06c6, - 0x0433 : 0x06c7, - 0x0445 : 0x06c8, - 0x0438 : 0x06c9, - 0x0439 : 0x06ca, - 0x043A : 0x06cb, - 0x043B : 0x06cc, - 0x043C : 0x06cd, - 0x043D : 0x06ce, - 0x043E : 0x06cf, - 0x043F : 0x06d0, - 0x044F : 0x06d1, - 0x0440 : 0x06d2, - 0x0441 : 0x06d3, - 0x0442 : 0x06d4, - 0x0443 : 0x06d5, - 0x0436 : 0x06d6, - 0x0432 : 0x06d7, - 0x044C : 0x06d8, - 0x044B : 0x06d9, - 0x0437 : 0x06da, - 0x0448 : 0x06db, - 0x044D : 0x06dc, - 0x0449 : 0x06dd, - 0x0447 : 0x06de, - 0x044A : 0x06df, - 0x042E : 0x06e0, - 0x0410 : 0x06e1, - 0x0411 : 0x06e2, - 0x0426 : 0x06e3, - 0x0414 : 0x06e4, - 0x0415 : 0x06e5, - 0x0424 : 0x06e6, - 0x0413 : 0x06e7, - 0x0425 : 0x06e8, - 0x0418 : 0x06e9, - 0x0419 : 0x06ea, - 0x041A : 0x06eb, - 0x041B : 0x06ec, - 0x041C : 0x06ed, - 0x041D : 0x06ee, - 0x041E : 0x06ef, - 0x041F : 0x06f0, - 0x042F : 0x06f1, - 0x0420 : 0x06f2, - 0x0421 : 0x06f3, - 0x0422 : 0x06f4, - 0x0423 : 0x06f5, - 0x0416 : 0x06f6, - 0x0412 : 0x06f7, - 0x042C : 0x06f8, - 0x042B : 0x06f9, - 0x0417 : 0x06fa, - 0x0428 : 0x06fb, - 0x042D : 0x06fc, - 0x0429 : 0x06fd, - 0x0427 : 0x06fe, - 0x042A : 0x06ff, - 0x0386 : 0x07a1, - 0x0388 : 0x07a2, - 0x0389 : 0x07a3, - 0x038A : 0x07a4, - 0x03AA : 0x07a5, - 0x038C : 0x07a7, - 0x038E : 0x07a8, - 0x03AB : 0x07a9, - 0x038F : 0x07ab, - 0x0385 : 0x07ae, - 0x2015 : 0x07af, - 0x03AC : 0x07b1, - 0x03AD : 0x07b2, - 0x03AE : 0x07b3, - 0x03AF : 0x07b4, - 0x03CA : 0x07b5, - 0x0390 : 0x07b6, - 0x03CC : 0x07b7, - 0x03CD : 0x07b8, - 0x03CB : 0x07b9, - 0x03B0 : 0x07ba, - 0x03CE : 0x07bb, - 0x0391 : 0x07c1, - 0x0392 : 0x07c2, - 0x0393 : 0x07c3, - 0x0394 : 0x07c4, - 0x0395 : 0x07c5, - 0x0396 : 0x07c6, - 0x0397 : 0x07c7, - 0x0398 : 0x07c8, - 0x0399 : 0x07c9, - 0x039A : 0x07ca, - 0x039B : 0x07cb, - 0x039C : 0x07cc, - 0x039D : 0x07cd, - 0x039E : 0x07ce, - 0x039F : 0x07cf, - 0x03A0 : 0x07d0, - 0x03A1 : 0x07d1, - 0x03A3 : 0x07d2, - 0x03A4 : 0x07d4, - 0x03A5 : 0x07d5, - 0x03A6 : 0x07d6, - 0x03A7 : 0x07d7, - 0x03A8 : 0x07d8, - 0x03A9 : 0x07d9, - 0x03B1 : 0x07e1, - 0x03B2 : 0x07e2, - 0x03B3 : 0x07e3, - 0x03B4 : 0x07e4, - 0x03B5 : 0x07e5, - 0x03B6 : 0x07e6, - 0x03B7 : 0x07e7, - 0x03B8 : 0x07e8, - 0x03B9 : 0x07e9, - 0x03BA : 0x07ea, - 0x03BB : 0x07eb, - 0x03BC : 0x07ec, - 0x03BD : 0x07ed, - 0x03BE : 0x07ee, - 0x03BF : 0x07ef, - 0x03C0 : 0x07f0, - 0x03C1 : 0x07f1, - 0x03C3 : 0x07f2, - 0x03C2 : 0x07f3, - 0x03C4 : 0x07f4, - 0x03C5 : 0x07f5, - 0x03C6 : 0x07f6, - 0x03C7 : 0x07f7, - 0x03C8 : 0x07f8, - 0x03C9 : 0x07f9, - 0x23B7 : 0x08a1, - 0x2320 : 0x08a4, - 0x2321 : 0x08a5, - 0x23A1 : 0x08a7, - 0x23A3 : 0x08a8, - 0x23A4 : 0x08a9, - 0x23A6 : 0x08aa, - 0x239B : 0x08ab, - 0x239D : 0x08ac, - 0x239E : 0x08ad, - 0x23A0 : 0x08ae, - 0x23A8 : 0x08af, - 0x23AC : 0x08b0, - 0x2264 : 0x08bc, - 0x2260 : 0x08bd, - 0x2265 : 0x08be, - 0x222B : 0x08bf, - 0x2234 : 0x08c0, - 0x221D : 0x08c1, - 0x221E : 0x08c2, - 0x2207 : 0x08c5, - 0x223C : 0x08c8, - 0x2243 : 0x08c9, - 0x21D4 : 0x08cd, - 0x21D2 : 0x08ce, - 0x2261 : 0x08cf, - //0x221A : 0x08d6, - 0x2282 : 0x08da, - 0x2283 : 0x08db, - 0x2229 : 0x08dc, - 0x222A : 0x08dd, - 0x2227 : 0x08de, - 0x2228 : 0x08df, - //0x2202 : 0x08ef, - 0x0192 : 0x08f6, - 0x2190 : 0x08fb, - 0x2191 : 0x08fc, - 0x2192 : 0x08fd, - 0x2193 : 0x08fe, - 0x25C6 : 0x09e0, - 0x2592 : 0x09e1, - 0x2409 : 0x09e2, - 0x240C : 0x09e3, - 0x240D : 0x09e4, - 0x240A : 0x09e5, - 0x2424 : 0x09e8, - 0x240B : 0x09e9, - 0x2518 : 0x09ea, - 0x2510 : 0x09eb, - 0x250C : 0x09ec, - 0x2514 : 0x09ed, - 0x253C : 0x09ee, - 0x23BA : 0x09ef, - 0x23BB : 0x09f0, - 0x2500 : 0x09f1, - 0x23BC : 0x09f2, - 0x23BD : 0x09f3, - 0x251C : 0x09f4, - 0x2524 : 0x09f5, - 0x2534 : 0x09f6, - 0x252C : 0x09f7, - 0x2502 : 0x09f8, - 0x2003 : 0x0aa1, - 0x2002 : 0x0aa2, - 0x2004 : 0x0aa3, - 0x2005 : 0x0aa4, - 0x2007 : 0x0aa5, - 0x2008 : 0x0aa6, - 0x2009 : 0x0aa7, - 0x200A : 0x0aa8, - 0x2014 : 0x0aa9, - 0x2013 : 0x0aaa, - 0x2026 : 0x0aae, - 0x2025 : 0x0aaf, - 0x2153 : 0x0ab0, - 0x2154 : 0x0ab1, - 0x2155 : 0x0ab2, - 0x2156 : 0x0ab3, - 0x2157 : 0x0ab4, - 0x2158 : 0x0ab5, - 0x2159 : 0x0ab6, - 0x215A : 0x0ab7, - 0x2105 : 0x0ab8, - 0x2012 : 0x0abb, - 0x215B : 0x0ac3, - 0x215C : 0x0ac4, - 0x215D : 0x0ac5, - 0x215E : 0x0ac6, - 0x2122 : 0x0ac9, - 0x2018 : 0x0ad0, - 0x2019 : 0x0ad1, - 0x201C : 0x0ad2, - 0x201D : 0x0ad3, - 0x211E : 0x0ad4, - 0x2032 : 0x0ad6, - 0x2033 : 0x0ad7, - 0x271D : 0x0ad9, - 0x2663 : 0x0aec, - 0x2666 : 0x0aed, - 0x2665 : 0x0aee, - 0x2720 : 0x0af0, - 0x2020 : 0x0af1, - 0x2021 : 0x0af2, - 0x2713 : 0x0af3, - 0x2717 : 0x0af4, - 0x266F : 0x0af5, - 0x266D : 0x0af6, - 0x2642 : 0x0af7, - 0x2640 : 0x0af8, - 0x260E : 0x0af9, - 0x2315 : 0x0afa, - 0x2117 : 0x0afb, - 0x2038 : 0x0afc, - 0x201A : 0x0afd, - 0x201E : 0x0afe, - 0x22A4 : 0x0bc2, - 0x230A : 0x0bc4, - 0x2218 : 0x0bca, - 0x2395 : 0x0bcc, - 0x22A5 : 0x0bce, - 0x25CB : 0x0bcf, - 0x2308 : 0x0bd3, - 0x22A3 : 0x0bdc, - 0x22A2 : 0x0bfc, - 0x2017 : 0x0cdf, - 0x05D0 : 0x0ce0, - 0x05D1 : 0x0ce1, - 0x05D2 : 0x0ce2, - 0x05D3 : 0x0ce3, - 0x05D4 : 0x0ce4, - 0x05D5 : 0x0ce5, - 0x05D6 : 0x0ce6, - 0x05D7 : 0x0ce7, - 0x05D8 : 0x0ce8, - 0x05D9 : 0x0ce9, - 0x05DA : 0x0cea, - 0x05DB : 0x0ceb, - 0x05DC : 0x0cec, - 0x05DD : 0x0ced, - 0x05DE : 0x0cee, - 0x05DF : 0x0cef, - 0x05E0 : 0x0cf0, - 0x05E1 : 0x0cf1, - 0x05E2 : 0x0cf2, - 0x05E3 : 0x0cf3, - 0x05E4 : 0x0cf4, - 0x05E5 : 0x0cf5, - 0x05E6 : 0x0cf6, - 0x05E7 : 0x0cf7, - 0x05E8 : 0x0cf8, - 0x05E9 : 0x0cf9, - 0x05EA : 0x0cfa, - 0x0E01 : 0x0da1, - 0x0E02 : 0x0da2, - 0x0E03 : 0x0da3, - 0x0E04 : 0x0da4, - 0x0E05 : 0x0da5, - 0x0E06 : 0x0da6, - 0x0E07 : 0x0da7, - 0x0E08 : 0x0da8, - 0x0E09 : 0x0da9, - 0x0E0A : 0x0daa, - 0x0E0B : 0x0dab, - 0x0E0C : 0x0dac, - 0x0E0D : 0x0dad, - 0x0E0E : 0x0dae, - 0x0E0F : 0x0daf, - 0x0E10 : 0x0db0, - 0x0E11 : 0x0db1, - 0x0E12 : 0x0db2, - 0x0E13 : 0x0db3, - 0x0E14 : 0x0db4, - 0x0E15 : 0x0db5, - 0x0E16 : 0x0db6, - 0x0E17 : 0x0db7, - 0x0E18 : 0x0db8, - 0x0E19 : 0x0db9, - 0x0E1A : 0x0dba, - 0x0E1B : 0x0dbb, - 0x0E1C : 0x0dbc, - 0x0E1D : 0x0dbd, - 0x0E1E : 0x0dbe, - 0x0E1F : 0x0dbf, - 0x0E20 : 0x0dc0, - 0x0E21 : 0x0dc1, - 0x0E22 : 0x0dc2, - 0x0E23 : 0x0dc3, - 0x0E24 : 0x0dc4, - 0x0E25 : 0x0dc5, - 0x0E26 : 0x0dc6, - 0x0E27 : 0x0dc7, - 0x0E28 : 0x0dc8, - 0x0E29 : 0x0dc9, - 0x0E2A : 0x0dca, - 0x0E2B : 0x0dcb, - 0x0E2C : 0x0dcc, - 0x0E2D : 0x0dcd, - 0x0E2E : 0x0dce, - 0x0E2F : 0x0dcf, - 0x0E30 : 0x0dd0, - 0x0E31 : 0x0dd1, - 0x0E32 : 0x0dd2, - 0x0E33 : 0x0dd3, - 0x0E34 : 0x0dd4, - 0x0E35 : 0x0dd5, - 0x0E36 : 0x0dd6, - 0x0E37 : 0x0dd7, - 0x0E38 : 0x0dd8, - 0x0E39 : 0x0dd9, - 0x0E3A : 0x0dda, - 0x0E3F : 0x0ddf, - 0x0E40 : 0x0de0, - 0x0E41 : 0x0de1, - 0x0E42 : 0x0de2, - 0x0E43 : 0x0de3, - 0x0E44 : 0x0de4, - 0x0E45 : 0x0de5, - 0x0E46 : 0x0de6, - 0x0E47 : 0x0de7, - 0x0E48 : 0x0de8, - 0x0E49 : 0x0de9, - 0x0E4A : 0x0dea, - 0x0E4B : 0x0deb, - 0x0E4C : 0x0dec, - 0x0E4D : 0x0ded, - 0x0E50 : 0x0df0, - 0x0E51 : 0x0df1, - 0x0E52 : 0x0df2, - 0x0E53 : 0x0df3, - 0x0E54 : 0x0df4, - 0x0E55 : 0x0df5, - 0x0E56 : 0x0df6, - 0x0E57 : 0x0df7, - 0x0E58 : 0x0df8, - 0x0E59 : 0x0df9, - 0x0587 : 0x1000587, - 0x0589 : 0x1000589, - 0x055D : 0x100055d, - 0x058A : 0x100058a, - 0x055C : 0x100055c, - 0x055B : 0x100055b, - 0x055E : 0x100055e, - 0x0531 : 0x1000531, - 0x0561 : 0x1000561, - 0x0532 : 0x1000532, - 0x0562 : 0x1000562, - 0x0533 : 0x1000533, - 0x0563 : 0x1000563, - 0x0534 : 0x1000534, - 0x0564 : 0x1000564, - 0x0535 : 0x1000535, - 0x0565 : 0x1000565, - 0x0536 : 0x1000536, - 0x0566 : 0x1000566, - 0x0537 : 0x1000537, - 0x0567 : 0x1000567, - 0x0538 : 0x1000538, - 0x0568 : 0x1000568, - 0x0539 : 0x1000539, - 0x0569 : 0x1000569, - 0x053A : 0x100053a, - 0x056A : 0x100056a, - 0x053B : 0x100053b, - 0x056B : 0x100056b, - 0x053C : 0x100053c, - 0x056C : 0x100056c, - 0x053D : 0x100053d, - 0x056D : 0x100056d, - 0x053E : 0x100053e, - 0x056E : 0x100056e, - 0x053F : 0x100053f, - 0x056F : 0x100056f, - 0x0540 : 0x1000540, - 0x0570 : 0x1000570, - 0x0541 : 0x1000541, - 0x0571 : 0x1000571, - 0x0542 : 0x1000542, - 0x0572 : 0x1000572, - 0x0543 : 0x1000543, - 0x0573 : 0x1000573, - 0x0544 : 0x1000544, - 0x0574 : 0x1000574, - 0x0545 : 0x1000545, - 0x0575 : 0x1000575, - 0x0546 : 0x1000546, - 0x0576 : 0x1000576, - 0x0547 : 0x1000547, - 0x0577 : 0x1000577, - 0x0548 : 0x1000548, - 0x0578 : 0x1000578, - 0x0549 : 0x1000549, - 0x0579 : 0x1000579, - 0x054A : 0x100054a, - 0x057A : 0x100057a, - 0x054B : 0x100054b, - 0x057B : 0x100057b, - 0x054C : 0x100054c, - 0x057C : 0x100057c, - 0x054D : 0x100054d, - 0x057D : 0x100057d, - 0x054E : 0x100054e, - 0x057E : 0x100057e, - 0x054F : 0x100054f, - 0x057F : 0x100057f, - 0x0550 : 0x1000550, - 0x0580 : 0x1000580, - 0x0551 : 0x1000551, - 0x0581 : 0x1000581, - 0x0552 : 0x1000552, - 0x0582 : 0x1000582, - 0x0553 : 0x1000553, - 0x0583 : 0x1000583, - 0x0554 : 0x1000554, - 0x0584 : 0x1000584, - 0x0555 : 0x1000555, - 0x0585 : 0x1000585, - 0x0556 : 0x1000556, - 0x0586 : 0x1000586, - 0x055A : 0x100055a, - 0x10D0 : 0x10010d0, - 0x10D1 : 0x10010d1, - 0x10D2 : 0x10010d2, - 0x10D3 : 0x10010d3, - 0x10D4 : 0x10010d4, - 0x10D5 : 0x10010d5, - 0x10D6 : 0x10010d6, - 0x10D7 : 0x10010d7, - 0x10D8 : 0x10010d8, - 0x10D9 : 0x10010d9, - 0x10DA : 0x10010da, - 0x10DB : 0x10010db, - 0x10DC : 0x10010dc, - 0x10DD : 0x10010dd, - 0x10DE : 0x10010de, - 0x10DF : 0x10010df, - 0x10E0 : 0x10010e0, - 0x10E1 : 0x10010e1, - 0x10E2 : 0x10010e2, - 0x10E3 : 0x10010e3, - 0x10E4 : 0x10010e4, - 0x10E5 : 0x10010e5, - 0x10E6 : 0x10010e6, - 0x10E7 : 0x10010e7, - 0x10E8 : 0x10010e8, - 0x10E9 : 0x10010e9, - 0x10EA : 0x10010ea, - 0x10EB : 0x10010eb, - 0x10EC : 0x10010ec, - 0x10ED : 0x10010ed, - 0x10EE : 0x10010ee, - 0x10EF : 0x10010ef, - 0x10F0 : 0x10010f0, - 0x10F1 : 0x10010f1, - 0x10F2 : 0x10010f2, - 0x10F3 : 0x10010f3, - 0x10F4 : 0x10010f4, - 0x10F5 : 0x10010f5, - 0x10F6 : 0x10010f6, - 0x1E8A : 0x1001e8a, - 0x012C : 0x100012c, - 0x01B5 : 0x10001b5, - 0x01E6 : 0x10001e6, - 0x01D2 : 0x10001d1, - 0x019F : 0x100019f, - 0x1E8B : 0x1001e8b, - 0x012D : 0x100012d, - 0x01B6 : 0x10001b6, - 0x01E7 : 0x10001e7, - //0x01D2 : 0x10001d2, - 0x0275 : 0x1000275, - 0x018F : 0x100018f, - 0x0259 : 0x1000259, - 0x1E36 : 0x1001e36, - 0x1E37 : 0x1001e37, - 0x1EA0 : 0x1001ea0, - 0x1EA1 : 0x1001ea1, - 0x1EA2 : 0x1001ea2, - 0x1EA3 : 0x1001ea3, - 0x1EA4 : 0x1001ea4, - 0x1EA5 : 0x1001ea5, - 0x1EA6 : 0x1001ea6, - 0x1EA7 : 0x1001ea7, - 0x1EA8 : 0x1001ea8, - 0x1EA9 : 0x1001ea9, - 0x1EAA : 0x1001eaa, - 0x1EAB : 0x1001eab, - 0x1EAC : 0x1001eac, - 0x1EAD : 0x1001ead, - 0x1EAE : 0x1001eae, - 0x1EAF : 0x1001eaf, - 0x1EB0 : 0x1001eb0, - 0x1EB1 : 0x1001eb1, - 0x1EB2 : 0x1001eb2, - 0x1EB3 : 0x1001eb3, - 0x1EB4 : 0x1001eb4, - 0x1EB5 : 0x1001eb5, - 0x1EB6 : 0x1001eb6, - 0x1EB7 : 0x1001eb7, - 0x1EB8 : 0x1001eb8, - 0x1EB9 : 0x1001eb9, - 0x1EBA : 0x1001eba, - 0x1EBB : 0x1001ebb, - 0x1EBC : 0x1001ebc, - 0x1EBD : 0x1001ebd, - 0x1EBE : 0x1001ebe, - 0x1EBF : 0x1001ebf, - 0x1EC0 : 0x1001ec0, - 0x1EC1 : 0x1001ec1, - 0x1EC2 : 0x1001ec2, - 0x1EC3 : 0x1001ec3, - 0x1EC4 : 0x1001ec4, - 0x1EC5 : 0x1001ec5, - 0x1EC6 : 0x1001ec6, - 0x1EC7 : 0x1001ec7, - 0x1EC8 : 0x1001ec8, - 0x1EC9 : 0x1001ec9, - 0x1ECA : 0x1001eca, - 0x1ECB : 0x1001ecb, - 0x1ECC : 0x1001ecc, - 0x1ECD : 0x1001ecd, - 0x1ECE : 0x1001ece, - 0x1ECF : 0x1001ecf, - 0x1ED0 : 0x1001ed0, - 0x1ED1 : 0x1001ed1, - 0x1ED2 : 0x1001ed2, - 0x1ED3 : 0x1001ed3, - 0x1ED4 : 0x1001ed4, - 0x1ED5 : 0x1001ed5, - 0x1ED6 : 0x1001ed6, - 0x1ED7 : 0x1001ed7, - 0x1ED8 : 0x1001ed8, - 0x1ED9 : 0x1001ed9, - 0x1EDA : 0x1001eda, - 0x1EDB : 0x1001edb, - 0x1EDC : 0x1001edc, - 0x1EDD : 0x1001edd, - 0x1EDE : 0x1001ede, - 0x1EDF : 0x1001edf, - 0x1EE0 : 0x1001ee0, - 0x1EE1 : 0x1001ee1, - 0x1EE2 : 0x1001ee2, - 0x1EE3 : 0x1001ee3, - 0x1EE4 : 0x1001ee4, - 0x1EE5 : 0x1001ee5, - 0x1EE6 : 0x1001ee6, - 0x1EE7 : 0x1001ee7, - 0x1EE8 : 0x1001ee8, - 0x1EE9 : 0x1001ee9, - 0x1EEA : 0x1001eea, - 0x1EEB : 0x1001eeb, - 0x1EEC : 0x1001eec, - 0x1EED : 0x1001eed, - 0x1EEE : 0x1001eee, - 0x1EEF : 0x1001eef, - 0x1EF0 : 0x1001ef0, - 0x1EF1 : 0x1001ef1, - 0x1EF4 : 0x1001ef4, - 0x1EF5 : 0x1001ef5, - 0x1EF6 : 0x1001ef6, - 0x1EF7 : 0x1001ef7, - 0x1EF8 : 0x1001ef8, - 0x1EF9 : 0x1001ef9, - 0x01A0 : 0x10001a0, - 0x01A1 : 0x10001a1, - 0x01AF : 0x10001af, - 0x01B0 : 0x10001b0, - 0x20A0 : 0x10020a0, - 0x20A1 : 0x10020a1, - 0x20A2 : 0x10020a2, - 0x20A3 : 0x10020a3, - 0x20A4 : 0x10020a4, - 0x20A5 : 0x10020a5, - 0x20A6 : 0x10020a6, - 0x20A7 : 0x10020a7, - 0x20A8 : 0x10020a8, - 0x20A9 : 0x10020a9, - 0x20AA : 0x10020aa, - 0x20AB : 0x10020ab, - 0x20AC : 0x20ac, - 0x2070 : 0x1002070, - 0x2074 : 0x1002074, - 0x2075 : 0x1002075, - 0x2076 : 0x1002076, - 0x2077 : 0x1002077, - 0x2078 : 0x1002078, - 0x2079 : 0x1002079, - 0x2080 : 0x1002080, - 0x2081 : 0x1002081, - 0x2082 : 0x1002082, - 0x2083 : 0x1002083, - 0x2084 : 0x1002084, - 0x2085 : 0x1002085, - 0x2086 : 0x1002086, - 0x2087 : 0x1002087, - 0x2088 : 0x1002088, - 0x2089 : 0x1002089, - 0x2202 : 0x1002202, - 0x2205 : 0x1002205, - 0x2208 : 0x1002208, - 0x2209 : 0x1002209, - 0x220B : 0x100220B, - 0x221A : 0x100221A, - 0x221B : 0x100221B, - 0x221C : 0x100221C, - 0x222C : 0x100222C, - 0x222D : 0x100222D, - 0x2235 : 0x1002235, - 0x2245 : 0x1002248, - 0x2247 : 0x1002247, - 0x2262 : 0x1002262, - 0x2263 : 0x1002263, - 0x2800 : 0x1002800, - 0x2801 : 0x1002801, - 0x2802 : 0x1002802, - 0x2803 : 0x1002803, - 0x2804 : 0x1002804, - 0x2805 : 0x1002805, - 0x2806 : 0x1002806, - 0x2807 : 0x1002807, - 0x2808 : 0x1002808, - 0x2809 : 0x1002809, - 0x280a : 0x100280a, - 0x280b : 0x100280b, - 0x280c : 0x100280c, - 0x280d : 0x100280d, - 0x280e : 0x100280e, - 0x280f : 0x100280f, - 0x2810 : 0x1002810, - 0x2811 : 0x1002811, - 0x2812 : 0x1002812, - 0x2813 : 0x1002813, - 0x2814 : 0x1002814, - 0x2815 : 0x1002815, - 0x2816 : 0x1002816, - 0x2817 : 0x1002817, - 0x2818 : 0x1002818, - 0x2819 : 0x1002819, - 0x281a : 0x100281a, - 0x281b : 0x100281b, - 0x281c : 0x100281c, - 0x281d : 0x100281d, - 0x281e : 0x100281e, - 0x281f : 0x100281f, - 0x2820 : 0x1002820, - 0x2821 : 0x1002821, - 0x2822 : 0x1002822, - 0x2823 : 0x1002823, - 0x2824 : 0x1002824, - 0x2825 : 0x1002825, - 0x2826 : 0x1002826, - 0x2827 : 0x1002827, - 0x2828 : 0x1002828, - 0x2829 : 0x1002829, - 0x282a : 0x100282a, - 0x282b : 0x100282b, - 0x282c : 0x100282c, - 0x282d : 0x100282d, - 0x282e : 0x100282e, - 0x282f : 0x100282f, - 0x2830 : 0x1002830, - 0x2831 : 0x1002831, - 0x2832 : 0x1002832, - 0x2833 : 0x1002833, - 0x2834 : 0x1002834, - 0x2835 : 0x1002835, - 0x2836 : 0x1002836, - 0x2837 : 0x1002837, - 0x2838 : 0x1002838, - 0x2839 : 0x1002839, - 0x283a : 0x100283a, - 0x283b : 0x100283b, - 0x283c : 0x100283c, - 0x283d : 0x100283d, - 0x283e : 0x100283e, - 0x283f : 0x100283f, - 0x2840 : 0x1002840, - 0x2841 : 0x1002841, - 0x2842 : 0x1002842, - 0x2843 : 0x1002843, - 0x2844 : 0x1002844, - 0x2845 : 0x1002845, - 0x2846 : 0x1002846, - 0x2847 : 0x1002847, - 0x2848 : 0x1002848, - 0x2849 : 0x1002849, - 0x284a : 0x100284a, - 0x284b : 0x100284b, - 0x284c : 0x100284c, - 0x284d : 0x100284d, - 0x284e : 0x100284e, - 0x284f : 0x100284f, - 0x2850 : 0x1002850, - 0x2851 : 0x1002851, - 0x2852 : 0x1002852, - 0x2853 : 0x1002853, - 0x2854 : 0x1002854, - 0x2855 : 0x1002855, - 0x2856 : 0x1002856, - 0x2857 : 0x1002857, - 0x2858 : 0x1002858, - 0x2859 : 0x1002859, - 0x285a : 0x100285a, - 0x285b : 0x100285b, - 0x285c : 0x100285c, - 0x285d : 0x100285d, - 0x285e : 0x100285e, - 0x285f : 0x100285f, - 0x2860 : 0x1002860, - 0x2861 : 0x1002861, - 0x2862 : 0x1002862, - 0x2863 : 0x1002863, - 0x2864 : 0x1002864, - 0x2865 : 0x1002865, - 0x2866 : 0x1002866, - 0x2867 : 0x1002867, - 0x2868 : 0x1002868, - 0x2869 : 0x1002869, - 0x286a : 0x100286a, - 0x286b : 0x100286b, - 0x286c : 0x100286c, - 0x286d : 0x100286d, - 0x286e : 0x100286e, - 0x286f : 0x100286f, - 0x2870 : 0x1002870, - 0x2871 : 0x1002871, - 0x2872 : 0x1002872, - 0x2873 : 0x1002873, - 0x2874 : 0x1002874, - 0x2875 : 0x1002875, - 0x2876 : 0x1002876, - 0x2877 : 0x1002877, - 0x2878 : 0x1002878, - 0x2879 : 0x1002879, - 0x287a : 0x100287a, - 0x287b : 0x100287b, - 0x287c : 0x100287c, - 0x287d : 0x100287d, - 0x287e : 0x100287e, - 0x287f : 0x100287f, - 0x2880 : 0x1002880, - 0x2881 : 0x1002881, - 0x2882 : 0x1002882, - 0x2883 : 0x1002883, - 0x2884 : 0x1002884, - 0x2885 : 0x1002885, - 0x2886 : 0x1002886, - 0x2887 : 0x1002887, - 0x2888 : 0x1002888, - 0x2889 : 0x1002889, - 0x288a : 0x100288a, - 0x288b : 0x100288b, - 0x288c : 0x100288c, - 0x288d : 0x100288d, - 0x288e : 0x100288e, - 0x288f : 0x100288f, - 0x2890 : 0x1002890, - 0x2891 : 0x1002891, - 0x2892 : 0x1002892, - 0x2893 : 0x1002893, - 0x2894 : 0x1002894, - 0x2895 : 0x1002895, - 0x2896 : 0x1002896, - 0x2897 : 0x1002897, - 0x2898 : 0x1002898, - 0x2899 : 0x1002899, - 0x289a : 0x100289a, - 0x289b : 0x100289b, - 0x289c : 0x100289c, - 0x289d : 0x100289d, - 0x289e : 0x100289e, - 0x289f : 0x100289f, - 0x28a0 : 0x10028a0, - 0x28a1 : 0x10028a1, - 0x28a2 : 0x10028a2, - 0x28a3 : 0x10028a3, - 0x28a4 : 0x10028a4, - 0x28a5 : 0x10028a5, - 0x28a6 : 0x10028a6, - 0x28a7 : 0x10028a7, - 0x28a8 : 0x10028a8, - 0x28a9 : 0x10028a9, - 0x28aa : 0x10028aa, - 0x28ab : 0x10028ab, - 0x28ac : 0x10028ac, - 0x28ad : 0x10028ad, - 0x28ae : 0x10028ae, - 0x28af : 0x10028af, - 0x28b0 : 0x10028b0, - 0x28b1 : 0x10028b1, - 0x28b2 : 0x10028b2, - 0x28b3 : 0x10028b3, - 0x28b4 : 0x10028b4, - 0x28b5 : 0x10028b5, - 0x28b6 : 0x10028b6, - 0x28b7 : 0x10028b7, - 0x28b8 : 0x10028b8, - 0x28b9 : 0x10028b9, - 0x28ba : 0x10028ba, - 0x28bb : 0x10028bb, - 0x28bc : 0x10028bc, - 0x28bd : 0x10028bd, - 0x28be : 0x10028be, - 0x28bf : 0x10028bf, - 0x28c0 : 0x10028c0, - 0x28c1 : 0x10028c1, - 0x28c2 : 0x10028c2, - 0x28c3 : 0x10028c3, - 0x28c4 : 0x10028c4, - 0x28c5 : 0x10028c5, - 0x28c6 : 0x10028c6, - 0x28c7 : 0x10028c7, - 0x28c8 : 0x10028c8, - 0x28c9 : 0x10028c9, - 0x28ca : 0x10028ca, - 0x28cb : 0x10028cb, - 0x28cc : 0x10028cc, - 0x28cd : 0x10028cd, - 0x28ce : 0x10028ce, - 0x28cf : 0x10028cf, - 0x28d0 : 0x10028d0, - 0x28d1 : 0x10028d1, - 0x28d2 : 0x10028d2, - 0x28d3 : 0x10028d3, - 0x28d4 : 0x10028d4, - 0x28d5 : 0x10028d5, - 0x28d6 : 0x10028d6, - 0x28d7 : 0x10028d7, - 0x28d8 : 0x10028d8, - 0x28d9 : 0x10028d9, - 0x28da : 0x10028da, - 0x28db : 0x10028db, - 0x28dc : 0x10028dc, - 0x28dd : 0x10028dd, - 0x28de : 0x10028de, - 0x28df : 0x10028df, - 0x28e0 : 0x10028e0, - 0x28e1 : 0x10028e1, - 0x28e2 : 0x10028e2, - 0x28e3 : 0x10028e3, - 0x28e4 : 0x10028e4, - 0x28e5 : 0x10028e5, - 0x28e6 : 0x10028e6, - 0x28e7 : 0x10028e7, - 0x28e8 : 0x10028e8, - 0x28e9 : 0x10028e9, - 0x28ea : 0x10028ea, - 0x28eb : 0x10028eb, - 0x28ec : 0x10028ec, - 0x28ed : 0x10028ed, - 0x28ee : 0x10028ee, - 0x28ef : 0x10028ef, - 0x28f0 : 0x10028f0, - 0x28f1 : 0x10028f1, - 0x28f2 : 0x10028f2, - 0x28f3 : 0x10028f3, - 0x28f4 : 0x10028f4, - 0x28f5 : 0x10028f5, - 0x28f6 : 0x10028f6, - 0x28f7 : 0x10028f7, - 0x28f8 : 0x10028f8, - 0x28f9 : 0x10028f9, - 0x28fa : 0x10028fa, - 0x28fb : 0x10028fb, - 0x28fc : 0x10028fc, - 0x28fd : 0x10028fd, - 0x28fe : 0x10028fe, - 0x28ff : 0x10028ff -}; diff --git a/circle/dashboard/static/dashboard/novnc/jsunzip.js b/circle/dashboard/static/dashboard/novnc/jsunzip.js deleted file mode 100755 index 8968f86..0000000 --- a/circle/dashboard/static/dashboard/novnc/jsunzip.js +++ /dev/null @@ -1,676 +0,0 @@ -/* - * JSUnzip - * - * Copyright (c) 2011 by Erik Moller - * All Rights Reserved - * - * This software is provided 'as-is', without any express - * or implied warranty. In no event will the authors be - * held liable for any damages arising from the use of - * this software. - * - * Permission is granted to anyone to use this software - * for any purpose, including commercial applications, - * and to alter it and redistribute it freely, subject to - * the following restrictions: - * - * 1. The origin of this software must not be - * misrepresented; you must not claim that you - * wrote the original software. If you use this - * software in a product, an acknowledgment in - * the product documentation would be appreciated - * but is not required. - * - * 2. Altered source versions must be plainly marked - * as such, and must not be misrepresented as - * being the original software. - * - * 3. This notice may not be removed or altered from - * any source distribution. - */ - -var tinf; - -function JSUnzip() { - - this.getInt = function(offset, size) { - switch (size) { - case 4: - return (this.data.charCodeAt(offset + 3) & 0xff) << 24 | - (this.data.charCodeAt(offset + 2) & 0xff) << 16 | - (this.data.charCodeAt(offset + 1) & 0xff) << 8 | - (this.data.charCodeAt(offset + 0) & 0xff); - break; - case 2: - return (this.data.charCodeAt(offset + 1) & 0xff) << 8 | - (this.data.charCodeAt(offset + 0) & 0xff); - break; - default: - return this.data.charCodeAt(offset) & 0xff; - break; - } - }; - - this.getDOSDate = function(dosdate, dostime) { - var day = dosdate & 0x1f; - var month = ((dosdate >> 5) & 0xf) - 1; - var year = 1980 + ((dosdate >> 9) & 0x7f) - var second = (dostime & 0x1f) * 2; - var minute = (dostime >> 5) & 0x3f; - hour = (dostime >> 11) & 0x1f; - return new Date(year, month, day, hour, minute, second); - } - - this.open = function(data) { - this.data = data; - this.files = []; - - if (this.data.length < 22) - return { 'status' : false, 'error' : 'Invalid data' }; - var endOfCentralDirectory = this.data.length - 22; - while (endOfCentralDirectory >= 0 && this.getInt(endOfCentralDirectory, 4) != 0x06054b50) - --endOfCentralDirectory; - if (endOfCentralDirectory < 0) - return { 'status' : false, 'error' : 'Invalid data' }; - if (this.getInt(endOfCentralDirectory + 4, 2) != 0 || this.getInt(endOfCentralDirectory + 6, 2) != 0) - return { 'status' : false, 'error' : 'No multidisk support' }; - - var entriesInThisDisk = this.getInt(endOfCentralDirectory + 8, 2); - var centralDirectoryOffset = this.getInt(endOfCentralDirectory + 16, 4); - var globalCommentLength = this.getInt(endOfCentralDirectory + 20, 2); - this.comment = this.data.slice(endOfCentralDirectory + 22, endOfCentralDirectory + 22 + globalCommentLength); - - var fileOffset = centralDirectoryOffset; - - for (var i = 0; i < entriesInThisDisk; ++i) { - if (this.getInt(fileOffset + 0, 4) != 0x02014b50) - return { 'status' : false, 'error' : 'Invalid data' }; - if (this.getInt(fileOffset + 6, 2) > 20) - return { 'status' : false, 'error' : 'Unsupported version' }; - if (this.getInt(fileOffset + 8, 2) & 1) - return { 'status' : false, 'error' : 'Encryption not implemented' }; - - var compressionMethod = this.getInt(fileOffset + 10, 2); - if (compressionMethod != 0 && compressionMethod != 8) - return { 'status' : false, 'error' : 'Unsupported compression method' }; - - var lastModFileTime = this.getInt(fileOffset + 12, 2); - var lastModFileDate = this.getInt(fileOffset + 14, 2); - var lastModifiedDate = this.getDOSDate(lastModFileDate, lastModFileTime); - - var crc = this.getInt(fileOffset + 16, 4); - // TODO: crc - - var compressedSize = this.getInt(fileOffset + 20, 4); - var uncompressedSize = this.getInt(fileOffset + 24, 4); - - var fileNameLength = this.getInt(fileOffset + 28, 2); - var extraFieldLength = this.getInt(fileOffset + 30, 2); - var fileCommentLength = this.getInt(fileOffset + 32, 2); - - var relativeOffsetOfLocalHeader = this.getInt(fileOffset + 42, 4); - - var fileName = this.data.slice(fileOffset + 46, fileOffset + 46 + fileNameLength); - var fileComment = this.data.slice(fileOffset + 46 + fileNameLength + extraFieldLength, fileOffset + 46 + fileNameLength + extraFieldLength + fileCommentLength); - - if (this.getInt(relativeOffsetOfLocalHeader + 0, 4) != 0x04034b50) - return { 'status' : false, 'error' : 'Invalid data' }; - var localFileNameLength = this.getInt(relativeOffsetOfLocalHeader + 26, 2); - var localExtraFieldLength = this.getInt(relativeOffsetOfLocalHeader + 28, 2); - var localFileContent = relativeOffsetOfLocalHeader + 30 + localFileNameLength + localExtraFieldLength; - - this.files[fileName] = - { - 'fileComment' : fileComment, - 'compressionMethod' : compressionMethod, - 'compressedSize' : compressedSize, - 'uncompressedSize' : uncompressedSize, - 'localFileContent' : localFileContent, - 'lastModifiedDate' : lastModifiedDate - }; - - fileOffset += 46 + fileNameLength + extraFieldLength + fileCommentLength; - } - return { 'status' : true } - }; - - - this.read = function(fileName) { - var fileInfo = this.files[fileName]; - if (fileInfo) { - if (fileInfo.compressionMethod == 8) { - if (!tinf) { - tinf = new TINF(); - tinf.init(); - } - var result = tinf.uncompress(this.data, fileInfo.localFileContent); - if (result.status == tinf.OK) - return { 'status' : true, 'data' : result.data }; - else - return { 'status' : false, 'error' : result.error }; - } else { - return { 'status' : true, 'data' : this.data.slice(fileInfo.localFileContent, fileInfo.localFileContent + fileInfo.uncompressedSize) }; - } - } - return { 'status' : false, 'error' : "File '" + fileName + "' doesn't exist in zip" }; - }; - -}; - - - -/* - * tinflate - tiny inflate - * - * Copyright (c) 2003 by Joergen Ibsen / Jibz - * All Rights Reserved - * - * http://www.ibsensoftware.com/ - * - * This software is provided 'as-is', without any express - * or implied warranty. In no event will the authors be - * held liable for any damages arising from the use of - * this software. - * - * Permission is granted to anyone to use this software - * for any purpose, including commercial applications, - * and to alter it and redistribute it freely, subject to - * the following restrictions: - * - * 1. The origin of this software must not be - * misrepresented; you must not claim that you - * wrote the original software. If you use this - * software in a product, an acknowledgment in - * the product documentation would be appreciated - * but is not required. - * - * 2. Altered source versions must be plainly marked - * as such, and must not be misrepresented as - * being the original software. - * - * 3. This notice may not be removed or altered from - * any source distribution. - */ - -/* - * tinflate javascript port by Erik Moller in May 2011. - * emoller@opera.com - * - * read_bits() patched by mike@imidio.com to allow - * reading more then 8 bits (needed in some zlib streams) - */ - -"use strict"; - -function TINF() { - -this.OK = 0; -this.DATA_ERROR = (-3); -this.WINDOW_SIZE = 32768; - -/* ------------------------------ * - * -- internal data structures -- * - * ------------------------------ */ - -this.TREE = function() { - this.table = new Array(16); /* table of code length counts */ - this.trans = new Array(288); /* code -> symbol translation table */ -}; - -this.DATA = function(that) { - this.source = ''; - this.sourceIndex = 0; - this.tag = 0; - this.bitcount = 0; - - this.dest = []; - - this.history = []; - - this.ltree = new that.TREE(); /* dynamic length/symbol tree */ - this.dtree = new that.TREE(); /* dynamic distance tree */ -}; - -/* --------------------------------------------------- * - * -- uninitialized global data (static structures) -- * - * --------------------------------------------------- */ - -this.sltree = new this.TREE(); /* fixed length/symbol tree */ -this.sdtree = new this.TREE(); /* fixed distance tree */ - -/* extra bits and base tables for length codes */ -this.length_bits = new Array(30); -this.length_base = new Array(30); - -/* extra bits and base tables for distance codes */ -this.dist_bits = new Array(30); -this.dist_base = new Array(30); - -/* special ordering of code length codes */ -this.clcidx = [ - 16, 17, 18, 0, 8, 7, 9, 6, - 10, 5, 11, 4, 12, 3, 13, 2, - 14, 1, 15 -]; - -/* ----------------------- * - * -- utility functions -- * - * ----------------------- */ - -/* build extra bits and base tables */ -this.build_bits_base = function(bits, base, delta, first) -{ - var i, sum; - - /* build bits table */ - for (i = 0; i < delta; ++i) bits[i] = 0; - for (i = 0; i < 30 - delta; ++i) bits[i + delta] = Math.floor(i / delta); - - /* build base table */ - for (sum = first, i = 0; i < 30; ++i) - { - base[i] = sum; - sum += 1 << bits[i]; - } -} - -/* build the fixed huffman trees */ -this.build_fixed_trees = function(lt, dt) -{ - var i; - - /* build fixed length tree */ - for (i = 0; i < 7; ++i) lt.table[i] = 0; - - lt.table[7] = 24; - lt.table[8] = 152; - lt.table[9] = 112; - - for (i = 0; i < 24; ++i) lt.trans[i] = 256 + i; - for (i = 0; i < 144; ++i) lt.trans[24 + i] = i; - for (i = 0; i < 8; ++i) lt.trans[24 + 144 + i] = 280 + i; - for (i = 0; i < 112; ++i) lt.trans[24 + 144 + 8 + i] = 144 + i; - - /* build fixed distance tree */ - for (i = 0; i < 5; ++i) dt.table[i] = 0; - - dt.table[5] = 32; - - for (i = 0; i < 32; ++i) dt.trans[i] = i; -} - -/* given an array of code lengths, build a tree */ -this.build_tree = function(t, lengths, loffset, num) -{ - var offs = new Array(16); - var i, sum; - - /* clear code length count table */ - for (i = 0; i < 16; ++i) t.table[i] = 0; - - /* scan symbol lengths, and sum code length counts */ - for (i = 0; i < num; ++i) t.table[lengths[loffset + i]]++; - - t.table[0] = 0; - - /* compute offset table for distribution sort */ - for (sum = 0, i = 0; i < 16; ++i) - { - offs[i] = sum; - sum += t.table[i]; - } - - /* create code->symbol translation table (symbols sorted by code) */ - for (i = 0; i < num; ++i) - { - if (lengths[loffset + i]) t.trans[offs[lengths[loffset + i]]++] = i; - } -} - -/* ---------------------- * - * -- decode functions -- * - * ---------------------- */ - -/* get one bit from source stream */ -this.getbit = function(d) -{ - var bit; - - /* check if tag is empty */ - if (!d.bitcount--) - { - /* load next tag */ - d.tag = d.source[d.sourceIndex++] & 0xff; - d.bitcount = 7; - } - - /* shift bit out of tag */ - bit = d.tag & 0x01; - d.tag >>= 1; - - return bit; -} - -/* read a num bit value from a stream and add base */ -function read_bits_direct(source, bitcount, tag, idx, num) -{ - var val = 0; - while (bitcount < 24) { - tag = tag | (source[idx++] & 0xff) << bitcount; - bitcount += 8; - } - val = tag & (0xffff >> (16 - num)); - tag >>= num; - bitcount -= num; - return [bitcount, tag, idx, val]; -} -this.read_bits = function(d, num, base) -{ - if (!num) - return base; - - var ret = read_bits_direct(d.source, d.bitcount, d.tag, d.sourceIndex, num); - d.bitcount = ret[0]; - d.tag = ret[1]; - d.sourceIndex = ret[2]; - return ret[3] + base; -} - -/* given a data stream and a tree, decode a symbol */ -this.decode_symbol = function(d, t) -{ - while (d.bitcount < 16) { - d.tag = d.tag | (d.source[d.sourceIndex++] & 0xff) << d.bitcount; - d.bitcount += 8; - } - - var sum = 0, cur = 0, len = 0; - do { - cur = 2 * cur + ((d.tag & (1 << len)) >> len); - - ++len; - - sum += t.table[len]; - cur -= t.table[len]; - - } while (cur >= 0); - - d.tag >>= len; - d.bitcount -= len; - - return t.trans[sum + cur]; -} - -/* given a data stream, decode dynamic trees from it */ -this.decode_trees = function(d, lt, dt) -{ - var code_tree = new this.TREE(); - var lengths = new Array(288+32); - var hlit, hdist, hclen; - var i, num, length; - - /* get 5 bits HLIT (257-286) */ - hlit = this.read_bits(d, 5, 257); - - /* get 5 bits HDIST (1-32) */ - hdist = this.read_bits(d, 5, 1); - - /* get 4 bits HCLEN (4-19) */ - hclen = this.read_bits(d, 4, 4); - - for (i = 0; i < 19; ++i) lengths[i] = 0; - - /* read code lengths for code length alphabet */ - for (i = 0; i < hclen; ++i) - { - /* get 3 bits code length (0-7) */ - var clen = this.read_bits(d, 3, 0); - - lengths[this.clcidx[i]] = clen; - } - - /* build code length tree */ - this.build_tree(code_tree, lengths, 0, 19); - - /* decode code lengths for the dynamic trees */ - for (num = 0; num < hlit + hdist; ) - { - var sym = this.decode_symbol(d, code_tree); - - switch (sym) - { - case 16: - /* copy previous code length 3-6 times (read 2 bits) */ - { - var prev = lengths[num - 1]; - for (length = this.read_bits(d, 2, 3); length; --length) - { - lengths[num++] = prev; - } - } - break; - case 17: - /* repeat code length 0 for 3-10 times (read 3 bits) */ - for (length = this.read_bits(d, 3, 3); length; --length) - { - lengths[num++] = 0; - } - break; - case 18: - /* repeat code length 0 for 11-138 times (read 7 bits) */ - for (length = this.read_bits(d, 7, 11); length; --length) - { - lengths[num++] = 0; - } - break; - default: - /* values 0-15 represent the actual code lengths */ - lengths[num++] = sym; - break; - } - } - - /* build dynamic trees */ - this.build_tree(lt, lengths, 0, hlit); - this.build_tree(dt, lengths, hlit, hdist); -} - -/* ----------------------------- * - * -- block inflate functions -- * - * ----------------------------- */ - -/* given a stream and two trees, inflate a block of data */ -this.inflate_block_data = function(d, lt, dt) -{ - // js optimization. - var ddest = d.dest; - var ddestlength = ddest.length; - - while (1) - { - var sym = this.decode_symbol(d, lt); - - /* check for end of block */ - if (sym == 256) - { - return this.OK; - } - - if (sym < 256) - { - ddest[ddestlength++] = sym; // ? String.fromCharCode(sym); - d.history.push(sym); - } else { - - var length, dist, offs; - var i; - - sym -= 257; - - /* possibly get more bits from length code */ - length = this.read_bits(d, this.length_bits[sym], this.length_base[sym]); - - dist = this.decode_symbol(d, dt); - - /* possibly get more bits from distance code */ - offs = d.history.length - this.read_bits(d, this.dist_bits[dist], this.dist_base[dist]); - - if (offs < 0) - throw ("Invalid zlib offset " + offs); - - /* copy match */ - for (i = offs; i < offs + length; ++i) { - //ddest[ddestlength++] = ddest[i]; - ddest[ddestlength++] = d.history[i]; - d.history.push(d.history[i]); - } - } - } -} - -/* inflate an uncompressed block of data */ -this.inflate_uncompressed_block = function(d) -{ - var length, invlength; - var i; - - if (d.bitcount > 7) { - var overflow = Math.floor(d.bitcount / 8); - d.sourceIndex -= overflow; - d.bitcount = 0; - d.tag = 0; - } - - /* get length */ - length = d.source[d.sourceIndex+1]; - length = 256*length + d.source[d.sourceIndex]; - - /* get one's complement of length */ - invlength = d.source[d.sourceIndex+3]; - invlength = 256*invlength + d.source[d.sourceIndex+2]; - - /* check length */ - if (length != (~invlength & 0x0000ffff)) return this.DATA_ERROR; - - d.sourceIndex += 4; - - /* copy block */ - for (i = length; i; --i) { - d.history.push(d.source[d.sourceIndex]); - d.dest[d.dest.length] = d.source[d.sourceIndex++]; - } - - /* make sure we start next block on a byte boundary */ - d.bitcount = 0; - - return this.OK; -} - -/* inflate a block of data compressed with fixed huffman trees */ -this.inflate_fixed_block = function(d) -{ - /* decode block using fixed trees */ - return this.inflate_block_data(d, this.sltree, this.sdtree); -} - -/* inflate a block of data compressed with dynamic huffman trees */ -this.inflate_dynamic_block = function(d) -{ - /* decode trees from stream */ - this.decode_trees(d, d.ltree, d.dtree); - - /* decode block using decoded trees */ - return this.inflate_block_data(d, d.ltree, d.dtree); -} - -/* ---------------------- * - * -- public functions -- * - * ---------------------- */ - -/* initialize global (static) data */ -this.init = function() -{ - /* build fixed huffman trees */ - this.build_fixed_trees(this.sltree, this.sdtree); - - /* build extra bits and base tables */ - this.build_bits_base(this.length_bits, this.length_base, 4, 3); - this.build_bits_base(this.dist_bits, this.dist_base, 2, 1); - - /* fix a special case */ - this.length_bits[28] = 0; - this.length_base[28] = 258; - - this.reset(); -} - -this.reset = function() -{ - this.d = new this.DATA(this); - delete this.header; -} - -/* inflate stream from source to dest */ -this.uncompress = function(source, offset) -{ - - var d = this.d; - var bfinal; - - /* initialise data */ - d.source = source; - d.sourceIndex = offset; - d.bitcount = 0; - - d.dest = []; - - // Skip zlib header at start of stream - if (typeof this.header == 'undefined') { - this.header = this.read_bits(d, 16, 0); - /* byte 0: 0x78, 7 = 32k window size, 8 = deflate */ - /* byte 1: check bits for header and other flags */ - } - - var blocks = 0; - - do { - - var btype; - var res; - - /* read final block flag */ - bfinal = this.getbit(d); - - /* read block type (2 bits) */ - btype = this.read_bits(d, 2, 0); - - /* decompress block */ - switch (btype) - { - case 0: - /* decompress uncompressed block */ - res = this.inflate_uncompressed_block(d); - break; - case 1: - /* decompress block with fixed huffman trees */ - res = this.inflate_fixed_block(d); - break; - case 2: - /* decompress block with dynamic huffman trees */ - res = this.inflate_dynamic_block(d); - break; - default: - return { 'status' : this.DATA_ERROR }; - } - - if (res != this.OK) return { 'status' : this.DATA_ERROR }; - blocks++; - - } while (!bfinal && d.sourceIndex < d.source.length); - - d.history = d.history.slice(-this.WINDOW_SIZE); - - return { 'status' : this.OK, 'data' : d.dest }; -} - -}; diff --git a/circle/dashboard/static/dashboard/novnc/logo.js b/circle/dashboard/static/dashboard/novnc/logo.js deleted file mode 100644 index befa598..0000000 --- a/circle/dashboard/static/dashboard/novnc/logo.js +++ /dev/null @@ -1 +0,0 @@ -noVNC_logo = {"width": 640, "height": 435, "data": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAoAAAAGzCAYAAAC/y6a9AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAStAAAErQBBHTWggAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAACAASURBVHic7N13fBvlwQfw3522ZMm2vPdIGCFkA4GyoYyGsCmjk+7dQksHL2/H2/dtC4W2tLTlfelu2VA2lEILFCgQIHEGJCQkdjzkLdmWZGvfvX8oOkmJEy/pNO73/Xz44DtLzz2RT7qfnnXC8uXLZUxDlqfdnUYQhIP+bjbPn+5xhypzrmUf6rGzOc5cjzVduXN9/nTPyfRrMt/jzOcY05U5n3L2f95s/34LPW4m/p6FbLp/73xe+5nKnWuZs/07ZOOcnusx5nucbJU727LneuxslDmdTBxn/2NmusyEuZS7kHMxG/XP5Gf3TOVmQzY+u/PhPMnkMcSsH5WIiIiI8goDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHG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"}; diff --git a/circle/dashboard/static/dashboard/novnc/playback.js b/circle/dashboard/static/dashboard/novnc/playback.js deleted file mode 100644 index 7756529..0000000 --- a/circle/dashboard/static/dashboard/novnc/playback.js +++ /dev/null @@ -1,102 +0,0 @@ -/* - * noVNC: HTML5 VNC client - * Copyright (C) 2012 Joel Martin - * Licensed under MPL 2.0 (see LICENSE.txt) - */ - -"use strict"; -/*jslint browser: true, white: false */ -/*global Util, VNC_frame_data, finish */ - -var rfb, mode, test_state, frame_idx, frame_length, - iteration, iterations, istart_time, - - // Pre-declarations for jslint - send_array, next_iteration, queue_next_packet, do_packet; - -// Override send_array -send_array = function (arr) { - // Stub out send_array -}; - -next_iteration = function () { - if (iteration === 0) { - frame_length = VNC_frame_data.length; - test_state = 'running'; - } else { - rfb.disconnect(); - } - - if (test_state !== 'running') { return; } - - iteration += 1; - if (iteration > iterations) { - finish(); - return; - } - - frame_idx = 0; - istart_time = (new Date()).getTime(); - rfb.connect('test', 0, "bogus"); - - queue_next_packet(); - -}; - -queue_next_packet = function () { - var frame, foffset, toffset, delay; - if (test_state !== 'running') { return; } - - frame = VNC_frame_data[frame_idx]; - while ((frame_idx < frame_length) && (frame.charAt(0) === "}")) { - //Util.Debug("Send frame " + frame_idx); - frame_idx += 1; - frame = VNC_frame_data[frame_idx]; - } - - if (frame === 'EOF') { - Util.Debug("Finished, found EOF"); - next_iteration(); - return; - } - if (frame_idx >= frame_length) { - Util.Debug("Finished, no more frames"); - next_iteration(); - return; - } - - if (mode === 'realtime') { - foffset = frame.slice(1, frame.indexOf('{', 1)); - toffset = (new Date()).getTime() - istart_time; - delay = foffset - toffset; - if (delay < 1) { - delay = 1; - } - - setTimeout(do_packet, delay); - } else { - setTimeout(do_packet, 1); - } -}; - -var bytes_processed = 0; - -do_packet = function () { - //Util.Debug("Processing frame: " + frame_idx); - var frame = VNC_frame_data[frame_idx], - start = frame.indexOf('{', 1) + 1; - bytes_processed += frame.length - start; - if (VNC_frame_encoding === 'binary') { - var u8 = new Uint8Array(frame.length - start); - for (var i = 0; i < frame.length - start; i++) { - u8[i] = frame.charCodeAt(start + i); - } - rfb.recv_message({'data' : u8}); - } else { - rfb.recv_message({'data' : frame.slice(start)}); - } - frame_idx += 1; - - queue_next_packet(); -}; - diff --git a/circle/dashboard/static/dashboard/novnc/rfb.js b/circle/dashboard/static/dashboard/novnc/rfb.js deleted file mode 100644 index 16ae76d..0000000 --- a/circle/dashboard/static/dashboard/novnc/rfb.js +++ /dev/null @@ -1,1872 +0,0 @@ -/* - * noVNC: HTML5 VNC client - * Copyright (C) 2012 Joel Martin - * Copyright (C) 2013 Samuel Mannehed for Cendio AB - * Licensed under MPL 2.0 (see LICENSE.txt) - * - * See README.md for usage and integration instructions. - * - * TIGHT decoder portion: - * (c) 2012 Michael Tinglof, Joe Balaz, Les Piech (Mercuri.ca) - */ - -/*jslint white: false, browser: true, bitwise: false, plusplus: false */ -/*global window, Util, Display, Keyboard, Mouse, Websock, Websock_native, Base64, DES */ - - -function RFB(defaults) { -"use strict"; - -var that = {}, // Public API methods - conf = {}, // Configuration attributes - - // Pre-declare private functions used before definitions (jslint) - init_vars, updateState, fail, handle_message, - init_msg, normal_msg, framebufferUpdate, print_stats, - - pixelFormat, clientEncodings, fbUpdateRequest, fbUpdateRequests, - keyEvent, pointerEvent, clientCutText, - - getTightCLength, extract_data_uri, - keyPress, mouseButton, mouseMove, - - checkEvents, // Overridable for testing - - - // - // Private RFB namespace variables - // - rfb_host = '', - rfb_port = 5900, - rfb_password = '', - rfb_path = '', - - rfb_state = 'disconnected', - rfb_version = 0, - rfb_max_version= 3.8, - rfb_auth_scheme= '', - - - // In preference order - encodings = [ - ['COPYRECT', 0x01 ], - ['TIGHT', 0x07 ], - ['TIGHT_PNG', -260 ], - ['HEXTILE', 0x05 ], - ['RRE', 0x02 ], - ['RAW', 0x00 ], - ['DesktopSize', -223 ], - ['Cursor', -239 ], - - // Psuedo-encoding settings - //['JPEG_quality_lo', -32 ], - ['JPEG_quality_med', -26 ], - //['JPEG_quality_hi', -23 ], - //['compress_lo', -255 ], - ['compress_hi', -247 ], - ['last_rect', -224 ] - ], - - encHandlers = {}, - encNames = {}, - encStats = {}, // [rectCnt, rectCntTot] - - ws = null, // Websock object - display = null, // Display object - keyboard = null, // Keyboard input handler object - mouse = null, // Mouse input handler object - sendTimer = null, // Send Queue check timer - connTimer = null, // connection timer - disconnTimer = null, // disconnection timer - msgTimer = null, // queued handle_message timer - - // Frame buffer update state - FBU = { - rects : 0, - subrects : 0, // RRE - lines : 0, // RAW - tiles : 0, // HEXTILE - bytes : 0, - x : 0, - y : 0, - width : 0, - height : 0, - encoding : 0, - subencoding : -1, - background : null, - zlibs : [] // TIGHT zlib streams - }, - - fb_Bpp = 4, - fb_depth = 3, - fb_width = 0, - fb_height = 0, - fb_name = "", - - last_req_time = 0, - rre_chunk_sz = 100, - - timing = { - last_fbu : 0, - fbu_total : 0, - fbu_total_cnt : 0, - full_fbu_total : 0, - full_fbu_cnt : 0, - - fbu_rt_start : 0, - fbu_rt_total : 0, - fbu_rt_cnt : 0, - pixels : 0 - }, - - test_mode = false, - - def_con_timeout = Websock_native ? 2 : 5, - - /* Mouse state */ - mouse_buttonMask = 0, - mouse_arr = [], - viewportDragging = false, - viewportDragPos = {}; - -// Configuration attributes -Util.conf_defaults(conf, that, defaults, [ - ['target', 'wo', 'dom', null, 'VNC display rendering Canvas object'], - ['focusContainer', 'wo', 'dom', document, 'DOM element that captures keyboard input'], - - ['encrypt', 'rw', 'bool', false, 'Use TLS/SSL/wss encryption'], - ['true_color', 'rw', 'bool', true, 'Request true color pixel data'], - ['local_cursor', 'rw', 'bool', false, 'Request locally rendered cursor'], - ['shared', 'rw', 'bool', true, 'Request shared mode'], - ['view_only', 'rw', 'bool', false, 'Disable client mouse/keyboard'], - - ['connectTimeout', 'rw', 'int', def_con_timeout, 'Time (s) to wait for connection'], - ['disconnectTimeout', 'rw', 'int', 3, 'Time (s) to wait for disconnection'], - - // UltraVNC repeater ID to connect to - ['repeaterID', 'rw', 'str', '', 'RepeaterID to connect to'], - - ['viewportDrag', 'rw', 'bool', false, 'Move the viewport on mouse drags'], - - ['check_rate', 'rw', 'int', 217, 'Timing (ms) of send/receive check'], - ['fbu_req_rate', 'rw', 'int', 1413, 'Timing (ms) of frameBufferUpdate requests'], - - // Callback functions - ['onUpdateState', 'rw', 'func', function() { }, - 'onUpdateState(rfb, state, oldstate, statusMsg): RFB state update/change '], - ['onPasswordRequired', 'rw', 'func', function() { }, - 'onPasswordRequired(rfb): VNC password is required '], - ['onClipboard', 'rw', 'func', function() { }, - 'onClipboard(rfb, text): RFB clipboard contents received'], - ['onBell', 'rw', 'func', function() { }, - 'onBell(rfb): RFB Bell message received '], - ['onFBUReceive', 'rw', 'func', function() { }, - 'onFBUReceive(rfb, fbu): RFB FBU received but not yet processed '], - ['onFBUComplete', 'rw', 'func', function() { }, - 'onFBUComplete(rfb, fbu): RFB FBU received and processed '], - ['onFBResize', 'rw', 'func', function() { }, - 'onFBResize(rfb, width, height): frame buffer resized'], - ['onDesktopName', 'rw', 'func', function() { }, - 'onDesktopName(rfb, name): desktop name received'], - - // These callback names are deprecated - ['updateState', 'rw', 'func', function() { }, - 'obsolete, use onUpdateState'], - ['clipboardReceive', 'rw', 'func', function() { }, - 'obsolete, use onClipboard'] - ]); - - -// Override/add some specific configuration getters/setters -that.set_local_cursor = function(cursor) { - if ((!cursor) || (cursor in {'0':1, 'no':1, 'false':1})) { - conf.local_cursor = false; - } else { - if (display.get_cursor_uri()) { - conf.local_cursor = true; - } else { - Util.Warn("Browser does not support local cursor"); - } - } -}; - -// These are fake configuration getters -that.get_display = function() { return display; }; - -that.get_keyboard = function() { return keyboard; }; - -that.get_mouse = function() { return mouse; }; - - - -// -// Setup routines -// - -// Create the public API interface and initialize values that stay -// constant across connect/disconnect -function constructor() { - var i, rmode; - Util.Debug(">> RFB.constructor"); - - // Create lookup tables based encoding number - for (i=0; i < encodings.length; i+=1) { - encHandlers[encodings[i][1]] = encHandlers[encodings[i][0]]; - encNames[encodings[i][1]] = encodings[i][0]; - encStats[encodings[i][1]] = [0, 0]; - } - // Initialize display, mouse, keyboard, and websock - try { - display = new Display({'target': conf.target}); - } catch (exc) { - Util.Error("Display exception: " + exc); - updateState('fatal', "No working Display"); - } - keyboard = new Keyboard({'target': conf.focusContainer, - 'onKeyPress': keyPress}); - mouse = new Mouse({'target': conf.target, - 'onMouseButton': mouseButton, - 'onMouseMove': mouseMove}); - - rmode = display.get_render_mode(); - - ws = new Websock(); - ws.on('message', handle_message); - ws.on('open', function() { - if (rfb_state === "connect") { - updateState('ProtocolVersion', "Starting VNC handshake"); - } else { - fail("Got unexpected WebSockets connection"); - } - }); - ws.on('close', function(e) { - Util.Warn("WebSocket on-close event"); - var msg = ""; - if (e.code) { - msg = " (code: " + e.code; - if (e.reason) { - msg += ", reason: " + e.reason; - } - msg += ")"; - } - if (rfb_state === 'disconnect') { - updateState('disconnected', 'VNC disconnected' + msg); - } else if (rfb_state === 'ProtocolVersion') { - fail('Failed to connect to server' + msg); - } else if (rfb_state in {'failed':1, 'disconnected':1}) { - Util.Error("Received onclose while disconnected" + msg); - } else { - fail('Server disconnected' + msg); - } - }); - ws.on('error', function(e) { - Util.Warn("WebSocket on-error event"); - //fail("WebSock reported an error"); - }); - - - init_vars(); - - /* Check web-socket-js if no builtin WebSocket support */ - if (Websock_native) { - Util.Info("Using native WebSockets"); - updateState('loaded', 'noVNC ready: native WebSockets, ' + rmode); - } else { - Util.Warn("Using web-socket-js bridge. Flash version: " + - Util.Flash.version); - if ((! Util.Flash) || - (Util.Flash.version < 9)) { - updateState('fatal', "WebSockets or Adobe Flash<\/a> is required"); - } else if (document.location.href.substr(0, 7) === "file://") { - updateState('fatal', - "'file://' URL is incompatible with Adobe Flash"); - } else { - updateState('loaded', 'noVNC ready: WebSockets emulation, ' + rmode); - } - } - - Util.Debug("<< RFB.constructor"); - return that; // Return the public API interface -} - -function connect() { - Util.Debug(">> RFB.connect"); - var uri; - - if (typeof UsingSocketIO !== "undefined") { - uri = "http://" + rfb_host + ":" + rfb_port + "/" + rfb_path; - } else { - if (conf.encrypt) { - uri = "wss://"; - } else { - uri = "ws://"; - } - uri += rfb_host + ":" + rfb_port + "/" + rfb_path; - } - Util.Info("connecting to " + uri); - // TODO: make protocols a configurable - ws.open(uri, ['binary', 'base64']); - - Util.Debug("<< RFB.connect"); -} - -// Initialize variables that are reset before each connection -init_vars = function() { - var i; - - /* Reset state */ - ws.init(); - - FBU.rects = 0; - FBU.subrects = 0; // RRE and HEXTILE - FBU.lines = 0; // RAW - FBU.tiles = 0; // HEXTILE - FBU.zlibs = []; // TIGHT zlib encoders - mouse_buttonMask = 0; - mouse_arr = []; - - // Clear the per connection encoding stats - for (i=0; i < encodings.length; i+=1) { - encStats[encodings[i][1]][0] = 0; - } - - for (i=0; i < 4; i++) { - //FBU.zlibs[i] = new InflateStream(); - FBU.zlibs[i] = new TINF(); - FBU.zlibs[i].init(); - } -}; - -// Print statistics -print_stats = function() { - var i, s; - Util.Info("Encoding stats for this connection:"); - for (i=0; i < encodings.length; i+=1) { - s = encStats[encodings[i][1]]; - if ((s[0] + s[1]) > 0) { - Util.Info(" " + encodings[i][0] + ": " + - s[0] + " rects"); - } - } - Util.Info("Encoding stats since page load:"); - for (i=0; i < encodings.length; i+=1) { - s = encStats[encodings[i][1]]; - if ((s[0] + s[1]) > 0) { - Util.Info(" " + encodings[i][0] + ": " + - s[1] + " rects"); - } - } -}; - -// -// Utility routines -// - - -/* - * Page states: - * loaded - page load, equivalent to disconnected - * disconnected - idle state - * connect - starting to connect (to ProtocolVersion) - * normal - connected - * disconnect - starting to disconnect - * failed - abnormal disconnect - * fatal - failed to load page, or fatal error - * - * RFB protocol initialization states: - * ProtocolVersion - * Security - * Authentication - * password - waiting for password, not part of RFB - * SecurityResult - * ClientInitialization - not triggered by server message - * ServerInitialization (to normal) - */ -updateState = function(state, statusMsg) { - var func, cmsg, oldstate = rfb_state; - - if (state === oldstate) { - /* Already here, ignore */ - Util.Debug("Already in state '" + state + "', ignoring."); - return; - } - - /* - * These are disconnected states. A previous connect may - * asynchronously cause a connection so make sure we are closed. - */ - if (state in {'disconnected':1, 'loaded':1, 'connect':1, - 'disconnect':1, 'failed':1, 'fatal':1}) { - if (sendTimer) { - clearInterval(sendTimer); - sendTimer = null; - } - - if (msgTimer) { - clearInterval(msgTimer); - msgTimer = null; - } - - if (display && display.get_context()) { - keyboard.ungrab(); - mouse.ungrab(); - display.defaultCursor(); - if ((Util.get_logging() !== 'debug') || - (state === 'loaded')) { - // Show noVNC logo on load and when disconnected if - // debug is off - display.clear(); - } - } - - ws.close(); - } - - if (oldstate === 'fatal') { - Util.Error("Fatal error, cannot continue"); - } - - if ((state === 'failed') || (state === 'fatal')) { - func = Util.Error; - } else { - func = Util.Warn; - } - - cmsg = typeof(statusMsg) !== 'undefined' ? (" Msg: " + statusMsg) : ""; - func("New state '" + state + "', was '" + oldstate + "'." + cmsg); - - if ((oldstate === 'failed') && (state === 'disconnected')) { - // Do disconnect action, but stay in failed state - rfb_state = 'failed'; - } else { - rfb_state = state; - } - - if (connTimer && (rfb_state !== 'connect')) { - Util.Debug("Clearing connect timer"); - clearInterval(connTimer); - connTimer = null; - } - - if (disconnTimer && (rfb_state !== 'disconnect')) { - Util.Debug("Clearing disconnect timer"); - clearInterval(disconnTimer); - disconnTimer = null; - } - - switch (state) { - case 'normal': - if ((oldstate === 'disconnected') || (oldstate === 'failed')) { - Util.Error("Invalid transition from 'disconnected' or 'failed' to 'normal'"); - } - - break; - - - case 'connect': - - connTimer = setTimeout(function () { - fail("Connect timeout"); - }, conf.connectTimeout * 1000); - - init_vars(); - connect(); - - // WebSocket.onopen transitions to 'ProtocolVersion' - break; - - - case 'disconnect': - - if (! test_mode) { - disconnTimer = setTimeout(function () { - fail("Disconnect timeout"); - }, conf.disconnectTimeout * 1000); - } - - print_stats(); - - // WebSocket.onclose transitions to 'disconnected' - break; - - - case 'failed': - if (oldstate === 'disconnected') { - Util.Error("Invalid transition from 'disconnected' to 'failed'"); - } - if (oldstate === 'normal') { - Util.Error("Error while connected."); - } - if (oldstate === 'init') { - Util.Error("Error while initializing."); - } - - // Make sure we transition to disconnected - setTimeout(function() { updateState('disconnected'); }, 50); - - break; - - - default: - // No state change action to take - - } - - if ((oldstate === 'failed') && (state === 'disconnected')) { - // Leave the failed message - conf.updateState(that, state, oldstate); // Obsolete - conf.onUpdateState(that, state, oldstate); - } else { - conf.updateState(that, state, oldstate, statusMsg); // Obsolete - conf.onUpdateState(that, state, oldstate, statusMsg); - } -}; - -fail = function(msg) { - updateState('failed', msg); - return false; -}; - -handle_message = function() { - //Util.Debug(">> handle_message ws.rQlen(): " + ws.rQlen()); - //Util.Debug("ws.rQslice(0,20): " + ws.rQslice(0,20) + " (" + ws.rQlen() + ")"); - if (ws.rQlen() === 0) { - Util.Warn("handle_message called on empty receive queue"); - return; - } - switch (rfb_state) { - case 'disconnected': - case 'failed': - Util.Error("Got data while disconnected"); - break; - case 'normal': - if (normal_msg() && ws.rQlen() > 0) { - // true means we can continue processing - // Give other events a chance to run - if (msgTimer === null) { - Util.Debug("More data to process, creating timer"); - msgTimer = setTimeout(function () { - msgTimer = null; - handle_message(); - }, 10); - } else { - Util.Debug("More data to process, existing timer"); - } - } - break; - default: - init_msg(); - break; - } -}; - - -function genDES(password, challenge) { - var i, passwd = []; - for (i=0; i < password.length; i += 1) { - passwd.push(password.charCodeAt(i)); - } - return (new DES(passwd)).encrypt(challenge); -} - -function flushClient() { - if (mouse_arr.length > 0) { - //send(mouse_arr.concat(fbUpdateRequests())); - ws.send(mouse_arr); - setTimeout(function() { - ws.send(fbUpdateRequests()); - }, 50); - - mouse_arr = []; - return true; - } else { - return false; - } -} - -// overridable for testing -checkEvents = function() { - var now; - if (rfb_state === 'normal' && !viewportDragging) { - if (! flushClient()) { - now = new Date().getTime(); - if (now > last_req_time + conf.fbu_req_rate) { - last_req_time = now; - ws.send(fbUpdateRequests()); - } - } - } - setTimeout(checkEvents, conf.check_rate); -}; - -keyPress = function(keysym, down) { - var arr; - - if (conf.view_only) { return; } // View only, skip keyboard events - - arr = keyEvent(keysym, down); - arr = arr.concat(fbUpdateRequests()); - ws.send(arr); -}; - -mouseButton = function(x, y, down, bmask) { - if (down) { - mouse_buttonMask |= bmask; - } else { - mouse_buttonMask ^= bmask; - } - - if (conf.viewportDrag) { - if (down && !viewportDragging) { - viewportDragging = true; - viewportDragPos = {'x': x, 'y': y}; - - // Skip sending mouse events - return; - } else { - viewportDragging = false; - ws.send(fbUpdateRequests()); // Force immediate redraw - } - } - - if (conf.view_only) { return; } // View only, skip mouse events - - mouse_arr = mouse_arr.concat( - pointerEvent(display.absX(x), display.absY(y)) ); - flushClient(); -}; - -mouseMove = function(x, y) { - //Util.Debug('>> mouseMove ' + x + "," + y); - var deltaX, deltaY; - - if (viewportDragging) { - //deltaX = x - viewportDragPos.x; // drag viewport - deltaX = viewportDragPos.x - x; // drag frame buffer - //deltaY = y - viewportDragPos.y; // drag viewport - deltaY = viewportDragPos.y - y; // drag frame buffer - viewportDragPos = {'x': x, 'y': y}; - - display.viewportChange(deltaX, deltaY); - - // Skip sending mouse events - return; - } - - if (conf.view_only) { return; } // View only, skip mouse events - - mouse_arr = mouse_arr.concat( - pointerEvent(display.absX(x), display.absY(y)) ); -}; - - -// -// Server message handlers -// - -// RFB/VNC initialisation message handler -init_msg = function() { - //Util.Debug(">> init_msg [rfb_state '" + rfb_state + "']"); - - var strlen, reason, length, sversion, cversion, repeaterID, - i, types, num_types, challenge, response, bpp, depth, - big_endian, red_max, green_max, blue_max, red_shift, - green_shift, blue_shift, true_color, name_length, is_repeater; - - //Util.Debug("ws.rQ (" + ws.rQlen() + ") " + ws.rQslice(0)); - switch (rfb_state) { - - case 'ProtocolVersion' : - if (ws.rQlen() < 12) { - return fail("Incomplete protocol version"); - } - sversion = ws.rQshiftStr(12).substr(4,7); - Util.Info("Server ProtocolVersion: " + sversion); - is_repeater = 0; - switch (sversion) { - case "000.000": is_repeater = 1; break; // UltraVNC repeater - case "003.003": rfb_version = 3.3; break; - case "003.006": rfb_version = 3.3; break; // UltraVNC - case "003.889": rfb_version = 3.3; break; // Apple Remote Desktop - case "003.007": rfb_version = 3.7; break; - case "003.008": rfb_version = 3.8; break; - case "004.000": rfb_version = 3.8; break; // Intel AMT KVM - case "004.001": rfb_version = 3.8; break; // RealVNC 4.6 - default: - return fail("Invalid server version " + sversion); - } - if (is_repeater) { - repeaterID = conf.repeaterID; - while (repeaterID.length < 250) { - repeaterID += "\0"; - } - ws.send_string(repeaterID); - break; - } - if (rfb_version > rfb_max_version) { - rfb_version = rfb_max_version; - } - - if (! test_mode) { - sendTimer = setInterval(function() { - // Send updates either at a rate of one update - // every 50ms, or whatever slower rate the network - // can handle. - ws.flush(); - }, 50); - } - - cversion = "00" + parseInt(rfb_version,10) + - ".00" + ((rfb_version * 10) % 10); - ws.send_string("RFB " + cversion + "\n"); - updateState('Security', "Sent ProtocolVersion: " + cversion); - break; - - case 'Security' : - if (rfb_version >= 3.7) { - // Server sends supported list, client decides - num_types = ws.rQshift8(); - if (ws.rQwait("security type", num_types, 1)) { return false; } - if (num_types === 0) { - strlen = ws.rQshift32(); - reason = ws.rQshiftStr(strlen); - return fail("Security failure: " + reason); - } - rfb_auth_scheme = 0; - types = ws.rQshiftBytes(num_types); - Util.Debug("Server security types: " + types); - for (i=0; i < types.length; i+=1) { - if ((types[i] > rfb_auth_scheme) && (types[i] < 3)) { - rfb_auth_scheme = types[i]; - } - } - if (rfb_auth_scheme === 0) { - return fail("Unsupported security types: " + types); - } - - ws.send([rfb_auth_scheme]); - } else { - // Server decides - if (ws.rQwait("security scheme", 4)) { return false; } - rfb_auth_scheme = ws.rQshift32(); - } - updateState('Authentication', - "Authenticating using scheme: " + rfb_auth_scheme); - init_msg(); // Recursive fallthrough (workaround JSLint complaint) - break; - - // Triggered by fallthough, not by server message - case 'Authentication' : - //Util.Debug("Security auth scheme: " + rfb_auth_scheme); - switch (rfb_auth_scheme) { - case 0: // connection failed - if (ws.rQwait("auth reason", 4)) { return false; } - strlen = ws.rQshift32(); - reason = ws.rQshiftStr(strlen); - return fail("Auth failure: " + reason); - case 1: // no authentication - if (rfb_version >= 3.8) { - updateState('SecurityResult'); - return; - } - // Fall through to ClientInitialisation - break; - case 2: // VNC authentication - if (rfb_password.length === 0) { - // Notify via both callbacks since it is kind of - // a RFB state change and a UI interface issue. - updateState('password', "Password Required"); - conf.onPasswordRequired(that); - return; - } - if (ws.rQwait("auth challenge", 16)) { return false; } - challenge = ws.rQshiftBytes(16); - //Util.Debug("Password: " + rfb_password); - //Util.Debug("Challenge: " + challenge + - // " (" + challenge.length + ")"); - response = genDES(rfb_password, challenge); - //Util.Debug("Response: " + response + - // " (" + response.length + ")"); - - //Util.Debug("Sending DES encrypted auth response"); - ws.send(response); - updateState('SecurityResult'); - return; - default: - fail("Unsupported auth scheme: " + rfb_auth_scheme); - return; - } - updateState('ClientInitialisation', "No auth required"); - init_msg(); // Recursive fallthrough (workaround JSLint complaint) - break; - - case 'SecurityResult' : - if (ws.rQwait("VNC auth response ", 4)) { return false; } - switch (ws.rQshift32()) { - case 0: // OK - // Fall through to ClientInitialisation - break; - case 1: // failed - if (rfb_version >= 3.8) { - length = ws.rQshift32(); - if (ws.rQwait("SecurityResult reason", length, 8)) { - return false; - } - reason = ws.rQshiftStr(length); - fail(reason); - } else { - fail("Authentication failed"); - } - return; - case 2: // too-many - return fail("Too many auth attempts"); - } - updateState('ClientInitialisation', "Authentication OK"); - init_msg(); // Recursive fallthrough (workaround JSLint complaint) - break; - - // Triggered by fallthough, not by server message - case 'ClientInitialisation' : - ws.send([conf.shared ? 1 : 0]); // ClientInitialisation - updateState('ServerInitialisation', "Authentication OK"); - break; - - case 'ServerInitialisation' : - if (ws.rQwait("server initialization", 24)) { return false; } - - /* Screen size */ - fb_width = ws.rQshift16(); - fb_height = ws.rQshift16(); - - /* PIXEL_FORMAT */ - bpp = ws.rQshift8(); - depth = ws.rQshift8(); - big_endian = ws.rQshift8(); - true_color = ws.rQshift8(); - - red_max = ws.rQshift16(); - green_max = ws.rQshift16(); - blue_max = ws.rQshift16(); - red_shift = ws.rQshift8(); - green_shift = ws.rQshift8(); - blue_shift = ws.rQshift8(); - ws.rQshiftStr(3); // padding - - Util.Info("Screen: " + fb_width + "x" + fb_height + - ", bpp: " + bpp + ", depth: " + depth + - ", big_endian: " + big_endian + - ", true_color: " + true_color + - ", red_max: " + red_max + - ", green_max: " + green_max + - ", blue_max: " + blue_max + - ", red_shift: " + red_shift + - ", green_shift: " + green_shift + - ", blue_shift: " + blue_shift); - - if (big_endian !== 0) { - Util.Warn("Server native endian is not little endian"); - } - if (red_shift !== 16) { - Util.Warn("Server native red-shift is not 16"); - } - if (blue_shift !== 0) { - Util.Warn("Server native blue-shift is not 0"); - } - - /* Connection name/title */ - name_length = ws.rQshift32(); - fb_name = ws.rQshiftStr(name_length); - conf.onDesktopName(that, fb_name); - - if (conf.true_color && fb_name === "Intel(r) AMT KVM") - { - Util.Warn("Intel AMT KVM only support 8/16 bit depths. Disabling true color"); - conf.true_color = false; - } - - display.set_true_color(conf.true_color); - conf.onFBResize(that, fb_width, fb_height); - display.resize(fb_width, fb_height); - keyboard.grab(); - mouse.grab(); - - if (conf.true_color) { - fb_Bpp = 4; - fb_depth = 3; - } else { - fb_Bpp = 1; - fb_depth = 1; - } - - response = pixelFormat(); - response = response.concat(clientEncodings()); - response = response.concat(fbUpdateRequests()); - timing.fbu_rt_start = (new Date()).getTime(); - timing.pixels = 0; - ws.send(response); - - /* Start pushing/polling */ - setTimeout(checkEvents, conf.check_rate); - - if (conf.encrypt) { - updateState('normal', "Connected (encrypted) to: " + fb_name); - } else { - updateState('normal', "Connected (unencrypted) to: " + fb_name); - } - break; - } - //Util.Debug("<< init_msg"); -}; - - -/* Normal RFB/VNC server message handler */ -normal_msg = function() { - //Util.Debug(">> normal_msg"); - - var ret = true, msg_type, length, text, - c, first_colour, num_colours, red, green, blue; - - if (FBU.rects > 0) { - msg_type = 0; - } else { - msg_type = ws.rQshift8(); - } - switch (msg_type) { - case 0: // FramebufferUpdate - ret = framebufferUpdate(); // false means need more data - break; - case 1: // SetColourMapEntries - Util.Debug("SetColourMapEntries"); - ws.rQshift8(); // Padding - first_colour = ws.rQshift16(); // First colour - num_colours = ws.rQshift16(); - if (ws.rQwait("SetColourMapEntries", num_colours*6, 6)) { return false; } - - for (c=0; c < num_colours; c+=1) { - red = ws.rQshift16(); - //Util.Debug("red before: " + red); - red = parseInt(red / 256, 10); - //Util.Debug("red after: " + red); - green = parseInt(ws.rQshift16() / 256, 10); - blue = parseInt(ws.rQshift16() / 256, 10); - display.set_colourMap([blue, green, red], first_colour + c); - } - Util.Debug("colourMap: " + display.get_colourMap()); - Util.Info("Registered " + num_colours + " colourMap entries"); - //Util.Debug("colourMap: " + display.get_colourMap()); - break; - case 2: // Bell - Util.Debug("Bell"); - conf.onBell(that); - break; - case 3: // ServerCutText - Util.Debug("ServerCutText"); - if (ws.rQwait("ServerCutText header", 7, 1)) { return false; } - ws.rQshiftBytes(3); // Padding - length = ws.rQshift32(); - if (ws.rQwait("ServerCutText", length, 8)) { return false; } - - text = ws.rQshiftStr(length); - conf.clipboardReceive(that, text); // Obsolete - conf.onClipboard(that, text); - break; - default: - fail("Disconnected: illegal server message type " + msg_type); - Util.Debug("ws.rQslice(0,30):" + ws.rQslice(0,30)); - break; - } - //Util.Debug("<< normal_msg"); - return ret; -}; - -framebufferUpdate = function() { - var now, hdr, fbu_rt_diff, ret = true; - - if (FBU.rects === 0) { - //Util.Debug("New FBU: ws.rQslice(0,20): " + ws.rQslice(0,20)); - if (ws.rQwait("FBU header", 3)) { - ws.rQunshift8(0); // FBU msg_type - return false; - } - ws.rQshift8(); // padding - FBU.rects = ws.rQshift16(); - //Util.Debug("FramebufferUpdate, rects:" + FBU.rects); - FBU.bytes = 0; - timing.cur_fbu = 0; - if (timing.fbu_rt_start > 0) { - now = (new Date()).getTime(); - Util.Info("First FBU latency: " + (now - timing.fbu_rt_start)); - } - } - - while (FBU.rects > 0) { - if (rfb_state !== "normal") { - return false; - } - if (ws.rQwait("FBU", FBU.bytes)) { return false; } - if (FBU.bytes === 0) { - if (ws.rQwait("rect header", 12)) { return false; } - /* New FramebufferUpdate */ - - hdr = ws.rQshiftBytes(12); - FBU.x = (hdr[0] << 8) + hdr[1]; - FBU.y = (hdr[2] << 8) + hdr[3]; - FBU.width = (hdr[4] << 8) + hdr[5]; - FBU.height = (hdr[6] << 8) + hdr[7]; - FBU.encoding = parseInt((hdr[8] << 24) + (hdr[9] << 16) + - (hdr[10] << 8) + hdr[11], 10); - - conf.onFBUReceive(that, - {'x': FBU.x, 'y': FBU.y, - 'width': FBU.width, 'height': FBU.height, - 'encoding': FBU.encoding, - 'encodingName': encNames[FBU.encoding]}); - - if (encNames[FBU.encoding]) { - // Debug: - /* - var msg = "FramebufferUpdate rects:" + FBU.rects; - msg += " x: " + FBU.x + " y: " + FBU.y; - msg += " width: " + FBU.width + " height: " + FBU.height; - msg += " encoding:" + FBU.encoding; - msg += "(" + encNames[FBU.encoding] + ")"; - msg += ", ws.rQlen(): " + ws.rQlen(); - Util.Debug(msg); - */ - } else { - fail("Disconnected: unsupported encoding " + - FBU.encoding); - return false; - } - } - - timing.last_fbu = (new Date()).getTime(); - - ret = encHandlers[FBU.encoding](); - - now = (new Date()).getTime(); - timing.cur_fbu += (now - timing.last_fbu); - - if (ret) { - encStats[FBU.encoding][0] += 1; - encStats[FBU.encoding][1] += 1; - timing.pixels += FBU.width * FBU.height; - } - - if (timing.pixels >= (fb_width * fb_height)) { - if (((FBU.width === fb_width) && - (FBU.height === fb_height)) || - (timing.fbu_rt_start > 0)) { - timing.full_fbu_total += timing.cur_fbu; - timing.full_fbu_cnt += 1; - Util.Info("Timing of full FBU, cur: " + - timing.cur_fbu + ", total: " + - timing.full_fbu_total + ", cnt: " + - timing.full_fbu_cnt + ", avg: " + - (timing.full_fbu_total / - timing.full_fbu_cnt)); - } - if (timing.fbu_rt_start > 0) { - fbu_rt_diff = now - timing.fbu_rt_start; - timing.fbu_rt_total += fbu_rt_diff; - timing.fbu_rt_cnt += 1; - Util.Info("full FBU round-trip, cur: " + - fbu_rt_diff + ", total: " + - timing.fbu_rt_total + ", cnt: " + - timing.fbu_rt_cnt + ", avg: " + - (timing.fbu_rt_total / - timing.fbu_rt_cnt)); - timing.fbu_rt_start = 0; - } - } - if (! ret) { - return ret; // false ret means need more data - } - } - - conf.onFBUComplete(that, - {'x': FBU.x, 'y': FBU.y, - 'width': FBU.width, 'height': FBU.height, - 'encoding': FBU.encoding, - 'encodingName': encNames[FBU.encoding]}); - - return true; // We finished this FBU -}; - -// -// FramebufferUpdate encodings -// - -encHandlers.RAW = function display_raw() { - //Util.Debug(">> display_raw (" + ws.rQlen() + " bytes)"); - - var cur_y, cur_height; - - if (FBU.lines === 0) { - FBU.lines = FBU.height; - } - FBU.bytes = FBU.width * fb_Bpp; // At least a line - if (ws.rQwait("RAW", FBU.bytes)) { return false; } - cur_y = FBU.y + (FBU.height - FBU.lines); - cur_height = Math.min(FBU.lines, - Math.floor(ws.rQlen()/(FBU.width * fb_Bpp))); - display.blitImage(FBU.x, cur_y, FBU.width, cur_height, - ws.get_rQ(), ws.get_rQi()); - ws.rQshiftBytes(FBU.width * cur_height * fb_Bpp); - FBU.lines -= cur_height; - - if (FBU.lines > 0) { - FBU.bytes = FBU.width * fb_Bpp; // At least another line - } else { - FBU.rects -= 1; - FBU.bytes = 0; - } - //Util.Debug("<< display_raw (" + ws.rQlen() + " bytes)"); - return true; -}; - -encHandlers.COPYRECT = function display_copy_rect() { - //Util.Debug(">> display_copy_rect"); - - var old_x, old_y; - - FBU.bytes = 4; - if (ws.rQwait("COPYRECT", 4)) { return false; } - display.renderQ_push({ - 'type': 'copy', - 'old_x': ws.rQshift16(), - 'old_y': ws.rQshift16(), - 'x': FBU.x, - 'y': FBU.y, - 'width': FBU.width, - 'height': FBU.height}); - FBU.rects -= 1; - FBU.bytes = 0; - return true; -}; - -encHandlers.RRE = function display_rre() { - //Util.Debug(">> display_rre (" + ws.rQlen() + " bytes)"); - var color, x, y, width, height, chunk; - - if (FBU.subrects === 0) { - FBU.bytes = 4+fb_Bpp; - if (ws.rQwait("RRE", 4+fb_Bpp)) { return false; } - FBU.subrects = ws.rQshift32(); - color = ws.rQshiftBytes(fb_Bpp); // Background - display.fillRect(FBU.x, FBU.y, FBU.width, FBU.height, color); - } - while ((FBU.subrects > 0) && (ws.rQlen() >= (fb_Bpp + 8))) { - color = ws.rQshiftBytes(fb_Bpp); - x = ws.rQshift16(); - y = ws.rQshift16(); - width = ws.rQshift16(); - height = ws.rQshift16(); - display.fillRect(FBU.x + x, FBU.y + y, width, height, color); - FBU.subrects -= 1; - } - //Util.Debug(" display_rre: rects: " + FBU.rects + - // ", FBU.subrects: " + FBU.subrects); - - if (FBU.subrects > 0) { - chunk = Math.min(rre_chunk_sz, FBU.subrects); - FBU.bytes = (fb_Bpp + 8) * chunk; - } else { - FBU.rects -= 1; - FBU.bytes = 0; - } - //Util.Debug("<< display_rre, FBU.bytes: " + FBU.bytes); - return true; -}; - -encHandlers.HEXTILE = function display_hextile() { - //Util.Debug(">> display_hextile"); - var subencoding, subrects, color, cur_tile, - tile_x, x, w, tile_y, y, h, xy, s, sx, sy, wh, sw, sh, - rQ = ws.get_rQ(), rQi = ws.get_rQi(); - - if (FBU.tiles === 0) { - FBU.tiles_x = Math.ceil(FBU.width/16); - FBU.tiles_y = Math.ceil(FBU.height/16); - FBU.total_tiles = FBU.tiles_x * FBU.tiles_y; - FBU.tiles = FBU.total_tiles; - } - - /* FBU.bytes comes in as 1, ws.rQlen() at least 1 */ - while (FBU.tiles > 0) { - FBU.bytes = 1; - if (ws.rQwait("HEXTILE subencoding", FBU.bytes)) { return false; } - subencoding = rQ[rQi]; // Peek - if (subencoding > 30) { // Raw - fail("Disconnected: illegal hextile subencoding " + subencoding); - //Util.Debug("ws.rQslice(0,30):" + ws.rQslice(0,30)); - return false; - } - subrects = 0; - cur_tile = FBU.total_tiles - FBU.tiles; - tile_x = cur_tile % FBU.tiles_x; - tile_y = Math.floor(cur_tile / FBU.tiles_x); - x = FBU.x + tile_x * 16; - y = FBU.y + tile_y * 16; - w = Math.min(16, (FBU.x + FBU.width) - x); - h = Math.min(16, (FBU.y + FBU.height) - y); - - /* Figure out how much we are expecting */ - if (subencoding & 0x01) { // Raw - //Util.Debug(" Raw subencoding"); - FBU.bytes += w * h * fb_Bpp; - } else { - if (subencoding & 0x02) { // Background - FBU.bytes += fb_Bpp; - } - if (subencoding & 0x04) { // Foreground - FBU.bytes += fb_Bpp; - } - if (subencoding & 0x08) { // AnySubrects - FBU.bytes += 1; // Since we aren't shifting it off - if (ws.rQwait("hextile subrects header", FBU.bytes)) { return false; } - subrects = rQ[rQi + FBU.bytes-1]; // Peek - if (subencoding & 0x10) { // SubrectsColoured - FBU.bytes += subrects * (fb_Bpp + 2); - } else { - FBU.bytes += subrects * 2; - } - } - } - - /* - Util.Debug(" tile:" + cur_tile + "/" + (FBU.total_tiles - 1) + - " (" + tile_x + "," + tile_y + ")" + - " [" + x + "," + y + "]@" + w + "x" + h + - ", subenc:" + subencoding + - "(last: " + FBU.lastsubencoding + "), subrects:" + - subrects + - ", ws.rQlen():" + ws.rQlen() + ", FBU.bytes:" + FBU.bytes + - " last:" + ws.rQslice(FBU.bytes-10, FBU.bytes) + - " next:" + ws.rQslice(FBU.bytes-1, FBU.bytes+10)); - */ - if (ws.rQwait("hextile", FBU.bytes)) { return false; } - - /* We know the encoding and have a whole tile */ - FBU.subencoding = rQ[rQi]; - rQi += 1; - if (FBU.subencoding === 0) { - if (FBU.lastsubencoding & 0x01) { - /* Weird: ignore blanks after RAW */ - Util.Debug(" Ignoring blank after RAW"); - } else { - display.fillRect(x, y, w, h, FBU.background); - } - } else if (FBU.subencoding & 0x01) { // Raw - display.blitImage(x, y, w, h, rQ, rQi); - rQi += FBU.bytes - 1; - } else { - if (FBU.subencoding & 0x02) { // Background - FBU.background = rQ.slice(rQi, rQi + fb_Bpp); - rQi += fb_Bpp; - } - if (FBU.subencoding & 0x04) { // Foreground - FBU.foreground = rQ.slice(rQi, rQi + fb_Bpp); - rQi += fb_Bpp; - } - - display.startTile(x, y, w, h, FBU.background); - if (FBU.subencoding & 0x08) { // AnySubrects - subrects = rQ[rQi]; - rQi += 1; - for (s = 0; s < subrects; s += 1) { - if (FBU.subencoding & 0x10) { // SubrectsColoured - color = rQ.slice(rQi, rQi + fb_Bpp); - rQi += fb_Bpp; - } else { - color = FBU.foreground; - } - xy = rQ[rQi]; - rQi += 1; - sx = (xy >> 4); - sy = (xy & 0x0f); - - wh = rQ[rQi]; - rQi += 1; - sw = (wh >> 4) + 1; - sh = (wh & 0x0f) + 1; - - display.subTile(sx, sy, sw, sh, color); - } - } - display.finishTile(); - } - ws.set_rQi(rQi); - FBU.lastsubencoding = FBU.subencoding; - FBU.bytes = 0; - FBU.tiles -= 1; - } - - if (FBU.tiles === 0) { - FBU.rects -= 1; - } - - //Util.Debug("<< display_hextile"); - return true; -}; - - -// Get 'compact length' header and data size -getTightCLength = function (arr) { - var header = 1, data = 0; - data += arr[0] & 0x7f; - if (arr[0] & 0x80) { - header += 1; - data += (arr[1] & 0x7f) << 7; - if (arr[1] & 0x80) { - header += 1; - data += arr[2] << 14; - } - } - return [header, data]; -}; - -function display_tight(isTightPNG) { - //Util.Debug(">> display_tight"); - - if (fb_depth === 1) { - fail("Tight protocol handler only implements true color mode"); - } - - var ctl, cmode, clength, color, img, data; - var filterId = -1, resetStreams = 0, streamId = -1; - var rQ = ws.get_rQ(), rQi = ws.get_rQi(); - - FBU.bytes = 1; // compression-control byte - if (ws.rQwait("TIGHT compression-control", FBU.bytes)) { return false; } - - var checksum = function(data) { - var sum=0, i; - for (i=0; i 65536) sum -= 65536; - } - return sum; - } - - var decompress = function(data) { - for (var i=0; i<4; i++) { - if ((resetStreams >> i) & 1) { - FBU.zlibs[i].reset(); - Util.Info("Reset zlib stream " + i); - } - } - var uncompressed = FBU.zlibs[streamId].uncompress(data, 0); - if (uncompressed.status !== 0) { - Util.Error("Invalid data in zlib stream"); - } - //Util.Warn("Decompressed " + data.length + " to " + - // uncompressed.data.length + " checksums " + - // checksum(data) + ":" + checksum(uncompressed.data)); - - return uncompressed.data; - } - - var indexedToRGB = function (data, numColors, palette, width, height) { - // Convert indexed (palette based) image data to RGB - // TODO: reduce number of calculations inside loop - var dest = []; - var x, y, b, w, w1, dp, sp; - if (numColors === 2) { - w = Math.floor((width + 7) / 8); - w1 = Math.floor(width / 8); - for (y = 0; y < height; y++) { - for (x = 0; x < w1; x++) { - for (b = 7; b >= 0; b--) { - dp = (y*width + x*8 + 7-b) * 3; - sp = (data[y*w + x] >> b & 1) * 3; - dest[dp ] = palette[sp ]; - dest[dp+1] = palette[sp+1]; - dest[dp+2] = palette[sp+2]; - } - } - for (b = 7; b >= 8 - width % 8; b--) { - dp = (y*width + x*8 + 7-b) * 3; - sp = (data[y*w + x] >> b & 1) * 3; - dest[dp ] = palette[sp ]; - dest[dp+1] = palette[sp+1]; - dest[dp+2] = palette[sp+2]; - } - } - } else { - for (y = 0; y < height; y++) { - for (x = 0; x < width; x++) { - dp = (y*width + x) * 3; - sp = data[y*width + x] * 3; - dest[dp ] = palette[sp ]; - dest[dp+1] = palette[sp+1]; - dest[dp+2] = palette[sp+2]; - } - } - } - return dest; - }; - var handlePalette = function() { - var numColors = rQ[rQi + 2] + 1; - var paletteSize = numColors * fb_depth; - FBU.bytes += paletteSize; - if (ws.rQwait("TIGHT palette " + cmode, FBU.bytes)) { return false; } - - var bpp = (numColors <= 2) ? 1 : 8; - var rowSize = Math.floor((FBU.width * bpp + 7) / 8); - var raw = false; - if (rowSize * FBU.height < 12) { - raw = true; - clength = [0, rowSize * FBU.height]; - } else { - clength = getTightCLength(ws.rQslice(3 + paletteSize, - 3 + paletteSize + 3)); - } - FBU.bytes += clength[0] + clength[1]; - if (ws.rQwait("TIGHT " + cmode, FBU.bytes)) { return false; } - - // Shift ctl, filter id, num colors, palette entries, and clength off - ws.rQshiftBytes(3); - var palette = ws.rQshiftBytes(paletteSize); - ws.rQshiftBytes(clength[0]); - - if (raw) { - data = ws.rQshiftBytes(clength[1]); - } else { - data = decompress(ws.rQshiftBytes(clength[1])); - } - - // Convert indexed (palette based) image data to RGB - var rgb = indexedToRGB(data, numColors, palette, FBU.width, FBU.height); - - // Add it to the render queue - display.renderQ_push({ - 'type': 'blitRgb', - 'data': rgb, - 'x': FBU.x, - 'y': FBU.y, - 'width': FBU.width, - 'height': FBU.height}); - return true; - } - - var handleCopy = function() { - var raw = false; - var uncompressedSize = FBU.width * FBU.height * fb_depth; - if (uncompressedSize < 12) { - raw = true; - clength = [0, uncompressedSize]; - } else { - clength = getTightCLength(ws.rQslice(1, 4)); - } - FBU.bytes = 1 + clength[0] + clength[1]; - if (ws.rQwait("TIGHT " + cmode, FBU.bytes)) { return false; } - - // Shift ctl, clength off - ws.rQshiftBytes(1 + clength[0]); - - if (raw) { - data = ws.rQshiftBytes(clength[1]); - } else { - data = decompress(ws.rQshiftBytes(clength[1])); - } - - display.renderQ_push({ - 'type': 'blitRgb', - 'data': data, - 'x': FBU.x, - 'y': FBU.y, - 'width': FBU.width, - 'height': FBU.height}); - return true; - } - - ctl = ws.rQpeek8(); - - // Keep tight reset bits - resetStreams = ctl & 0xF; - - // Figure out filter - ctl = ctl >> 4; - streamId = ctl & 0x3; - - if (ctl === 0x08) cmode = "fill"; - else if (ctl === 0x09) cmode = "jpeg"; - else if (ctl === 0x0A) cmode = "png"; - else if (ctl & 0x04) cmode = "filter"; - else if (ctl < 0x04) cmode = "copy"; - else return fail("Illegal tight compression received, ctl: " + ctl); - - if (isTightPNG && (cmode === "filter" || cmode === "copy")) { - return fail("filter/copy received in tightPNG mode"); - } - - switch (cmode) { - // fill uses fb_depth because TPIXELs drop the padding byte - case "fill": FBU.bytes += fb_depth; break; // TPIXEL - case "jpeg": FBU.bytes += 3; break; // max clength - case "png": FBU.bytes += 3; break; // max clength - case "filter": FBU.bytes += 2; break; // filter id + num colors if palette - case "copy": break; - } - - if (ws.rQwait("TIGHT " + cmode, FBU.bytes)) { return false; } - - //Util.Debug(" ws.rQslice(0,20): " + ws.rQslice(0,20) + " (" + ws.rQlen() + ")"); - //Util.Debug(" cmode: " + cmode); - - // Determine FBU.bytes - switch (cmode) { - case "fill": - ws.rQshift8(); // shift off ctl - color = ws.rQshiftBytes(fb_depth); - display.renderQ_push({ - 'type': 'fill', - 'x': FBU.x, - 'y': FBU.y, - 'width': FBU.width, - 'height': FBU.height, - 'color': [color[2], color[1], color[0]] }); - break; - case "png": - case "jpeg": - clength = getTightCLength(ws.rQslice(1, 4)); - FBU.bytes = 1 + clength[0] + clength[1]; // ctl + clength size + jpeg-data - if (ws.rQwait("TIGHT " + cmode, FBU.bytes)) { return false; } - - // We have everything, render it - //Util.Debug(" jpeg, ws.rQlen(): " + ws.rQlen() + ", clength[0]: " + - // clength[0] + ", clength[1]: " + clength[1]); - ws.rQshiftBytes(1 + clength[0]); // shift off ctl + compact length - img = new Image(); - img.src = "data:image/" + cmode + - extract_data_uri(ws.rQshiftBytes(clength[1])); - display.renderQ_push({ - 'type': 'img', - 'img': img, - 'x': FBU.x, - 'y': FBU.y}); - img = null; - break; - case "filter": - filterId = rQ[rQi + 1]; - if (filterId === 1) { - if (!handlePalette()) { return false; } - } else { - // Filter 0, Copy could be valid here, but servers don't send it as an explicit filter - // Filter 2, Gradient is valid but not used if jpeg is enabled - throw("Unsupported tight subencoding received, filter: " + filterId); - } - break; - case "copy": - if (!handleCopy()) { return false; } - break; - } - - FBU.bytes = 0; - FBU.rects -= 1; - //Util.Debug(" ending ws.rQslice(0,20): " + ws.rQslice(0,20) + " (" + ws.rQlen() + ")"); - //Util.Debug("<< display_tight_png"); - return true; -} - -extract_data_uri = function(arr) { - //var i, stra = []; - //for (i=0; i< arr.length; i += 1) { - // stra.push(String.fromCharCode(arr[i])); - //} - //return "," + escape(stra.join('')); - return ";base64," + Base64.encode(arr); -}; - -encHandlers.TIGHT = function () { return display_tight(false); }; -encHandlers.TIGHT_PNG = function () { return display_tight(true); }; - -encHandlers.last_rect = function last_rect() { - //Util.Debug(">> last_rect"); - FBU.rects = 0; - //Util.Debug("<< last_rect"); - return true; -}; - -encHandlers.DesktopSize = function set_desktopsize() { - Util.Debug(">> set_desktopsize"); - fb_width = FBU.width; - fb_height = FBU.height; - conf.onFBResize(that, fb_width, fb_height); - display.resize(fb_width, fb_height); - timing.fbu_rt_start = (new Date()).getTime(); - // Send a new non-incremental request - ws.send(fbUpdateRequests()); - - FBU.bytes = 0; - FBU.rects -= 1; - - Util.Debug("<< set_desktopsize"); - return true; -}; - -encHandlers.Cursor = function set_cursor() { - var x, y, w, h, pixelslength, masklength; - Util.Debug(">> set_cursor"); - x = FBU.x; // hotspot-x - y = FBU.y; // hotspot-y - w = FBU.width; - h = FBU.height; - - pixelslength = w * h * fb_Bpp; - masklength = Math.floor((w + 7) / 8) * h; - - FBU.bytes = pixelslength + masklength; - if (ws.rQwait("cursor encoding", FBU.bytes)) { return false; } - - //Util.Debug(" set_cursor, x: " + x + ", y: " + y + ", w: " + w + ", h: " + h); - - display.changeCursor(ws.rQshiftBytes(pixelslength), - ws.rQshiftBytes(masklength), - x, y, w, h); - - FBU.bytes = 0; - FBU.rects -= 1; - - Util.Debug("<< set_cursor"); - return true; -}; - -encHandlers.JPEG_quality_lo = function set_jpeg_quality() { - Util.Error("Server sent jpeg_quality pseudo-encoding"); -}; - -encHandlers.compress_lo = function set_compress_level() { - Util.Error("Server sent compress level pseudo-encoding"); -}; - -/* - * Client message routines - */ - -pixelFormat = function() { - //Util.Debug(">> pixelFormat"); - var arr; - arr = [0]; // msg-type - arr.push8(0); // padding - arr.push8(0); // padding - arr.push8(0); // padding - - arr.push8(fb_Bpp * 8); // bits-per-pixel - arr.push8(fb_depth * 8); // depth - arr.push8(0); // little-endian - arr.push8(conf.true_color ? 1 : 0); // true-color - - arr.push16(255); // red-max - arr.push16(255); // green-max - arr.push16(255); // blue-max - arr.push8(16); // red-shift - arr.push8(8); // green-shift - arr.push8(0); // blue-shift - - arr.push8(0); // padding - arr.push8(0); // padding - arr.push8(0); // padding - //Util.Debug("<< pixelFormat"); - return arr; -}; - -clientEncodings = function() { - //Util.Debug(">> clientEncodings"); - var arr, i, encList = []; - - for (i=0; i> fbUpdateRequest"); - if (typeof(x) === "undefined") { x = 0; } - if (typeof(y) === "undefined") { y = 0; } - if (typeof(xw) === "undefined") { xw = fb_width; } - if (typeof(yw) === "undefined") { yw = fb_height; } - var arr; - arr = [3]; // msg-type - arr.push8(incremental); - arr.push16(x); - arr.push16(y); - arr.push16(xw); - arr.push16(yw); - //Util.Debug("<< fbUpdateRequest"); - return arr; -}; - -// Based on clean/dirty areas, generate requests to send -fbUpdateRequests = function() { - var cleanDirty = display.getCleanDirtyReset(), - arr = [], i, cb, db; - - cb = cleanDirty.cleanBox; - if (cb.w > 0 && cb.h > 0) { - // Request incremental for clean box - arr = arr.concat(fbUpdateRequest(1, cb.x, cb.y, cb.w, cb.h)); - } - for (i = 0; i < cleanDirty.dirtyBoxes.length; i++) { - db = cleanDirty.dirtyBoxes[i]; - // Force all (non-incremental for dirty box - arr = arr.concat(fbUpdateRequest(0, db.x, db.y, db.w, db.h)); - } - return arr; -}; - - - -keyEvent = function(keysym, down) { - //Util.Debug(">> keyEvent, keysym: " + keysym + ", down: " + down); - var arr; - arr = [4]; // msg-type - arr.push8(down); - arr.push16(0); - arr.push32(keysym); - //Util.Debug("<< keyEvent"); - return arr; -}; - -pointerEvent = function(x, y) { - //Util.Debug(">> pointerEvent, x,y: " + x + "," + y + - // " , mask: " + mouse_buttonMask); - var arr; - arr = [5]; // msg-type - arr.push8(mouse_buttonMask); - arr.push16(x); - arr.push16(y); - //Util.Debug("<< pointerEvent"); - return arr; -}; - -clientCutText = function(text) { - //Util.Debug(">> clientCutText"); - var arr, i, n; - arr = [6]; // msg-type - arr.push8(0); // padding - arr.push8(0); // padding - arr.push8(0); // padding - arr.push32(text.length); - n = text.length; - for (i=0; i < n; i+=1) { - arr.push(text.charCodeAt(i)); - } - //Util.Debug("<< clientCutText:" + arr); - return arr; -}; - - - -// -// Public API interface functions -// - -that.connect = function(host, port, password, path) { - //Util.Debug(">> connect"); - - rfb_host = host; - rfb_port = port; - rfb_password = (password !== undefined) ? password : ""; - rfb_path = (path !== undefined) ? path : ""; - - if ((!rfb_host) || (!rfb_port)) { - return fail("Must set host and port"); - } - - updateState('connect'); - //Util.Debug("<< connect"); - -}; - -that.disconnect = function() { - //Util.Debug(">> disconnect"); - updateState('disconnect', 'Disconnecting'); - //Util.Debug("<< disconnect"); -}; - -that.sendPassword = function(passwd) { - rfb_password = passwd; - rfb_state = "Authentication"; - setTimeout(init_msg, 1); -}; - -that.sendCtrlAltDel = function() { - if (rfb_state !== "normal" || conf.view_only) { return false; } - Util.Info("Sending Ctrl-Alt-Del"); - var arr = []; - arr = arr.concat(keyEvent(0xFFE3, 1)); // Control - arr = arr.concat(keyEvent(0xFFE9, 1)); // Alt - arr = arr.concat(keyEvent(0xFFFF, 1)); // Delete - arr = arr.concat(keyEvent(0xFFFF, 0)); // Delete - arr = arr.concat(keyEvent(0xFFE9, 0)); // Alt - arr = arr.concat(keyEvent(0xFFE3, 0)); // Control - arr = arr.concat(fbUpdateRequests()); - ws.send(arr); -}; - -// Send a key press. If 'down' is not specified then send a down key -// followed by an up key. -that.sendKey = function(code, down) { - if (rfb_state !== "normal" || conf.view_only) { return false; } - var arr = []; - if (typeof down !== 'undefined') { - Util.Info("Sending key code (" + (down ? "down" : "up") + "): " + code); - arr = arr.concat(keyEvent(code, down ? 1 : 0)); - } else { - Util.Info("Sending key code (down + up): " + code); - arr = arr.concat(keyEvent(code, 1)); - arr = arr.concat(keyEvent(code, 0)); - } - arr = arr.concat(fbUpdateRequests()); - ws.send(arr); -}; - -that.clipboardPasteFrom = function(text) { - if (rfb_state !== "normal") { return; } - //Util.Debug(">> clipboardPasteFrom: " + text.substr(0,40) + "..."); - ws.send(clientCutText(text)); - //Util.Debug("<< clipboardPasteFrom"); -}; - -// Override internal functions for testing -that.testMode = function(override_send, data_mode) { - test_mode = true; - that.recv_message = ws.testMode(override_send, data_mode); - - checkEvents = function () { /* Stub Out */ }; - that.connect = function(host, port, password) { - rfb_host = host; - rfb_port = port; - rfb_password = password; - init_vars(); - updateState('ProtocolVersion', "Starting VNC handshake"); - }; -}; - - -return constructor(); // Return the public API interface - -} // End of RFB() diff --git a/circle/dashboard/static/dashboard/novnc/ui.js b/circle/dashboard/static/dashboard/novnc/ui.js deleted file mode 100644 index b933d31..0000000 --- a/circle/dashboard/static/dashboard/novnc/ui.js +++ /dev/null @@ -1,761 +0,0 @@ -/* - * noVNC: HTML5 VNC client - * Copyright (C) 2012 Joel Martin - * Copyright (C) 2013 Samuel Mannehed for Cendio AB - * Licensed under MPL 2.0 (see LICENSE.txt) - * - * See README.md for usage and integration instructions. - */ - -"use strict"; -/*jslint white: false, browser: true */ -/*global window, $D, Util, WebUtil, RFB, Display */ - -// Load supporting scripts -window.onscriptsload = function () { UI.load(); }; -Util.load_scripts(["webutil.js", "base64.js", "websock.js", "des.js", - "input.js", "display.js", "jsunzip.js", "rfb.js"]); - -var UI = { - -rfb_state : 'loaded', -settingsOpen : false, -connSettingsOpen : false, -popupStatusOpen : false, -clipboardOpen: false, -keyboardVisible: false, - -// Setup rfb object, load settings from browser storage, then call -// UI.init to setup the UI/menus -load: function (callback) { - WebUtil.initSettings(UI.start, callback); -}, - -// Render default UI and initialize settings menu -start: function(callback) { - var html = '', i, sheet, sheets, llevels, port; - - // Stylesheet selection dropdown - sheet = WebUtil.selectStylesheet(); - sheets = WebUtil.getStylesheets(); - for (i = 0; i < sheets.length; i += 1) { - UI.addOption($D('noVNC_stylesheet'),sheets[i].title, sheets[i].title); - } - - // Logging selection dropdown - llevels = ['error', 'warn', 'info', 'debug']; - for (i = 0; i < llevels.length; i += 1) { - UI.addOption($D('noVNC_logging'),llevels[i], llevels[i]); - } - - // Settings with immediate effects - UI.initSetting('logging', 'warn'); - WebUtil.init_logging(UI.getSetting('logging')); - - UI.initSetting('stylesheet', 'default'); - WebUtil.selectStylesheet(null); - // call twice to get around webkit bug - WebUtil.selectStylesheet(UI.getSetting('stylesheet')); - - // if port == 80 (or 443) then it won't be present and should be - // set manually - port = window.location.port; - if (!port) { - if (window.location.protocol.substring(0,5) == 'https') { - port = 443; - } - else if (window.location.protocol.substring(0,4) == 'http') { - port = 80; - } - } - - /* Populate the controls if defaults are provided in the URL */ - UI.initSetting('host', window.location.hostname); - UI.initSetting('port', port); - UI.initSetting('password', ''); - UI.initSetting('encrypt', (window.location.protocol === "https:")); - UI.initSetting('true_color', true); - UI.initSetting('cursor', false); - UI.initSetting('shared', true); - UI.initSetting('view_only', false); - UI.initSetting('connectTimeout', 2); - UI.initSetting('path', 'websockify'); - UI.initSetting('repeaterID', ''); - - UI.rfb = RFB({'target': $D('noVNC_canvas'), - 'onUpdateState': UI.updateState, - 'onClipboard': UI.clipReceive, - 'onDesktopName': UI.updateDocumentTitle}); - UI.updateVisualState(); - - // Unfocus clipboard when over the VNC area - //$D('VNC_screen').onmousemove = function () { - // var keyboard = UI.rfb.get_keyboard(); - // if ((! keyboard) || (! keyboard.get_focused())) { - // $D('VNC_clipboard_text').blur(); - // } - // }; - - // Show mouse selector buttons on touch screen devices - if ('ontouchstart' in document.documentElement) { - // Show mobile buttons - $D('noVNC_mobile_buttons').style.display = "inline"; - UI.setMouseButton(); - // Remove the address bar - setTimeout(function() { window.scrollTo(0, 1); }, 100); - UI.forceSetting('clip', true); - $D('noVNC_clip').disabled = true; - } else { - UI.initSetting('clip', false); - } - - //iOS Safari does not support CSS position:fixed. - //This detects iOS devices and enables javascript workaround. - if ((navigator.userAgent.match(/iPhone/i)) || - (navigator.userAgent.match(/iPod/i)) || - (navigator.userAgent.match(/iPad/i))) { - //UI.setOnscroll(); - //UI.setResize(); - } - UI.setBarPosition(); - - $D('noVNC_host').focus(); - - UI.setViewClip(); - Util.addEvent(window, 'resize', UI.setViewClip); - - Util.addEvent(window, 'beforeunload', function () { - if (UI.rfb_state === 'normal') { - return "You are currently connected."; - } - } ); - - // Show description by default when hosted at for kanaka.github.com - if (location.host === "kanaka.github.com") { - // Open the description dialog - $D('noVNC_description').style.display = "block"; - } else { - // Open the connect panel on first load - UI.toggleConnectPanel(); - } - - // Add mouse event click/focus/blur event handlers to the UI - UI.addMouseHandlers(); - - if (typeof callback === "function") { - callback(UI.rfb); - } -}, - -addMouseHandlers: function() { - // Setup interface handlers that can't be inline - $D("noVNC_view_drag_button").onclick = UI.setViewDrag; - $D("noVNC_mouse_button0").onclick = function () { UI.setMouseButton(1); }; - $D("noVNC_mouse_button1").onclick = function () { UI.setMouseButton(2); }; - $D("noVNC_mouse_button2").onclick = function () { UI.setMouseButton(4); }; - $D("noVNC_mouse_button4").onclick = function () { UI.setMouseButton(0); }; - $D("showKeyboard").onclick = UI.showKeyboard; - //$D("keyboardinput").onkeydown = function (event) { onKeyDown(event); }; - $D("keyboardinput").onblur = UI.keyInputBlur; - - $D("sendCtrlAltDelButton").onclick = UI.sendCtrlAltDel; - $D("noVNC_status").onclick = UI.togglePopupStatusPanel; - $D("noVNC_popup_status_panel").onclick = UI.togglePopupStatusPanel; - $D("clipboardButton").onclick = UI.toggleClipboardPanel; - $D("settingsButton").onclick = UI.toggleSettingsPanel; - $D("connectButton").onclick = UI.toggleConnectPanel; - $D("disconnectButton").onclick = UI.disconnect; - $D("descriptionButton").onclick = UI.toggleConnectPanel; - - $D("noVNC_clipboard_text").onfocus = UI.displayBlur; - $D("noVNC_clipboard_text").onblur = UI.displayFocus; - $D("noVNC_clipboard_text").onchange = UI.clipSend; - $D("noVNC_clipboard_clear_button").onclick = UI.clipClear; - - $D("noVNC_settings_menu").onmouseover = UI.displayBlur; - $D("noVNC_settings_menu").onmouseover = UI.displayFocus; - $D("noVNC_apply").onclick = UI.settingsApply; - - $D("noVNC_connect_button").onclick = UI.connect; -}, - -// Read form control compatible setting from cookie -getSetting: function(name) { - var val, ctrl = $D('noVNC_' + name); - val = WebUtil.readSetting(name); - if (val !== null && ctrl.type === 'checkbox') { - if (val.toString().toLowerCase() in {'0':1, 'no':1, 'false':1}) { - val = false; - } else { - val = true; - } - } - return val; -}, - -// Update cookie and form control setting. If value is not set, then -// updates from control to current cookie setting. -updateSetting: function(name, value) { - - var i, ctrl = $D('noVNC_' + name); - // Save the cookie for this session - if (typeof value !== 'undefined') { - WebUtil.writeSetting(name, value); - } - - // Update the settings control - value = UI.getSetting(name); - - if (ctrl.type === 'checkbox') { - ctrl.checked = value; - - } else if (typeof ctrl.options !== 'undefined') { - for (i = 0; i < ctrl.options.length; i += 1) { - if (ctrl.options[i].value === value) { - ctrl.selectedIndex = i; - break; - } - } - } else { - /*Weird IE9 error leads to 'null' appearring - in textboxes instead of ''.*/ - if (value === null) { - value = ""; - } - ctrl.value = value; - } -}, - -// Save control setting to cookie -saveSetting: function(name) { - var val, ctrl = $D('noVNC_' + name); - if (ctrl.type === 'checkbox') { - val = ctrl.checked; - } else if (typeof ctrl.options !== 'undefined') { - val = ctrl.options[ctrl.selectedIndex].value; - } else { - val = ctrl.value; - } - WebUtil.writeSetting(name, val); - //Util.Debug("Setting saved '" + name + "=" + val + "'"); - return val; -}, - -// Initial page load read/initialization of settings -initSetting: function(name, defVal) { - var val; - - // Check Query string followed by cookie - val = WebUtil.getQueryVar(name); - if (val === null) { - val = WebUtil.readSetting(name, defVal); - } - UI.updateSetting(name, val); - //Util.Debug("Setting '" + name + "' initialized to '" + val + "'"); - return val; -}, - -// Force a setting to be a certain value -forceSetting: function(name, val) { - UI.updateSetting(name, val); - return val; -}, - - -// Show the popup status panel -togglePopupStatusPanel: function() { - var psp = $D('noVNC_popup_status_panel'); - if (UI.popupStatusOpen === true) { - psp.style.display = "none"; - UI.popupStatusOpen = false; - } else { - psp.innerHTML = $D('noVNC_status').innerHTML; - psp.style.display = "block"; - psp.style.left = window.innerWidth/2 - - parseInt(window.getComputedStyle(psp, false).width)/2 -30 + "px"; - UI.popupStatusOpen = true; - } -}, - -// Show the clipboard panel -toggleClipboardPanel: function() { - // Close the description panel - $D('noVNC_description').style.display = "none"; - // Close settings if open - if (UI.settingsOpen === true) { - UI.settingsApply(); - UI.closeSettingsMenu(); - } - // Close connection settings if open - if (UI.connSettingsOpen === true) { - UI.toggleConnectPanel(); - } - // Close popup status panel if open - if (UI.popupStatusOpen === true) { - UI.togglePopupStatusPanel(); - } - // Toggle Clipboard Panel - if (UI.clipboardOpen === true) { - $D('noVNC_clipboard').style.display = "none"; - $D('clipboardButton').className = "noVNC_status_button"; - UI.clipboardOpen = false; - } else { - $D('noVNC_clipboard').style.display = "block"; - $D('clipboardButton').className = "noVNC_status_button_selected"; - UI.clipboardOpen = true; - } -}, - -// Show the connection settings panel/menu -toggleConnectPanel: function() { - // Close the description panel - $D('noVNC_description').style.display = "none"; - // Close connection settings if open - if (UI.settingsOpen === true) { - UI.settingsApply(); - UI.closeSettingsMenu(); - $D('connectButton').className = "noVNC_status_button"; - } - // Close clipboard panel if open - if (UI.clipboardOpen === true) { - UI.toggleClipboardPanel(); - } - // Close popup status panel if open - if (UI.popupStatusOpen === true) { - UI.togglePopupStatusPanel(); - } - - // Toggle Connection Panel - if (UI.connSettingsOpen === true) { - $D('noVNC_controls').style.display = "none"; - $D('connectButton').className = "noVNC_status_button"; - UI.connSettingsOpen = false; - UI.saveSetting('host'); - UI.saveSetting('port'); - //UI.saveSetting('password'); - } else { - $D('noVNC_controls').style.display = "block"; - $D('connectButton').className = "noVNC_status_button_selected"; - UI.connSettingsOpen = true; - $D('noVNC_host').focus(); - } -}, - -// Toggle the settings menu: -// On open, settings are refreshed from saved cookies. -// On close, settings are applied -toggleSettingsPanel: function() { - // Close the description panel - $D('noVNC_description').style.display = "none"; - if (UI.settingsOpen) { - UI.settingsApply(); - UI.closeSettingsMenu(); - } else { - UI.updateSetting('encrypt'); - UI.updateSetting('true_color'); - if (UI.rfb.get_display().get_cursor_uri()) { - UI.updateSetting('cursor'); - } else { - UI.updateSetting('cursor', false); - $D('noVNC_cursor').disabled = true; - } - UI.updateSetting('clip'); - UI.updateSetting('shared'); - UI.updateSetting('view_only'); - UI.updateSetting('connectTimeout'); - UI.updateSetting('path'); - UI.updateSetting('repeaterID'); - UI.updateSetting('stylesheet'); - UI.updateSetting('logging'); - - UI.openSettingsMenu(); - } -}, - -// Open menu -openSettingsMenu: function() { - // Close the description panel - $D('noVNC_description').style.display = "none"; - // Close clipboard panel if open - if (UI.clipboardOpen === true) { - UI.toggleClipboardPanel(); - } - // Close connection settings if open - if (UI.connSettingsOpen === true) { - UI.toggleConnectPanel(); - } - // Close popup status panel if open - if (UI.popupStatusOpen === true) { - UI.togglePopupStatusPanel(); - } - $D('noVNC_settings').style.display = "block"; - $D('settingsButton').className = "noVNC_status_button_selected"; - UI.settingsOpen = true; -}, - -// Close menu (without applying settings) -closeSettingsMenu: function() { - $D('noVNC_settings').style.display = "none"; - $D('settingsButton').className = "noVNC_status_button"; - UI.settingsOpen = false; -}, - -// Save/apply settings when 'Apply' button is pressed -settingsApply: function() { - //Util.Debug(">> settingsApply"); - UI.saveSetting('encrypt'); - UI.saveSetting('true_color'); - if (UI.rfb.get_display().get_cursor_uri()) { - UI.saveSetting('cursor'); - } - UI.saveSetting('clip'); - UI.saveSetting('shared'); - UI.saveSetting('view_only'); - UI.saveSetting('connectTimeout'); - UI.saveSetting('path'); - UI.saveSetting('repeaterID'); - UI.saveSetting('stylesheet'); - UI.saveSetting('logging'); - - // Settings with immediate (non-connected related) effect - WebUtil.selectStylesheet(UI.getSetting('stylesheet')); - WebUtil.init_logging(UI.getSetting('logging')); - UI.setViewClip(); - UI.setViewDrag(UI.rfb.get_viewportDrag()); - //Util.Debug("<< settingsApply"); -}, - - - -setPassword: function() { - UI.rfb.sendPassword($D('noVNC_password').value); - //Reset connect button. - $D('noVNC_connect_button').value = "Connect"; - $D('noVNC_connect_button').onclick = UI.Connect; - //Hide connection panel. - UI.toggleConnectPanel(); - return false; -}, - -sendCtrlAltDel: function() { - UI.rfb.sendCtrlAltDel(); -}, - -setMouseButton: function(num) { - var b, blist = [0, 1,2,4], button; - - if (typeof num === 'undefined') { - // Disable mouse buttons - num = -1; - } - if (UI.rfb) { - UI.rfb.get_mouse().set_touchButton(num); - } - - for (b = 0; b < blist.length; b++) { - button = $D('noVNC_mouse_button' + blist[b]); - if (blist[b] === num) { - button.style.display = ""; - } else { - button.style.display = "none"; - /* - button.style.backgroundColor = "black"; - button.style.color = "lightgray"; - button.style.backgroundColor = ""; - button.style.color = ""; - */ - } - } -}, - -updateState: function(rfb, state, oldstate, msg) { - var s, sb, c, d, cad, vd, klass; - UI.rfb_state = state; - switch (state) { - case 'failed': - case 'fatal': - klass = "noVNC_status_error"; - break; - case 'normal': - klass = "noVNC_status_normal"; - break; - case 'disconnected': - $D('noVNC_logo').style.display = "block"; - // Fall through - case 'loaded': - klass = "noVNC_status_normal"; - break; - case 'password': - UI.toggleConnectPanel(); - - $D('noVNC_connect_button').value = "Send Password"; - $D('noVNC_connect_button').onclick = UI.setPassword; - $D('noVNC_password').focus(); - - klass = "noVNC_status_warn"; - break; - default: - klass = "noVNC_status_warn"; - break; - } - - if (typeof(msg) !== 'undefined') { - $D('noVNC-control-bar').setAttribute("class", klass); - $D('noVNC_status').innerHTML = msg; - } - - UI.updateVisualState(); -}, - -// Disable/enable controls depending on connection state -updateVisualState: function() { - var connected = UI.rfb_state === 'normal' ? true : false; - - //Util.Debug(">> updateVisualState"); - $D('noVNC_encrypt').disabled = connected; - $D('noVNC_true_color').disabled = connected; - if (UI.rfb && UI.rfb.get_display() && - UI.rfb.get_display().get_cursor_uri()) { - $D('noVNC_cursor').disabled = connected; - } else { - UI.updateSetting('cursor', false); - $D('noVNC_cursor').disabled = true; - } - $D('noVNC_shared').disabled = connected; - $D('noVNC_view_only').disabled = connected; - $D('noVNC_connectTimeout').disabled = connected; - $D('noVNC_path').disabled = connected; - $D('noVNC_repeaterID').disabled = connected; - - if (connected) { - UI.setViewClip(); - UI.setMouseButton(1); - $D('clipboardButton').style.display = "inline"; - $D('showKeyboard').style.display = "inline"; - $D('sendCtrlAltDelButton').style.display = "inline"; - } else { - UI.setMouseButton(); - $D('clipboardButton').style.display = "none"; - $D('showKeyboard').style.display = "none"; - $D('sendCtrlAltDelButton').style.display = "none"; - } - // State change disables viewport dragging. - // It is enabled (toggled) by direct click on the button - UI.setViewDrag(false); - - switch (UI.rfb_state) { - case 'fatal': - case 'failed': - case 'loaded': - case 'disconnected': - $D('connectButton').style.display = ""; - $D('disconnectButton').style.display = "none"; - break; - default: - $D('connectButton').style.display = "none"; - $D('disconnectButton').style.display = ""; - break; - } - - //Util.Debug("<< updateVisualState"); -}, - - -// Display the desktop name in the document title -updateDocumentTitle: function(rfb, name) { - document.title = name + " - noVNC"; -}, - - -clipReceive: function(rfb, text) { - Util.Debug(">> UI.clipReceive: " + text.substr(0,40) + "..."); - $D('noVNC_clipboard_text').value = text; - Util.Debug("<< UI.clipReceive"); -}, - - -connect: function() { - var host, port, password, path; - - UI.closeSettingsMenu(); - UI.toggleConnectPanel(); - - host = $D('noVNC_host').value; - port = $D('noVNC_port').value; - password = $D('noVNC_password').value; - path = $D('noVNC_path').value; - if ((!host) || (!port)) { - throw("Must set host and port"); - } - - UI.rfb.set_encrypt(UI.getSetting('encrypt')); - UI.rfb.set_true_color(UI.getSetting('true_color')); - UI.rfb.set_local_cursor(UI.getSetting('cursor')); - UI.rfb.set_shared(UI.getSetting('shared')); - UI.rfb.set_view_only(UI.getSetting('view_only')); - UI.rfb.set_connectTimeout(UI.getSetting('connectTimeout')); - UI.rfb.set_repeaterID(UI.getSetting('repeaterID')); - - UI.rfb.connect(host, port, password, path); - - //Close dialog. - setTimeout(UI.setBarPosition, 100); - $D('noVNC_logo').style.display = "none"; -}, - -disconnect: function() { - UI.closeSettingsMenu(); - UI.rfb.disconnect(); - - $D('noVNC_logo').style.display = "block"; - UI.connSettingsOpen = false; - UI.toggleConnectPanel(); -}, - -displayBlur: function() { - UI.rfb.get_keyboard().set_focused(false); - UI.rfb.get_mouse().set_focused(false); -}, - -displayFocus: function() { - UI.rfb.get_keyboard().set_focused(true); - UI.rfb.get_mouse().set_focused(true); -}, - -clipClear: function() { - $D('noVNC_clipboard_text').value = ""; - UI.rfb.clipboardPasteFrom(""); -}, - -clipSend: function() { - var text = $D('noVNC_clipboard_text').value; - Util.Debug(">> UI.clipSend: " + text.substr(0,40) + "..."); - UI.rfb.clipboardPasteFrom(text); - Util.Debug("<< UI.clipSend"); -}, - - -// Enable/disable and configure viewport clipping -setViewClip: function(clip) { - var display, cur_clip, pos, new_w, new_h; - - if (UI.rfb) { - display = UI.rfb.get_display(); - } else { - return; - } - - cur_clip = display.get_viewport(); - - if (typeof(clip) !== 'boolean') { - // Use current setting - clip = UI.getSetting('clip'); - } - - if (clip && !cur_clip) { - // Turn clipping on - UI.updateSetting('clip', true); - } else if (!clip && cur_clip) { - // Turn clipping off - UI.updateSetting('clip', false); - display.set_viewport(false); - $D('noVNC_canvas').style.position = 'static'; - display.viewportChange(); - } - if (UI.getSetting('clip')) { - // If clipping, update clipping settings - $D('noVNC_canvas').style.position = 'absolute'; - pos = Util.getPosition($D('noVNC_canvas')); - new_w = window.innerWidth - pos.x; - new_h = window.innerHeight - pos.y; - display.set_viewport(true); - display.viewportChange(0, 0, new_w, new_h); - } -}, - -// Toggle/set/unset the viewport drag/move button -setViewDrag: function(drag) { - var vmb = $D('noVNC_view_drag_button'); - if (!UI.rfb) { return; } - - if (UI.rfb_state === 'normal' && - UI.rfb.get_display().get_viewport()) { - vmb.style.display = "inline"; - } else { - vmb.style.display = "none"; - } - - if (typeof(drag) === "undefined" || - typeof(drag) === "object") { - // If not specified, then toggle - drag = !UI.rfb.get_viewportDrag(); - } - if (drag) { - vmb.className = "noVNC_status_button_selected"; - UI.rfb.set_viewportDrag(true); - } else { - vmb.className = "noVNC_status_button"; - UI.rfb.set_viewportDrag(false); - } -}, - -// On touch devices, show the OS keyboard -showKeyboard: function() { - if(UI.keyboardVisible === false) { - $D('keyboardinput').focus(); - UI.keyboardVisible = true; - $D('showKeyboard').className = "noVNC_status_button_selected"; - } else if(UI.keyboardVisible === true) { - $D('keyboardinput').blur(); - $D('showKeyboard').className = "noVNC_status_button"; - UI.keyboardVisible = false; - } -}, - -keyInputBlur: function() { - $D('showKeyboard').className = "noVNC_status_button"; - //Weird bug in iOS if you change keyboardVisible - //here it does not actually occur so next time - //you click keyboard icon it doesnt work. - setTimeout(function() { UI.setKeyboard(); },100); -}, - -setKeyboard: function() { - UI.keyboardVisible = false; -}, - -// iOS < Version 5 does not support position fixed. Javascript workaround: -setOnscroll: function() { - window.onscroll = function() { - UI.setBarPosition(); - }; -}, - -setResize: function () { - window.onResize = function() { - UI.setBarPosition(); - }; -}, - -//Helper to add options to dropdown. -addOption: function(selectbox,text,value ) -{ - var optn = document.createElement("OPTION"); - optn.text = text; - optn.value = value; - selectbox.options.add(optn); -}, - -setBarPosition: function() { - $D('noVNC-control-bar').style.top = (window.pageYOffset) + 'px'; - $D('noVNC_mobile_buttons').style.left = (window.pageXOffset) + 'px'; - - var vncwidth = $D('noVNC_screen').style.offsetWidth; - $D('noVNC-control-bar').style.width = vncwidth + 'px'; -} - -}; - - - - diff --git a/circle/dashboard/static/dashboard/novnc/util.js b/circle/dashboard/static/dashboard/novnc/util.js deleted file mode 100644 index 8893591..0000000 --- a/circle/dashboard/static/dashboard/novnc/util.js +++ /dev/null @@ -1,383 +0,0 @@ -/* - * noVNC: HTML5 VNC client - * Copyright (C) 2012 Joel Martin - * Licensed under MPL 2.0 (see LICENSE.txt) - * - * See README.md for usage and integration instructions. - */ - -"use strict"; -/*jslint bitwise: false, white: false */ -/*global window, console, document, navigator, ActiveXObject */ - -// Globals defined here -var Util = {}; - - -/* - * Make arrays quack - */ - -Array.prototype.push8 = function (num) { - this.push(num & 0xFF); -}; - -Array.prototype.push16 = function (num) { - this.push((num >> 8) & 0xFF, - (num ) & 0xFF ); -}; -Array.prototype.push32 = function (num) { - this.push((num >> 24) & 0xFF, - (num >> 16) & 0xFF, - (num >> 8) & 0xFF, - (num ) & 0xFF ); -}; - -// IE does not support map (even in IE9) -//This prototype is provided by the Mozilla foundation and -//is distributed under the MIT license. -//http://www.ibiblio.org/pub/Linux/LICENSES/mit.license -if (!Array.prototype.map) -{ - Array.prototype.map = function(fun /*, thisp*/) - { - var len = this.length; - if (typeof fun != "function") - throw new TypeError(); - - var res = new Array(len); - var thisp = arguments[1]; - for (var i = 0; i < len; i++) - { - if (i in this) - res[i] = fun.call(thisp, this[i], i, this); - } - - return res; - }; -} - -// -// requestAnimationFrame shim with setTimeout fallback -// - -window.requestAnimFrame = (function(){ - return window.requestAnimationFrame || - window.webkitRequestAnimationFrame || - window.mozRequestAnimationFrame || - window.oRequestAnimationFrame || - window.msRequestAnimationFrame || - function(callback){ - window.setTimeout(callback, 1000 / 60); - }; -})(); - -/* - * ------------------------------------------------------ - * Namespaced in Util - * ------------------------------------------------------ - */ - -/* - * Logging/debug routines - */ - -Util._log_level = 'warn'; -Util.init_logging = function (level) { - if (typeof level === 'undefined') { - level = Util._log_level; - } else { - Util._log_level = level; - } - if (typeof window.console === "undefined") { - if (typeof window.opera !== "undefined") { - window.console = { - 'log' : window.opera.postError, - 'warn' : window.opera.postError, - 'error': window.opera.postError }; - } else { - window.console = { - 'log' : function(m) {}, - 'warn' : function(m) {}, - 'error': function(m) {}}; - } - } - - Util.Debug = Util.Info = Util.Warn = Util.Error = function (msg) {}; - switch (level) { - case 'debug': Util.Debug = function (msg) { console.log(msg); }; - case 'info': Util.Info = function (msg) { console.log(msg); }; - case 'warn': Util.Warn = function (msg) { console.warn(msg); }; - case 'error': Util.Error = function (msg) { console.error(msg); }; - case 'none': - break; - default: - throw("invalid logging type '" + level + "'"); - } -}; -Util.get_logging = function () { - return Util._log_level; -}; -// Initialize logging level -Util.init_logging(); - - -// Set configuration default for Crockford style function namespaces -Util.conf_default = function(cfg, api, defaults, v, mode, type, defval, desc) { - var getter, setter; - - // Default getter function - getter = function (idx) { - if ((type in {'arr':1, 'array':1}) && - (typeof idx !== 'undefined')) { - return cfg[v][idx]; - } else { - return cfg[v]; - } - }; - - // Default setter function - setter = function (val, idx) { - if (type in {'boolean':1, 'bool':1}) { - if ((!val) || (val in {'0':1, 'no':1, 'false':1})) { - val = false; - } else { - val = true; - } - } else if (type in {'integer':1, 'int':1}) { - val = parseInt(val, 10); - } else if (type === 'str') { - val = String(val); - } else if (type === 'func') { - if (!val) { - val = function () {}; - } - } - if (typeof idx !== 'undefined') { - cfg[v][idx] = val; - } else { - cfg[v] = val; - } - }; - - // Set the description - api[v + '_description'] = desc; - - // Set the getter function - if (typeof api['get_' + v] === 'undefined') { - api['get_' + v] = getter; - } - - // Set the setter function with extra sanity checks - if (typeof api['set_' + v] === 'undefined') { - api['set_' + v] = function (val, idx) { - if (mode in {'RO':1, 'ro':1}) { - throw(v + " is read-only"); - } else if ((mode in {'WO':1, 'wo':1}) && - (typeof cfg[v] !== 'undefined')) { - throw(v + " can only be set once"); - } - setter(val, idx); - }; - } - - // Set the default value - if (typeof defaults[v] !== 'undefined') { - defval = defaults[v]; - } else if ((type in {'arr':1, 'array':1}) && - (! (defval instanceof Array))) { - defval = []; - } - // Coerce existing setting to the right type - //Util.Debug("v: " + v + ", defval: " + defval + ", defaults[v]: " + defaults[v]); - setter(defval); -}; - -// Set group of configuration defaults -Util.conf_defaults = function(cfg, api, defaults, arr) { - var i; - for (i = 0; i < arr.length; i++) { - Util.conf_default(cfg, api, defaults, arr[i][0], arr[i][1], - arr[i][2], arr[i][3], arr[i][4]); - } -}; - - -/* - * Cross-browser routines - */ - - -// Dynamically load scripts without using document.write() -// Reference: http://unixpapa.com/js/dyna.html -// -// Handles the case where load_scripts is invoked from a script that -// itself is loaded via load_scripts. Once all scripts are loaded the -// window.onscriptsloaded handler is called (if set). -Util.get_include_uri = function() { - return (typeof INCLUDE_URI !== "undefined") ? INCLUDE_URI : "include/"; -} -Util._loading_scripts = []; -Util._pending_scripts = []; -Util.load_scripts = function(files) { - var head = document.getElementsByTagName('head')[0], script, - ls = Util._loading_scripts, ps = Util._pending_scripts; - for (var f=0; f 0 && (ls[0].readyState === 'loaded' || - ls[0].readyState === 'complete')) { - // For IE, append the script to trigger execution - var s = ls.shift(); - //console.log("loaded script: " + s.src); - head.appendChild(s); - } - if (!this.readyState || - (Util.Engine.presto && this.readyState === 'loaded') || - this.readyState === 'complete') { - if (ps.indexOf(this) >= 0) { - this.onload = this.onreadystatechange = null; - //console.log("completed script: " + this.src); - ps.splice(ps.indexOf(this), 1); - - // Call window.onscriptsload after last script loads - if (ps.length === 0 && window.onscriptsload) { - window.onscriptsload(); - } - } - } - }; - // In-order script execution tricks - if (Util.Engine.trident) { - // For IE wait until readyState is 'loaded' before - // appending it which will trigger execution - // http://wiki.whatwg.org/wiki/Dynamic_Script_Execution_Order - ls.push(script); - } else { - // For webkit and firefox set async=false and append now - // https://developer.mozilla.org/en-US/docs/HTML/Element/script - script.async = false; - head.appendChild(script); - } - ps.push(script); - } -} - -// Get DOM element position on page -Util.getPosition = function (obj) { - var x = 0, y = 0; - if (obj.offsetParent) { - do { - x += obj.offsetLeft; - y += obj.offsetTop; - obj = obj.offsetParent; - } while (obj); - } - return {'x': x, 'y': y}; -}; - -// Get mouse event position in DOM element -Util.getEventPosition = function (e, obj, scale) { - var evt, docX, docY, pos; - //if (!e) evt = window.event; - evt = (e ? e : window.event); - evt = (evt.changedTouches ? evt.changedTouches[0] : evt.touches ? evt.touches[0] : evt); - if (evt.pageX || evt.pageY) { - docX = evt.pageX; - docY = evt.pageY; - } else if (evt.clientX || evt.clientY) { - docX = evt.clientX + document.body.scrollLeft + - document.documentElement.scrollLeft; - docY = evt.clientY + document.body.scrollTop + - document.documentElement.scrollTop; - } - pos = Util.getPosition(obj); - if (typeof scale === "undefined") { - scale = 1; - } - var realx = docX - pos.x; - var realy = docY - pos.y; - var x = Math.max(Math.min(realx, obj.width-1), 0); - var y = Math.max(Math.min(realy, obj.height-1), 0); - return {'x': x / scale, 'y': y / scale, 'realx': realx / scale, 'realy': realy / scale}; -}; - - -// Event registration. Based on: http://www.scottandrew.com/weblog/articles/cbs-events -Util.addEvent = function (obj, evType, fn){ - if (obj.attachEvent){ - var r = obj.attachEvent("on"+evType, fn); - return r; - } else if (obj.addEventListener){ - obj.addEventListener(evType, fn, false); - return true; - } else { - throw("Handler could not be attached"); - } -}; - -Util.removeEvent = function(obj, evType, fn){ - if (obj.detachEvent){ - var r = obj.detachEvent("on"+evType, fn); - return r; - } else if (obj.removeEventListener){ - obj.removeEventListener(evType, fn, false); - return true; - } else { - throw("Handler could not be removed"); - } -}; - -Util.stopEvent = function(e) { - if (e.stopPropagation) { e.stopPropagation(); } - else { e.cancelBubble = true; } - - if (e.preventDefault) { e.preventDefault(); } - else { e.returnValue = false; } -}; - - -// Set browser engine versions. Based on mootools. -Util.Features = {xpath: !!(document.evaluate), air: !!(window.runtime), query: !!(document.querySelector)}; - -Util.Engine = { - // Version detection break in Opera 11.60 (errors on arguments.callee.caller reference) - //'presto': (function() { - // return (!window.opera) ? false : ((arguments.callee.caller) ? 960 : ((document.getElementsByClassName) ? 950 : 925)); }()), - 'presto': (function() { return (!window.opera) ? false : true; }()), - - 'trident': (function() { - return (!window.ActiveXObject) ? false : ((window.XMLHttpRequest) ? ((document.querySelectorAll) ? 6 : 5) : 4); }()), - 'webkit': (function() { - try { return (navigator.taintEnabled) ? false : ((Util.Features.xpath) ? ((Util.Features.query) ? 525 : 420) : 419); } catch (e) { return false; } }()), - //'webkit': (function() { - // return ((typeof navigator.taintEnabled !== "unknown") && navigator.taintEnabled) ? false : ((Util.Features.xpath) ? ((Util.Features.query) ? 525 : 420) : 419); }()), - 'gecko': (function() { - return (!document.getBoxObjectFor && window.mozInnerScreenX == null) ? false : ((document.getElementsByClassName) ? 19 : 18); }()) -}; -if (Util.Engine.webkit) { - // Extract actual webkit version if available - Util.Engine.webkit = (function(v) { - var re = new RegExp('WebKit/([0-9\.]*) '); - v = (navigator.userAgent.match(re) || ['', v])[1]; - return parseFloat(v, 10); - })(Util.Engine.webkit); -} - -Util.Flash = (function(){ - var v, version; - try { - v = navigator.plugins['Shockwave Flash'].description; - } catch(err1) { - try { - v = new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version'); - } catch(err2) { - v = '0 r0'; - } - } - version = v.match(/\d+/g); - return {version: parseInt(version[0] || 0 + '.' + version[1], 10) || 0, build: parseInt(version[2], 10) || 0}; -}()); diff --git a/circle/dashboard/static/dashboard/novnc/websock.js b/circle/dashboard/static/dashboard/novnc/websock.js deleted file mode 100644 index 01a24c3..0000000 --- a/circle/dashboard/static/dashboard/novnc/websock.js +++ /dev/null @@ -1,422 +0,0 @@ -/* - * Websock: high-performance binary WebSockets - * Copyright (C) 2012 Joel Martin - * Licensed under MPL 2.0 (see LICENSE.txt) - * - * Websock is similar to the standard WebSocket object but Websock - * enables communication with raw TCP sockets (i.e. the binary stream) - * via websockify. This is accomplished by base64 encoding the data - * stream between Websock and websockify. - * - * Websock has built-in receive queue buffering; the message event - * does not contain actual data but is simply a notification that - * there is new data available. Several rQ* methods are available to - * read binary data off of the receive queue. - */ - -/*jslint browser: true, bitwise: false, plusplus: false */ -/*global Util, Base64 */ - - -// Load Flash WebSocket emulator if needed - -// To force WebSocket emulator even when native WebSocket available -//window.WEB_SOCKET_FORCE_FLASH = true; -// To enable WebSocket emulator debug: -//window.WEB_SOCKET_DEBUG=1; - -if (window.WebSocket && !window.WEB_SOCKET_FORCE_FLASH) { - Websock_native = true; -} else if (window.MozWebSocket && !window.WEB_SOCKET_FORCE_FLASH) { - Websock_native = true; - window.WebSocket = window.MozWebSocket; -} else { - /* no builtin WebSocket so load web_socket.js */ - - Websock_native = false; - (function () { - window.WEB_SOCKET_SWF_LOCATION = Util.get_include_uri() + - "web-socket-js/WebSocketMain.swf"; - if (Util.Engine.trident) { - Util.Debug("Forcing uncached load of WebSocketMain.swf"); - window.WEB_SOCKET_SWF_LOCATION += "?" + Math.random(); - } - Util.load_scripts(["web-socket-js/swfobject.js", - "web-socket-js/web_socket.js"]); - }()); -} - - -function Websock() { -"use strict"; - -var api = {}, // Public API - websocket = null, // WebSocket object - mode = 'base64', // Current WebSocket mode: 'binary', 'base64' - rQ = [], // Receive queue - rQi = 0, // Receive queue index - rQmax = 10000, // Max receive queue size before compacting - sQ = [], // Send queue - - eventHandlers = { - 'message' : function() {}, - 'open' : function() {}, - 'close' : function() {}, - 'error' : function() {} - }, - - test_mode = false; - - -// -// Queue public functions -// - -function get_sQ() { - return sQ; -} - -function get_rQ() { - return rQ; -} -function get_rQi() { - return rQi; -} -function set_rQi(val) { - rQi = val; -} - -function rQlen() { - return rQ.length - rQi; -} - -function rQpeek8() { - return (rQ[rQi] ); -} -function rQshift8() { - return (rQ[rQi++] ); -} -function rQunshift8(num) { - if (rQi === 0) { - rQ.unshift(num); - } else { - rQi -= 1; - rQ[rQi] = num; - } - -} -function rQshift16() { - return (rQ[rQi++] << 8) + - (rQ[rQi++] ); -} -function rQshift32() { - return (rQ[rQi++] << 24) + - (rQ[rQi++] << 16) + - (rQ[rQi++] << 8) + - (rQ[rQi++] ); -} -function rQshiftStr(len) { - if (typeof(len) === 'undefined') { len = rQlen(); } - var arr = rQ.slice(rQi, rQi + len); - rQi += len; - return String.fromCharCode.apply(null, arr); -} -function rQshiftBytes(len) { - if (typeof(len) === 'undefined') { len = rQlen(); } - rQi += len; - return rQ.slice(rQi-len, rQi); -} - -function rQslice(start, end) { - if (end) { - return rQ.slice(rQi + start, rQi + end); - } else { - return rQ.slice(rQi + start); - } -} - -// Check to see if we must wait for 'num' bytes (default to FBU.bytes) -// to be available in the receive queue. Return true if we need to -// wait (and possibly print a debug message), otherwise false. -function rQwait(msg, num, goback) { - var rQlen = rQ.length - rQi; // Skip rQlen() function call - if (rQlen < num) { - if (goback) { - if (rQi < goback) { - throw("rQwait cannot backup " + goback + " bytes"); - } - rQi -= goback; - } - //Util.Debug(" waiting for " + (num-rQlen) + - // " " + msg + " byte(s)"); - return true; // true means need more data - } - return false; -} - -// -// Private utility routines -// - -function encode_message() { - if (mode === 'binary') { - // Put in a binary arraybuffer - return (new Uint8Array(sQ)).buffer; - } else { - // base64 encode - return Base64.encode(sQ); - } -} - -function decode_message(data) { - //Util.Debug(">> decode_message: " + data); - if (mode === 'binary') { - // push arraybuffer values onto the end - var u8 = new Uint8Array(data); - for (var i = 0; i < u8.length; i++) { - rQ.push(u8[i]); - } - } else { - // base64 decode and concat to the end - rQ = rQ.concat(Base64.decode(data, 0)); - } - //Util.Debug(">> decode_message, rQ: " + rQ); -} - - -// -// Public Send functions -// - -function flush() { - if (websocket.bufferedAmount !== 0) { - Util.Debug("bufferedAmount: " + websocket.bufferedAmount); - } - if (websocket.bufferedAmount < api.maxBufferedAmount) { - //Util.Debug("arr: " + arr); - //Util.Debug("sQ: " + sQ); - if (sQ.length > 0) { - websocket.send(encode_message(sQ)); - sQ = []; - } - return true; - } else { - Util.Info("Delaying send, bufferedAmount: " + - websocket.bufferedAmount); - return false; - } -} - -// overridable for testing -function send(arr) { - //Util.Debug(">> send_array: " + arr); - sQ = sQ.concat(arr); - return flush(); -} - -function send_string(str) { - //Util.Debug(">> send_string: " + str); - api.send(str.split('').map( - function (chr) { return chr.charCodeAt(0); } ) ); -} - -// -// Other public functions - -function recv_message(e) { - //Util.Debug(">> recv_message: " + e.data.length); - - try { - decode_message(e.data); - if (rQlen() > 0) { - eventHandlers.message(); - // Compact the receive queue - if (rQ.length > rQmax) { - //Util.Debug("Compacting receive queue"); - rQ = rQ.slice(rQi); - rQi = 0; - } - } else { - Util.Debug("Ignoring empty message"); - } - } catch (exc) { - if (typeof exc.stack !== 'undefined') { - Util.Warn("recv_message, caught exception: " + exc.stack); - } else if (typeof exc.description !== 'undefined') { - Util.Warn("recv_message, caught exception: " + exc.description); - } else { - Util.Warn("recv_message, caught exception:" + exc); - } - if (typeof exc.name !== 'undefined') { - eventHandlers.error(exc.name + ": " + exc.message); - } else { - eventHandlers.error(exc); - } - } - //Util.Debug("<< recv_message"); -} - - -// Set event handlers -function on(evt, handler) { - eventHandlers[evt] = handler; -} - -function init(protocols) { - rQ = []; - rQi = 0; - sQ = []; - websocket = null; - - var bt = false, - wsbt = false, - try_binary = false; - - // Check for full typed array support - if (('Uint8Array' in window) && - ('set' in Uint8Array.prototype)) { - bt = true; - } - - // Check for full binary type support in WebSockets - // TODO: this sucks, the property should exist on the prototype - // but it does not. - try { - if (bt && ('binaryType' in (new WebSocket("ws://localhost:17523")))) { - Util.Info("Detected binaryType support in WebSockets"); - wsbt = true; - } - } catch (exc) { - // Just ignore failed test localhost connections - } - - // Default protocols if not specified - if (typeof(protocols) === "undefined") { - if (wsbt) { - protocols = ['binary', 'base64']; - } else { - protocols = 'base64'; - } - } - - // If no binary support, make sure it was not requested - if (!wsbt) { - if (protocols === 'binary') { - throw("WebSocket binary sub-protocol requested but not supported"); - } - if (typeof(protocols) === "object") { - var new_protocols = []; - for (var i = 0; i < protocols.length; i++) { - if (protocols[i] === 'binary') { - Util.Error("Skipping unsupported WebSocket binary sub-protocol"); - } else { - new_protocols.push(protocols[i]); - } - } - if (new_protocols.length > 0) { - protocols = new_protocols; - } else { - throw("Only WebSocket binary sub-protocol was requested and not supported."); - } - } - } - - return protocols; -} - -function open(uri, protocols) { - protocols = init(protocols); - - if (test_mode) { - websocket = {}; - } else { - websocket = new WebSocket(uri, protocols); - if (protocols.indexOf('binary') >= 0) { - websocket.binaryType = 'arraybuffer'; - } - } - - websocket.onmessage = recv_message; - websocket.onopen = function() { - Util.Debug(">> WebSock.onopen"); - if (websocket.protocol) { - mode = websocket.protocol; - Util.Info("Server chose sub-protocol: " + websocket.protocol); - } else { - mode = 'base64'; - Util.Error("Server select no sub-protocol!: " + websocket.protocol); - } - eventHandlers.open(); - Util.Debug("<< WebSock.onopen"); - }; - websocket.onclose = function(e) { - Util.Debug(">> WebSock.onclose"); - eventHandlers.close(e); - Util.Debug("<< WebSock.onclose"); - }; - websocket.onerror = function(e) { - Util.Debug(">> WebSock.onerror: " + e); - eventHandlers.error(e); - Util.Debug("<< WebSock.onerror"); - }; -} - -function close() { - if (websocket) { - if ((websocket.readyState === WebSocket.OPEN) || - (websocket.readyState === WebSocket.CONNECTING)) { - Util.Info("Closing WebSocket connection"); - websocket.close(); - } - websocket.onmessage = function (e) { return; }; - } -} - -// Override internal functions for testing -// Takes a send function, returns reference to recv function -function testMode(override_send, data_mode) { - test_mode = true; - mode = data_mode; - api.send = override_send; - api.close = function () {}; - return recv_message; -} - -function constructor() { - // Configuration settings - api.maxBufferedAmount = 200; - - // Direct access to send and receive queues - api.get_sQ = get_sQ; - api.get_rQ = get_rQ; - api.get_rQi = get_rQi; - api.set_rQi = set_rQi; - - // Routines to read from the receive queue - api.rQlen = rQlen; - api.rQpeek8 = rQpeek8; - api.rQshift8 = rQshift8; - api.rQunshift8 = rQunshift8; - api.rQshift16 = rQshift16; - api.rQshift32 = rQshift32; - api.rQshiftStr = rQshiftStr; - api.rQshiftBytes = rQshiftBytes; - api.rQslice = rQslice; - api.rQwait = rQwait; - - api.flush = flush; - api.send = send; - api.send_string = send_string; - - api.on = on; - api.init = init; - api.open = open; - api.close = close; - api.testMode = testMode; - - return api; -} - -return constructor(); - -} diff --git a/circle/dashboard/static/dashboard/novnc/webutil.js b/circle/dashboard/static/dashboard/novnc/webutil.js deleted file mode 100644 index ebf8e89..0000000 --- a/circle/dashboard/static/dashboard/novnc/webutil.js +++ /dev/null @@ -1,216 +0,0 @@ -/* - * noVNC: HTML5 VNC client - * Copyright (C) 2012 Joel Martin - * Licensed under MPL 2.0 (see LICENSE.txt) - * - * See README.md for usage and integration instructions. - */ - -"use strict"; -/*jslint bitwise: false, white: false */ -/*global Util, window, document */ - -// Globals defined here -var WebUtil = {}, $D; - -/* - * Simple DOM selector by ID - */ -if (!window.$D) { - window.$D = function (id) { - if (document.getElementById) { - return document.getElementById(id); - } else if (document.all) { - return document.all[id]; - } else if (document.layers) { - return document.layers[id]; - } - return undefined; - }; -} - - -/* - * ------------------------------------------------------ - * Namespaced in WebUtil - * ------------------------------------------------------ - */ - -// init log level reading the logging HTTP param -WebUtil.init_logging = function(level) { - if (typeof level !== "undefined") { - Util._log_level = level; - } else { - Util._log_level = (document.location.href.match( - /logging=([A-Za-z0-9\._\-]*)/) || - ['', Util._log_level])[1]; - } - Util.init_logging(); -}; - - -WebUtil.dirObj = function (obj, depth, parent) { - var i, msg = "", val = ""; - if (! depth) { depth=2; } - if (! parent) { parent= ""; } - - // Print the properties of the passed-in object - for (i in obj) { - if ((depth > 1) && (typeof obj[i] === "object")) { - // Recurse attributes that are objects - msg += WebUtil.dirObj(obj[i], depth-1, parent + "." + i); - } else { - //val = new String(obj[i]).replace("\n", " "); - if (typeof(obj[i]) === "undefined") { - val = "undefined"; - } else { - val = obj[i].toString().replace("\n", " "); - } - if (val.length > 30) { - val = val.substr(0,30) + "..."; - } - msg += parent + "." + i + ": " + val + "\n"; - } - } - return msg; -}; - -// Read a query string variable -WebUtil.getQueryVar = function(name, defVal) { - var re = new RegExp('[?][^#]*' + name + '=([^&#]*)'), - match = document.location.href.match(re); - if (typeof defVal === 'undefined') { defVal = null; } - if (match) { - return decodeURIComponent(match[1]); - } else { - return defVal; - } -}; - - -/* - * Cookie handling. Dervied from: http://www.quirksmode.org/js/cookies.html - */ - -// No days means only for this browser session -WebUtil.createCookie = function(name,value,days) { - var date, expires; - if (days) { - date = new Date(); - date.setTime(date.getTime()+(days*24*60*60*1000)); - expires = "; expires="+date.toGMTString(); - } - else { - expires = ""; - } - document.cookie = name+"="+value+expires+"; path=/"; -}; - -WebUtil.readCookie = function(name, defaultValue) { - var i, c, nameEQ = name + "=", ca = document.cookie.split(';'); - for(i=0; i < ca.length; i += 1) { - c = ca[i]; - while (c.charAt(0) === ' ') { c = c.substring(1,c.length); } - if (c.indexOf(nameEQ) === 0) { return c.substring(nameEQ.length,c.length); } - } - return (typeof defaultValue !== 'undefined') ? defaultValue : null; -}; - -WebUtil.eraseCookie = function(name) { - WebUtil.createCookie(name,"",-1); -}; - -/* - * Setting handling. - */ - -WebUtil.initSettings = function(callback) { - var callbackArgs = Array.prototype.slice.call(arguments, 1); - if (window.chrome && window.chrome.storage) { - window.chrome.storage.sync.get(function (cfg) { - WebUtil.settings = cfg; - console.log(WebUtil.settings); - if (callback) { - callback.apply(this, callbackArgs); - } - }); - } else { - // No-op - if (callback) { - callback.apply(this, callbackArgs); - } - } -}; - -// No days means only for this browser session -WebUtil.writeSetting = function(name, value) { - if (window.chrome && window.chrome.storage) { - //console.log("writeSetting:", name, value); - if (WebUtil.settings[name] !== value) { - WebUtil.settings[name] = value; - window.chrome.storage.sync.set(WebUtil.settings); - } - } else { - localStorage.setItem(name, value); - } -}; - -WebUtil.readSetting = function(name, defaultValue) { - var value; - if (window.chrome && window.chrome.storage) { - value = WebUtil.settings[name]; - } else { - value = localStorage.getItem(name); - } - if (typeof value === "undefined") { - value = null; - } - if (value === null && typeof defaultValue !== undefined) { - return defaultValue; - } else { - return value; - } -}; - -WebUtil.eraseSetting = function(name) { - if (window.chrome && window.chrome.storage) { - window.chrome.storage.sync.remove(name); - delete WebUtil.settings[name]; - } else { - localStorage.removeItem(name); - } -}; - -/* - * Alternate stylesheet selection - */ -WebUtil.getStylesheets = function() { var i, links, sheets = []; - links = document.getElementsByTagName("link"); - for (i = 0; i < links.length; i += 1) { - if (links[i].title && - links[i].rel.toUpperCase().indexOf("STYLESHEET") > -1) { - sheets.push(links[i]); - } - } - return sheets; -}; - -// No sheet means try and use value from cookie, null sheet used to -// clear all alternates. -WebUtil.selectStylesheet = function(sheet) { - var i, link, sheets = WebUtil.getStylesheets(); - if (typeof sheet === 'undefined') { - sheet = 'default'; - } - for (i=0; i < sheets.length; i += 1) { - link = sheets[i]; - if (link.title === sheet) { - Util.Debug("Using stylesheet " + sheet); - link.disabled = false; - } else { - //Util.Debug("Skipping stylesheet " + link.title); - link.disabled = true; - } - } - return sheet; -}; diff --git a/circle/dashboard/static/dashboard/profile.js b/circle/dashboard/static/dashboard/profile.js index 553e375..690936c 100644 --- a/circle/dashboard/static/dashboard/profile.js +++ b/circle/dashboard/static/dashboard/profile.js @@ -7,10 +7,10 @@ $(function() { $.ajax({ type: 'POST', url:"/dashboard/profile/" + user + "/use_gravatar/", - headers: {"X-CSRFToken": getCookie('csrftoken')}, + headers: {"X-CSRFToken": getCookie('csrftoken')}, success: function(re) { if(re.new_avatar_url) { - $("#dashboard-profile-avatar").prop("src", re.new_avatar_url); + $("#dashboard-profile-avatar").prop("src", re.new_avatar_url); } }, error: function(xhr, textStatus, error) { diff --git a/circle/dashboard/static/dashboard/store.js b/circle/dashboard/static/dashboard/store.js index 1970ddc..e921ae0 100644 --- a/circle/dashboard/static/dashboard/store.js +++ b/circle/dashboard/static/dashboard/store.js @@ -25,18 +25,18 @@ $(function() { $('#store-upload-form button[type="submit"] i').addClass("fa-spinner fa-spin"); var current_dir = $("#store-upload-form").find('[name="current_dir"]').val(); $.get($("#store-upload-form").data("action") + "?current_dir=" + current_dir, function(result) { - $("#store-upload-form").get(0).setAttribute("action", result['url']); + $("#store-upload-form").get(0).setAttribute("action", result.url); $("#store-upload-form").submit(); }); return false; }); - + /* "fake" browse button */ $("#store-list-container").on("click", "#store-upload-browse", function() { $('#store-upload-form input[type="file"]').click(); }); - + $("#store-list-container").on("change", "#store-upload-file", function() { var input = $(this); var numFiles = input.get(0).files ? input.get(0).files.length : 1; diff --git a/circle/dashboard/static/dashboard/template-list.js b/circle/dashboard/static/dashboard/template-list.js index a3e45ff..1c6ac21 100644 --- a/circle/dashboard/static/dashboard/template-list.js +++ b/circle/dashboard/static/dashboard/template-list.js @@ -20,7 +20,7 @@ $(function() { }); return false; }); - + /* template table sort */ var ttable = $(".template-list-table").stupidtable(); @@ -37,7 +37,7 @@ $(function() { // only if js is enabled $(".template-list-table thead th").css("cursor", "pointer"); - + $(".template-list-table th a").on("click", function(event) { if(!$(this).closest("th").data("sort")) return true; event.preventDefault(); @@ -49,16 +49,16 @@ $(function() { function deleteTemplate(data) { $.ajax({ type: 'POST', - url: data['url'], - headers: {"X-CSRFToken": getCookie('csrftoken')}, - success: function(re, textStatus, xhr) { - addMessage(re['message'], 'success'); - $('a[data-template-pk="' + data['template_pk'] + '"]').closest('tr').fadeOut(function() { + url: data.url, + headers: {"X-CSRFToken": getCookie('csrftoken')}, + success: function(re, textStatus, xhr) { + addMessage(re.message, 'success'); + $('a[data-template-pk="' + data.template_pk + '"]').closest('tr').fadeOut(function() { $(this).remove(); }); }, error: function(xhr, textStatus, error) { - addMessage('Uh oh :(', 'danger') + addMessage('Uh oh :(', 'danger'); } }); } @@ -68,16 +68,16 @@ function deleteTemplate(data) { function deleteLease(data) { $.ajax({ type: 'POST', - url: data['url'], - headers: {"X-CSRFToken": getCookie('csrftoken')}, - success: function(re, textStatus, xhr) { - addMessage(re['message'], 'success'); - $('a[data-lease-pk="' + data['lease_pk'] + '"]').closest('tr').fadeOut(function() { + url: data.url, + headers: {"X-CSRFToken": getCookie('csrftoken')}, + success: function(re, textStatus, xhr) { + addMessage(re.message, 'success'); + $('a[data-lease-pk="' + data.lease_pk + '"]').closest('tr').fadeOut(function() { $(this).remove(); }); }, error: function(xhr, textStatus, error) { - addMessage('Uh oh :(', 'danger') + addMessage('Uh oh :(', 'danger'); } }); } diff --git a/circle/dashboard/static/dashboard/vm-common.js b/circle/dashboard/static/dashboard/vm-common.js index 10111e8..cc749f1 100644 --- a/circle/dashboard/static/dashboard/vm-common.js +++ b/circle/dashboard/static/dashboard/vm-common.js @@ -66,7 +66,7 @@ $(function() { }, error: function(xhr, textStatus, error) { $('#confirmation-modal').modal("hide"); - + if (xhr.status == 500) { addMessage("500 Internal Server Error", "danger"); } else { diff --git a/circle/dashboard/static/dashboard/vm-console.js b/circle/dashboard/static/dashboard/vm-console.js index 15a75f9..b4da004 100644 --- a/circle/dashboard/static/dashboard/vm-console.js +++ b/circle/dashboard/static/dashboard/vm-console.js @@ -1,12 +1,12 @@ $(function() { "use strict"; - Util.load_scripts(["webutil.js", "base64.js", "websock.js", "des.js", - "input.js", "display.js", "jsunzip.js", "rfb.js"]); + // Util.load_scripts(["webutil.js", "base64.js", "websock.js", "des.js", + // "input.js", "display.js", "jsunzip.js", "rfb.js"]); var rfb; function updateState(rfb, state, oldstate, msg) { - $('#_console .btn-toolbar button').attr('disabled', !(state === "normal")); + $('#_console .btn-toolbar button').attr('disabled', (state !== "normal")); rfb.sendKey(0xffe3); // press and release ctrl to kill screensaver if (typeof(msg) !== 'undefined') { @@ -20,7 +20,7 @@ $(function() { rfb = 0; } $("#vm-info-pane").fadeIn(); - $("#vm-detail-pane").removeClass("col-md-12"); + $("#vm-detail-pane").removeClass("col-md-12").addClass("col-md-8"); }); $('#sendCtrlAltDelButton').click(function() { rfb.sendCtrlAltDel(); return false;}); @@ -35,20 +35,20 @@ $(function() { var host, port, password, path; $("#vm-info-pane").hide(); - $("#vm-detail-pane").addClass("col-md-12"); + $("#vm-detail-pane").removeClass("col-md-8").addClass("col-md-12"); WebUtil.init_logging('warn'); host = window.location.hostname; if (window.location.port == 8080) { port = 9999; } else { - port = window.location.port == "" ? "443" : window.location.port; + port = window.location.port === "" ? "443" : window.location.port; } password = ''; $('#_console .btn-toolbar button').attr('disabled', true); $('#noVNC_status').html('Retreiving authorization token.'); $.get(VNC_URL, function(data) { - if (data.indexOf('vnc') != 0) { + if (data.indexOf('vnc') !== 0) { $('#noVNC_status').html('No authorization token received.'); } else { @@ -58,13 +58,13 @@ $(function() { 'local_cursor': true, 'shared': true, 'view_only': false, - 'updateState': updateState}); + 'onUpdateState': updateState}); rfb.connect(host, port, password, data); } }).fail(function(){ $('#noVNC_status').html("Can't connect to console."); }); }); - if (window.location.hash == "#console") - window.onscriptsload = function(){$('a[href$="console"]').click();}; + if (window.location.hash === "#console") + $('a[href$="console"]').trigger("click"); }); diff --git a/circle/dashboard/static/dashboard/vm-create.js b/circle/dashboard/static/dashboard/vm-create.js index cdbb550..681af5e 100644 --- a/circle/dashboard/static/dashboard/vm-create.js +++ b/circle/dashboard/static/dashboard/vm-create.js @@ -18,7 +18,7 @@ function vmCreateLoaded() { $(".customize-vm").click(function() { var template = $(this).data("template-pk"); - + $.get("/dashboard/vm/create/?template=" + template, function(data) { var r = $('#create-modal'); r.next('div').remove(); r.remove(); $('body').append(data); @@ -34,7 +34,7 @@ function vmCreateLoaded() { }); return false; }); - + /* start vm button clicks */ $('.vm-create-start').click(function() { template = $(this).data("template-pk"); @@ -60,7 +60,7 @@ function vmCreateLoaded() { }, error: function(xhr, textStatus, error) { var r = $('#create-modal'); r.next('div').remove(); r.remove(); - + if (xhr.status == 500) { addMessage("500 Internal Server Error", "danger"); } else { @@ -77,7 +77,7 @@ function vmCreateLoaded() { var now = $(this).attr('aria-valuenow'); var siz = (now-min)*100/(max-min); $(this).css('width', siz+'%'); - }); + }); } @@ -93,18 +93,18 @@ function vmCustomizeLoaded() { // remove the hex chars name = name.substring(name.indexOf(" "), name.length); - if ($('#vm-create-network-list').children('span').length < 1) { + if ($('#vm-create-network-list').children('span').length < 1) { $('#vm-create-network-list').html(''); - } + } $('#vm-create-network-list').append( vmCreateNetworkLabel(vlan_pk, name, managed) ); - + /* select the network in the hidden network select */ $('#vm-create-network-add-vlan option[value="' + vlan_pk + '"]').prop('selected', true); $('option:selected', $('#vm-create-network-add-select')).remove(); - + /* add dummy text if no more networks are available */ if($('#vm-create-network-add-select option').length < 1) { $('#vm-create-network-add-button').attr('disabled', true); @@ -117,23 +117,23 @@ function vmCustomizeLoaded() { /* remove network */ // event for network remove button (icon, X) $('body').on('click', '.vm-create-remove-network', function() { - var vlan_pk = ($(this).parent('span').prop('id')).replace('vlan-', '') + var vlan_pk = ($(this).parent('span').prop('id')).replace('vlan-', ''); // if it's "blue" then it's managed, kinda not cool var managed = $(this).parent('span').hasClass('label-primary'); $(this).parent('span').fadeOut(500, function() { /* if ther are no more vlans disabled the add button */ - if($('#vm-create-network-add-select option')[0].value == -1) { - $('#vm-create-network-add-button').attr('disabled', false); + if($('#vm-create-network-add-select option')[0].value == -1) { + $('#vm-create-network-add-button').attr('disabled', false); $('#vm-create-network-add-select').html(''); } - + /* remove the network label */ - $(this).remove(); + $(this).remove(); var vlan_name = $(this).text(); - var html = ''; $('#vm-create-network-add-select').append(html); @@ -148,7 +148,7 @@ function vmCustomizeLoaded() { /* copy networks from hidden select */ $('#vm-create-network-add-vlan option').each(function() { - var managed = $(this).text().indexOf("mana") == 0; + var managed = $(this).text().indexOf("mana") === 0; var raw_text = $(this).text(); var pk = $(this).val(); if(managed) { @@ -157,7 +157,7 @@ function vmCustomizeLoaded() { text = raw_text.replace("unmanaged -", ""); } var html = ''; - + if($('#vm-create-network-list span').length < 1) { $("#vm-create-network-list").html(""); } @@ -180,7 +180,7 @@ function vmCustomizeLoaded() { vlans.push({ 'name': $(this).text().replace("unmanaged -", "").replace("managed -", ""), 'pk': parseInt($(this).val()), - 'managed': $(this).text().indexOf("mana") == 0, + 'managed': $(this).text().indexOf("mana") === 0, }); }); @@ -250,7 +250,7 @@ function vmCustomizeLoaded() { }, error: function(xhr, textStatus, error) { var r = $('#create-modal'); r.next('div').remove(); r.remove(); - + if (xhr.status == 500) { addMessage("500 Internal Server Error", "danger"); } else { @@ -262,8 +262,8 @@ function vmCustomizeLoaded() { }); /* for no js stuff */ - $('.no-js-hidden').show(); - $('.js-hidden').hide(); + $('.no-js-hidden').show(); + $('.js-hidden').hide(); } diff --git a/circle/dashboard/static/dashboard/vm-details.js b/circle/dashboard/static/dashboard/vm-details.js index e851d86..d0422e7 100644 --- a/circle/dashboard/static/dashboard/vm-details.js +++ b/circle/dashboard/static/dashboard/vm-details.js @@ -1,6 +1,7 @@ var show_all = false; var in_progress = false; var activity_hash = 5; +var Websock_native; // not sure var reload_vm_detail = false; $(function() { @@ -42,7 +43,7 @@ $(function() { var vm = $(this).data("vm"); $.ajax({ type: 'POST', - url: "/dashboard/vm/" + vm + "/op/resources_change/", + url: "/dashboard/vm/" + vm + "/op/resources_change/", data: $('#vm-details-resources-form').serialize(), success: function(data, textStatus, xhr) { if(data.success) { @@ -58,7 +59,7 @@ $(function() { addMessage("500 Internal Server Error", "danger"); } else { addMessage(xhr.status + " Unknown Error", "danger"); - } + } } }); e.preventDefault(); @@ -71,17 +72,17 @@ $(function() { $.ajax({ type: 'POST', url: location.href, - headers: {"X-CSRFToken": getCookie('csrftoken')}, + headers: {"X-CSRFToken": getCookie('csrftoken')}, data: {'to_remove': to_remove}, success: function(re) { - if(re['message'].toLowerCase() == "success") { + if(re.message.toLowerCase() == "success") { $(clicked).closest(".label").fadeOut(500, function() { $(this).remove(); }); } }, error: function() { - addMessage(re['message'], 'danger'); + addMessage(re.message, 'danger'); } }); @@ -90,7 +91,7 @@ $(function() { /* remove port */ $('.vm-details-remove-port').click(function() { - addModalConfirmation(removePort, + addModalConfirmation(removePort, { 'url': $(this).prop("href"), 'data': [], @@ -101,7 +102,7 @@ $(function() { /* for js fallback */ $("#vm-details-pw-show").parent("div").children("input").prop("type", "password"); - + /* show password */ $("#vm-details-pw-show").click(function() { var input = $(this).parent("div").children("input"); @@ -150,7 +151,7 @@ $(function() { } }); } else { - $("#vm-details-pw-confirm").fadeOut(); + $("#vm-details-pw-confirm").fadeOut(); } return false; }); @@ -170,7 +171,7 @@ $(function() { /* for interface remove buttons */ $('.interface-remove').click(function() { var interface_pk = $(this).data('interface-pk'); - addModalConfirmation(removeInterface, + addModalConfirmation(removeInterface, { 'url': '/dashboard/interface/' + interface_pk + '/delete/', 'data': [], 'pk': interface_pk, @@ -183,15 +184,15 @@ $(function() { function removeInterface(data) { $.ajax({ type: 'POST', - url: data['url'], - headers: {"X-CSRFToken": getCookie('csrftoken')}, - success: function(re, textStatus, xhr) { + url: data.url, + headers: {"X-CSRFToken": getCookie('csrftoken')}, + success: function(re, textStatus, xhr) { /* remove the html element */ $('a[data-interface-pk="' + data.pk + '"]').closest("div").fadeOut(); location.reload(); }, error: function(xhr, textStatus, error) { - addMessage('Uh oh :(', 'danger') + addMessage('Uh oh :(', 'danger'); } }); } @@ -221,12 +222,12 @@ $(function() { data: {'new_name': name}, headers: {"X-CSRFToken": getCookie('csrftoken')}, success: function(data, textStatus, xhr) { - $(".vm-details-home-edit-name").text(data['new_name']).show(); + $(".vm-details-home-edit-name").text(data.new_name).show(); $(".vm-details-home-edit-name").parent("div").show(); $(".vm-details-home-edit-name-click").show(); $(".vm-details-home-rename-form-div").hide(); // update the inputs too - $(".vm-details-rename-submit").parent("span").prev("input").val(data['new_name']); + $(".vm-details-rename-submit").parent("span").prev("input").val(data.new_name); }, error: function(xhr, textStatus, error) { addMessage("Error during renaming!", "danger"); @@ -234,7 +235,7 @@ $(function() { }); return false; }); - + /* update description click */ $(".vm-details-home-edit-description-click").click(function(e) { $(".vm-details-home-edit-description-click").hide(); @@ -246,7 +247,7 @@ $(function() { ta.val(tmp) e.preventDefault(); }); - + /* description update ajax */ $('.vm-details-description-submit').click(function() { var description = $(this).prev("textarea").val(); @@ -256,14 +257,14 @@ $(function() { data: {'new_description': description}, headers: {"X-CSRFToken": getCookie('csrftoken')}, success: function(data, textStatus, xhr) { - var new_desc = data['new_description']; - /* we can't simply use $.text, because we need new lines */ + var new_desc = data.new_description; + /* we can't simply use $.text, because we need new lines */ var tagsToReplace = { '&': "&", '<': "<", '>': ">", }; - + new_desc = new_desc.replace(/[&<>]/g, function(tag) { return tagsToReplace[tag] || tag; }); @@ -273,7 +274,7 @@ $(function() { $(".vm-details-home-edit-description-click").show(); $("#vm-details-home-description").hide(); // update the textareia - $("vm-details-home-description textarea").text(data['new_description']); + $("vm-details-home-description textarea").text(data.new_description); }, error: function(xhr, textStatus, error) { addMessage("Error during renaming!", "danger"); @@ -300,8 +301,8 @@ $(function() { .find("i").removeClass("fa-spinner fa-spin"); }); - - + + // screenshot close $("#vm-console-screenshot button").click(function() { $(this).parent("div").slideUp(); @@ -340,15 +341,15 @@ $(function() { function removePort(data) { $.ajax({ type: 'POST', - url: data['url'], + url: data.url, headers: {"X-CSRFToken": getCookie('csrftoken')}, success: function(re, textStatus, xhr) { - $("a[data-rule=" + data['rule'] + "]").each(function() { + $("a[data-rule=" + data.rule + "]").each(function() { $(this).closest("tr").fadeOut(500, function() { $(this).remove(); }); }); - addMessage(re['message'], "success"); + addMessage(re.message, "success"); }, error: function(xhr, textStatus, error) { @@ -374,23 +375,23 @@ function checkNewActivity(runs) { url: '/dashboard/vm/' + instance + '/activity/', data: {'show_all': show_all}, success: function(data) { - var new_activity_hash = (data['activities'] + "").hashCode(); + var new_activity_hash = (data.activities + "").hashCode(); if(new_activity_hash != activity_hash) { - $("#activity-refresh").html(data['activities']); + $("#activity-refresh").html(data.activities); } activity_hash = new_activity_hash; - $("#ops").html(data['ops']); - $("#disk-ops").html(data['disk_ops']); + $("#ops").html(data.ops); + $("#disk-ops").html(data.disk_ops); $("[title]").tooltip(); /* changing the status text */ var icon = $("#vm-details-state i"); - if(data['is_new_state']) { + if(data.is_new_state) { if(!icon.hasClass("fa-spin")) icon.prop("class", "fa fa-spinner fa-spin"); } else { - icon.prop("class", "fa " + data['icon']); + icon.prop("class", "fa " + data.icon); } $("#vm-details-state").data("status", data['status']); $("#vm-details-state span").html(data['human_readable_status'].toUpperCase()); @@ -406,7 +407,7 @@ function checkNewActivity(runs) { $("[data-target=#_console]").attr("data-toggle", "_pill").attr("href", "#").parent("li").addClass("disabled"); } - if(data['status'] == "STOPPED" || data['status'] == "PENDING") { + if(data.status == "STOPPED" || data.status == "PENDING") { $(".change-resources-button").prop("disabled", false); $(".change-resources-help").hide(); } else { @@ -416,7 +417,7 @@ function checkNewActivity(runs) { if(runs > 0 && decideActivityRefresh()) { setTimeout( - function() {checkNewActivity(runs + 1)}, + function() {checkNewActivity(runs + 1);}, 1000 + Math.exp(runs * 0.05) ); } else { @@ -433,7 +434,7 @@ function checkNewActivity(runs) { String.prototype.hashCode = function() { var hash = 0, i, chr, len; - if (this.length == 0) return hash; + if (this.length === 0) return hash; for (i = 0, len = this.length; i < len; i++) { chr = this.charCodeAt(i); hash = ((hash << 5) - hash) + chr; diff --git a/circle/dashboard/static/dashboard/vm-list.js b/circle/dashboard/static/dashboard/vm-list.js index b9d9ded..f4a73a4 100644 --- a/circle/dashboard/static/dashboard/vm-list.js +++ b/circle/dashboard/static/dashboard/vm-list.js @@ -25,7 +25,7 @@ $(function() { retval = false; } else if(shiftDown) { if(selected.length > 0) { - start = selected[selected.length - 1]['index'] + 1; + start = selected[selected.length - 1].index + 1; end = $(this).index(); if(start > end) { @@ -101,7 +101,7 @@ $(function() { }); - $("body").on("click", "#op-form-send", function() { + $("body").on("click", "#mass-op-form-send", function() { var url = $(this).closest("form").prop("action"); $(this).find("i").prop("class", "fa fa-fw fa-spinner fa-spin"); diff --git a/circle/dashboard/static/template.css b/circle/dashboard/static/template.less similarity index 78% rename from circle/dashboard/static/template.css rename to circle/dashboard/static/template.less index 8ce2de7..3f23f1a 100644 --- a/circle/dashboard/static/template.css +++ b/circle/dashboard/static/template.less @@ -23,46 +23,6 @@ html { padding-right: 15px; } -/* values for 45px tall navbar */ -.navbar { - min-height: 45px; -} - -.navbar-brand { - height: 45px; - padding: 12.5px 12.5px; -} - -.navbar-toggle { - margin-top: 5.5px; - margin-bottom: 5.5px; -} - -.navbar-form { - margin-top: 5.5px; - margin-bottom: 5.5px; -} - -.navbar-btn { - margin-top: 5.5px; - margin-bottom: 5.5px; -} - -.navbar-btn.btn-sm { - margin-top: 7.5px; - margin-bottom: 7.5px; -} -.navbar-btn.btn-xs { - margin-top: 11.5px; - margin-bottom: 11.5px; -} -.navbar-text { - margin-top: 12.5px; - margin-bottom: 12.5px; -} - -/* --- */ - /* Responsive: Portrait tablets and up */ @media screen and (min-width: 768px) { /* Let the jumbotron breathe */ diff --git a/circle/dashboard/templates/base.html b/circle/dashboard/templates/base.html index ccee162..58fbd43 100644 --- a/circle/dashboard/templates/base.html +++ b/circle/dashboard/templates/base.html @@ -1,4 +1,6 @@ {% load i18n %} +{% load staticfiles %} +{% load compressed %} @@ -6,14 +8,11 @@ - + {% block title %}{% block title-page %}{% endblock %} | {% block title-site %}CIRCLE{% endblock %}{% endblock %} - - - - + {% compressed_css 'all' %} {% endblock %} - -{% block extra_js %} - -{% endblock %} diff --git a/circle/dashboard/templates/dashboard/node-list/column-monitor.html b/circle/dashboard/templates/dashboard/node-list/column-monitor.html index f955db2..77a37a9 100644 --- a/circle/dashboard/templates/dashboard/node-list/column-monitor.html +++ b/circle/dashboard/templates/dashboard/node-list/column-monitor.html @@ -2,7 +2,7 @@ {% load i18n %} {% trans "CPU" %} -
+
+
-
+
+
+ {% trans "Memory" %} -
+
-
- - - +
diff --git a/circle/dashboard/templates/dashboard/nojs-wrapper.html b/circle/dashboard/templates/dashboard/nojs-wrapper.html index e5f87c2..7ec7b87 100644 --- a/circle/dashboard/templates/dashboard/nojs-wrapper.html +++ b/circle/dashboard/templates/dashboard/nojs-wrapper.html @@ -1,4 +1,5 @@ {% extends "dashboard/base.html" %} +{% load staticfiles %} {% block content %}
@@ -14,9 +15,3 @@
{% endblock %} - -{% block extra_js %} - {% if template == "dashboard/_vm-create-1.html" or template == "dashboard/_vm-create-2.html" %} - - {% endif %} -{% endblock %} diff --git a/circle/dashboard/templates/dashboard/profile.html b/circle/dashboard/templates/dashboard/profile.html index 7e10e62..5c2a07a 100644 --- a/circle/dashboard/templates/dashboard/profile.html +++ b/circle/dashboard/templates/dashboard/profile.html @@ -1,4 +1,5 @@ {% extends "dashboard/base.html" %} +{% load staticfiles %} {% load i18n %} {% load crispy_forms_tags %} @@ -111,7 +112,3 @@
{% endblock %} - -{% block extra_js %} - -{% endblock %} diff --git a/circle/dashboard/templates/dashboard/store/index-files.html b/circle/dashboard/templates/dashboard/store/index-files.html index 4930924..92cb582 100644 --- a/circle/dashboard/templates/dashboard/store/index-files.html +++ b/circle/dashboard/templates/dashboard/store/index-files.html @@ -3,10 +3,11 @@
+ title="{% trans "A list of your most recent files." %}" + data-container="body"> - {% for t in files.toplist %} {% if t.TYPE == "F" %} -
+
{{ t.NAME }} @@ -37,7 +39,8 @@
{% else %}
+ class="list-group-item + {% if forloop.last and files.toplist|length < 5 %}list-group-item-last{% endif %}">
{{ t.NAME }} diff --git a/circle/dashboard/templates/dashboard/store/list.html b/circle/dashboard/templates/dashboard/store/list.html index d0702ac..1cd33dc 100644 --- a/circle/dashboard/templates/dashboard/store/list.html +++ b/circle/dashboard/templates/dashboard/store/list.html @@ -1,4 +1,5 @@ {% extends "dashboard/base.html" %} +{% load staticfiles %} {% load i18n %} {% block title-page %}{% trans "List" %} | {% trans "Store" %}{% endblock %} @@ -17,26 +18,23 @@
-
+
{% blocktrans with used=quota.readable_used %} {{ used }} used {% endblocktrans %}
-
-
+ data-placement="top" data-container="body">
{% endblock %} - -{% block extra_js %} - -{% endblock %} diff --git a/circle/dashboard/templates/dashboard/template-edit.html b/circle/dashboard/templates/dashboard/template-edit.html index 64963e7..83b7f06 100644 --- a/circle/dashboard/templates/dashboard/template-edit.html +++ b/circle/dashboard/templates/dashboard/template-edit.html @@ -1,4 +1,5 @@ {% extends "dashboard/base.html" %} +{% load staticfiles %} {% load i18n %} {% load sizefieldtags %} {% load crispy_forms_tags %} @@ -152,6 +153,4 @@ $("#hint_id_num_cores, #hint_id_priority, #hint_id_ram_size").hide(); }); - - {% endblock %} diff --git a/circle/dashboard/templates/dashboard/template-list.html b/circle/dashboard/templates/dashboard/template-list.html index 29ec340..e768096 100644 --- a/circle/dashboard/templates/dashboard/template-list.html +++ b/circle/dashboard/templates/dashboard/template-list.html @@ -1,4 +1,5 @@ {% extends "dashboard/base.html" %} +{% load staticfiles %} {% load i18n %} {% load render_table from django_tables2 %} @@ -75,8 +76,3 @@
{% endif %} {% endblock %} - -{% block extra_js %} - - -{% endblock %} diff --git a/circle/dashboard/templates/dashboard/vm-detail.html b/circle/dashboard/templates/dashboard/vm-detail.html index 84e95e9..b757677 100644 --- a/circle/dashboard/templates/dashboard/vm-detail.html +++ b/circle/dashboard/templates/dashboard/vm-detail.html @@ -1,5 +1,7 @@ {% extends "dashboard/base.html" %} +{% load staticfiles %} {% load i18n %} +{% load compressed %} {% block title-page %}{{ instance.name }} | vm{% endblock %} @@ -70,6 +72,13 @@ {{ instance.name }}
{{ instance.primary_host.get_fqdn }} + + {% if fav %} + + {% else %} + + {% endif %} +
@@ -220,10 +229,5 @@ {% endblock %} {% block extra_js %} - - - - - - + {% compressed_js 'vm-detail' %} {% endblock %} diff --git a/circle/dashboard/templates/dashboard/vm-detail/console.html b/circle/dashboard/templates/dashboard/vm-detail/console.html index e58cf07..a9a71ae 100644 --- a/circle/dashboard/templates/dashboard/vm-detail/console.html +++ b/circle/dashboard/templates/dashboard/vm-detail/console.html @@ -1,4 +1,5 @@ {% load i18n %} +{% load staticfiles %}
{% if perms.vm.access_console %} @@ -22,9 +23,8 @@ Canvas not supported. - {% endif %} diff --git a/circle/dashboard/templates/dashboard/vm-list.html b/circle/dashboard/templates/dashboard/vm-list.html index c7bc1dc..9cb56c8 100644 --- a/circle/dashboard/templates/dashboard/vm-list.html +++ b/circle/dashboard/templates/dashboard/vm-list.html @@ -1,4 +1,5 @@ {% extends "dashboard/base.html" %} +{% load staticfiles %} {% load i18n %} {% block title-page %}{% trans "Virtual machines" %}{% endblock %} @@ -154,8 +155,3 @@
{% endblock %} - -{% block extra_js %} - - -{% endblock %} diff --git a/circle/dashboard/templates/dashboard/vm-opensearch.xml b/circle/dashboard/templates/dashboard/vm-opensearch.xml new file mode 100644 index 0000000..cf323d8 --- /dev/null +++ b/circle/dashboard/templates/dashboard/vm-opensearch.xml @@ -0,0 +1,6 @@ +{% load i18n %} + + {% blocktrans with name=COMPANY_NAME %}{{name}} virtual machines{% endblocktrans %} + + diff --git a/circle/dashboard/tests/test_templates.py b/circle/dashboard/tests/test_templates.py new file mode 100644 index 0000000..2592bc4 --- /dev/null +++ b/circle/dashboard/tests/test_templates.py @@ -0,0 +1,52 @@ +# Copyright 2014 Budapest University of Technology and Economics (BME IK) +# +# This file is part of CIRCLE Cloud. +# +# CIRCLE is free software: you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) +# any later version. +# +# CIRCLE is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License along +# with CIRCLE. If not, see . + +from os import listdir +from os.path import isfile, isdir, join +import unittest + +from django.conf import settings +from django.template import Template, Context, VariableDoesNotExist +from django.template.loader import find_template_loader +from django.core.urlresolvers import NoReverseMatch + + +class TemplateSyntaxTestCase(unittest.TestCase): + + def test_templates(self): + """Test all templates for syntax errors.""" + for loader_name in settings.TEMPLATE_LOADERS: + print loader_name + loader = find_template_loader(loader_name) + self._test_dir(loader.get_template_sources('')) + + def _test_dir(self, dir, path="/"): + for i in dir: + i = join(path, i) + if isfile(i): + self._test_template(join(path, i)) + elif isdir(i): + print "%s:" % i + self._test_dir(listdir(i), i) + + def _test_template(self, path): + print path + try: + Template(open(path).read()).render(Context({})) + except (NoReverseMatch, VariableDoesNotExist, KeyError, AttributeError, + ValueError, ) as e: + print e diff --git a/circle/dashboard/urls.py b/circle/dashboard/urls.py index 9bbc5b2..2c93f64 100644 --- a/circle/dashboard/urls.py +++ b/circle/dashboard/urls.py @@ -50,6 +50,7 @@ from .views import ( VmGraphView, NodeGraphView, NodeListGraphView, TransferInstanceOwnershipView, TransferInstanceOwnershipConfirmView, TransferTemplateOwnershipView, TransferTemplateOwnershipConfirmView, + OpenSearchDescriptionView, ) from .views.vm import vm_ops, vm_mass_ops from .views.node import node_ops @@ -221,6 +222,8 @@ urlpatterns = patterns( name="dashboard.views.client-check"), url(r'^token-login/(?P.*)/$', TokenLogin.as_view(), name="dashboard.views.token-login"), + url(r'^vm/opensearch.xml$', OpenSearchDescriptionView.as_view(), + name="dashboard.views.vm-opensearch"), ) urlpatterns += patterns( diff --git a/circle/dashboard/views/index.py b/circle/dashboard/views/index.py index bd4839a..2ffb18a 100644 --- a/circle/dashboard/views/index.py +++ b/circle/dashboard/views/index.py @@ -19,6 +19,7 @@ from __future__ import unicode_literals, absolute_import import logging from django.core.cache import get_cache +from django.core.urlresolvers import reverse from django.conf import settings from django.contrib.auth.models import Group from django.views.generic import TemplateView @@ -121,3 +122,15 @@ class HelpView(TemplateView): ctx.update({"saml": hasattr(settings, "SAML_CONFIG"), "store": settings.STORE_URL}) return ctx + + +class OpenSearchDescriptionView(TemplateView): + template_name = "dashboard/vm-opensearch.xml" + content_type = "application/opensearchdescription+xml" + + def get_context_data(self, **kwargs): + context = super(OpenSearchDescriptionView, self).get_context_data( + **kwargs) + context['url'] = self.request.build_absolute_uri( + reverse("dashboard.views.vm-list")) + return context diff --git a/circle/dashboard/views/vm.py b/circle/dashboard/views/vm.py index 606b768..b02153f 100644 --- a/circle/dashboard/views/vm.py +++ b/circle/dashboard/views/vm.py @@ -115,6 +115,7 @@ class VmDetailView(GraphMixin, CheckedDetailView): 'op': {i.op: i for i in ops}, 'connect_commands': user.profile.get_connect_commands(instance), 'hide_tutorial': hide_tutorial, + 'fav': instance.favourite_set.filter(user=user).exists(), }) # activity data diff --git a/circle/fabfile.py b/circle/fabfile.py index 42e1477..73460b9 100755 --- a/circle/fabfile.py +++ b/circle/fabfile.py @@ -34,6 +34,15 @@ def pip(env, req): run("pip install -r %s" % req) +def bower(component=None): + "Install bower component" + with cd("~/circle/circle"): + if component: + run("bower install %s" % component) + else: + run("bower install") + + @roles('portal') def migrate(): "Run db migrations" @@ -113,11 +122,14 @@ def pull(dir="~/circle/circle"): @roles('portal') -def update_portal(test=False): +def update_portal(test=False, git=True): "Update and restart portal+manager" with _stopped("portal", "manager"): - pull() + if git: + pull() + cleanup() pip("circle", "~/circle/requirements.txt") + bower() migrate() compile_things() if test: @@ -125,6 +137,12 @@ def update_portal(test=False): @roles('portal') +def build_portal(): + "Update portal without pulling from git" + return update_portal(False, False) + + +@roles('portal') def stop_portal(test=False): "Stop portal and manager" _stop_services("portal", "manager") @@ -136,10 +154,15 @@ def update_node(): with _stopped("node", "agentdriver", "monitor-client"): pull("~/vmdriver") pip("vmdriver", "~/vmdriver/requirements/production.txt") + _cleanup("~/vmdriver") + pull("~/agentdriver") pip("agentdriver", "~/agentdriver/requirements.txt") + _cleanup("~/agentdriver") + pull("~/monitor-client") pip("monitor-client", "~/monitor-client/requirements.txt") + _cleanup("~/monitor-client") @parallel @@ -161,6 +184,18 @@ def checkout(vmdriver="master", agent="master"): run("git checkout %s" % agent) +@roles('portal') +def cleanup(): + "Clean pyc files of portal" + _cleanup() + + +def _cleanup(dir="~/circle/circle"): + "Clean pyc files" + with cd("~/circle/circle"): + run("find -name '*.py[co]' -exec rm -f {} +") + + def _stop_services(*services): "Stop given services (warn only if not running)" with settings(warn_only=True): @@ -189,3 +224,12 @@ def _stopped(*services): def _workon(name): return prefix("source ~/.virtualenvs/%s/bin/activate && " "source ~/.virtualenvs/%s/bin/postactivate" % (name, name)) + + +@roles('portal') +def install_bash_completion_script(): + sudo("wget https://raw.githubusercontent.com/marcelor/fabric-bash-" + "autocompletion/48baf5735bafbb2be5be8787d2c2c04a44b6cdb0/fab " + "-O /etc/bash_completion.d/fab") + print("To have bash completion instantly, run\n" + " source /etc/bash_completion.d/fab") diff --git a/circle/firewall/fields.py b/circle/firewall/fields.py index 8da33a4..6113ba0 100644 --- a/circle/firewall/fields.py +++ b/circle/firewall/fields.py @@ -15,6 +15,7 @@ # You should have received a copy of the GNU General Public License along # with CIRCLE. If not, see . +from string import ascii_letters from django.core.exceptions import ValidationError from django.db import models from django.utils.translation import ugettext_lazy as _ @@ -22,7 +23,7 @@ from django.utils.ipv6 import is_valid_ipv6_address from south.modelsinspector import add_introspection_rules from django import forms from netaddr import (IPAddress, IPNetwork, AddrFormatError, ZEROFILL, - EUI, mac_unix) + EUI, mac_unix, AddrConversionError) import re @@ -31,7 +32,6 @@ domain_re = re.compile(r'^([A-Za-z0-9_-]\.?)+$') domain_wildcard_re = re.compile(r'^(\*\.)?([A-Za-z0-9_-]\.?)+$') ipv4_re = re.compile('^([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)$') reverse_domain_re = re.compile(r'^(%\([abcd]\)d|[a-z0-9.-])+$') -ipv6_template_re = re.compile(r'^(%\([abcd]\)[dxX]|[A-Za-z0-9:-])+$') class mac_custom(mac_unix): @@ -246,15 +246,60 @@ def val_reverse_domain(value): raise ValidationError(u'%s - invalid reverse domain name' % value) -def is_valid_ipv6_template(value): - """Check whether the parameter is a valid ipv6 template.""" - return ipv6_template_re.match(value) is not None - - def val_ipv6_template(value): - """Validate whether the parameter is a valid ipv6 template.""" - if not is_valid_ipv6_template(value): - raise ValidationError(u'%s - invalid reverse ipv6 template' % value) + """Validate whether the parameter is a valid ipv6 template. + + Normal use: + >>> val_ipv6_template("123::%(a)d:%(b)d:%(c)d:%(d)d") + >>> val_ipv6_template("::%(a)x:%(b)x:%(c)d:%(d)d") + + Don't have to use all bytes from the left (no a): + >>> val_ipv6_template("::%(b)x:%(c)d:%(d)d") + + But have to use all ones to the right (a, but no b): + >>> val_ipv6_template("::%(a)x:%(c)d:%(d)d") + Traceback (most recent call last): + ... + ValidationError: [u"template doesn't use parameter b"] + + Detects valid templates building invalid ips: + >>> val_ipv6_template("xxx::%(a)d:%(b)d:%(c)d:%(d)d") + Traceback (most recent call last): + ... + ValidationError: [u'template renders invalid IPv6 address'] + + Also IPv4-compatible addresses are invalid: + >>> val_ipv6_template("::%(a)02x%(b)02x:%(c)d:%(d)d") + Traceback (most recent call last): + ... + ValidationError: [u'template results in IPv4 address'] + """ + tpl = {ascii_letters[i]: 255 for i in range(4)} + try: + v6 = value % tpl + except: + raise ValidationError(_('%s: invalid template') % value) + + used = False + for i in ascii_letters[:4]: + try: + value % {k: tpl[k] for k in tpl if k != i} + except KeyError: + used = True # ok, it misses this key + else: + if used: + raise ValidationError( + _("template doesn't use parameter %s") % i) + try: + v6 = IPAddress(v6, 6) + except: + raise ValidationError(_('template renders invalid IPv6 address')) + try: + v6.ipv4() + except (AddrConversionError, AddrFormatError): + pass # can't converted to ipv4 == it's real ipv6 + else: + raise ValidationError(_('template results in IPv4 address')) def is_valid_ipv4_address(value): @@ -284,12 +329,3 @@ def val_mx(value): domain_re.match(mx[1])): raise ValidationError(_("Bad MX address format. " "Should be: :")) - - -def convert_ipv4_to_ipv6(ipv6_template, ipv4): - """Convert IPv4 address string to IPv6 address string.""" - m = ipv4.words - return IPAddress(ipv6_template % {'a': int(m[0]), - 'b': int(m[1]), - 'c': int(m[2]), - 'd': int(m[3])}) diff --git a/circle/firewall/management/__init__.py b/circle/firewall/management/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/circle/firewall/management/__init__.py diff --git a/circle/firewall/management/commands/__init__.py b/circle/firewall/management/commands/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/circle/firewall/management/commands/__init__.py diff --git a/circle/firewall/management/commands/reload_firewall.py b/circle/firewall/management/commands/reload_firewall.py new file mode 100644 index 0000000..9be52f8 --- /dev/null +++ b/circle/firewall/management/commands/reload_firewall.py @@ -0,0 +1,27 @@ +# Copyright 2014 Budapest University of Technology and Economics (BME IK) +# +# This file is part of CIRCLE Cloud. +# +# CIRCLE is free software: you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) +# any later version. +# +# CIRCLE is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License along +# with CIRCLE. If not, see . + +from __future__ import unicode_literals, absolute_import + +from django.core.management.base import BaseCommand + +from firewall.tasks.local_tasks import reloadtask + + +class Command(BaseCommand): + def handle(self, *args, **options): + reloadtask('Vlan') diff --git a/circle/firewall/models.py b/circle/firewall/models.py index 2a7e6ba..b4d4299 100644 --- a/circle/firewall/models.py +++ b/circle/firewall/models.py @@ -17,9 +17,11 @@ # You should have received a copy of the GNU General Public License along # with CIRCLE. If not, see . -from itertools import islice, ifilter +from string import ascii_letters +from itertools import islice, ifilter, chain +from math import ceil import logging -from netaddr import IPSet, EUI, IPNetwork +import random from django.contrib.auth.models import User from django.db import models @@ -28,15 +30,17 @@ from django.utils.translation import ugettext_lazy as _ from firewall.fields import (MACAddressField, val_alfanum, val_reverse_domain, val_ipv6_template, val_domain, val_ipv4, val_domain_wildcard, - val_ipv6, val_mx, convert_ipv4_to_ipv6, + val_ipv6, val_mx, IPNetworkField, IPAddressField) from django.core.validators import MinValueValidator, MaxValueValidator import django.conf from django.db.models.signals import post_save, post_delete -import random +from celery.exceptions import TimeoutError +from netaddr import IPSet, EUI, IPNetwork, IPAddress, ipv6_full from common.models import method_cache, WorkerNotFound, HumanSortField from firewall.tasks.local_tasks import reloadtask +from firewall.tasks.remote_tasks import get_dhcp_clients from .iptables import IptRule from acl.models import AclBase @@ -360,9 +364,19 @@ class Vlan(AclBase, models.Model): 'address is: "%(d)d.%(c)d.%(b)d.%(a)d.in-addr.arpa".'), default="%(d)d.%(c)d.%(b)d.%(a)d.in-addr.arpa") ipv6_template = models.TextField( - validators=[val_ipv6_template], - verbose_name=_('ipv6 template'), - default="2001:738:2001:4031:%(b)d:%(c)d:%(d)d:0") + blank=True, + help_text=_('Template for translating IPv4 addresses to IPv6. ' + 'Automatically generated hosts in dual-stack networks ' + 'will get this address. The template ' + 'can contain four tokens: "%(a)d", "%(b)d", ' + '"%(c)d", and "%(d)d", representing the four bytes ' + 'of the IPv4 address, respectively, in decimal notation. ' + 'Moreover you can use any standard printf format ' + 'specification like %(a)02x to get the first byte as two ' + 'hexadecimal digits. Usual choices for mapping ' + '198.51.100.0/24 to 2001:0DB8:1:1::/64 would be ' + '"2001:db8:1:1:%(d)d::" and "2001:db8:1:1:%(d)02x00::".'), + validators=[val_ipv6_template], verbose_name=_('ipv6 template')) dhcp_pool = models.TextField(blank=True, verbose_name=_('DHCP pool'), help_text=_( 'The address range of the DHCP pool: ' @@ -377,6 +391,87 @@ class Vlan(AclBase, models.Model): modified_at = models.DateTimeField(auto_now=True, verbose_name=_('modified at')) + def clean(self): + super(Vlan, self).clean() + if self.ipv6_template: + if not self.network6: + raise ValidationError( + _("You cannot specify an IPv6 template if there is no " + "IPv6 network set.")) + for i in (self.network4[1], self.network4[-1]): + i6 = self.convert_ipv4_to_ipv6(i) + if i6 not in self.network6: + raise ValidationError( + _("%(ip6)s (translated from %(ip4)s) is outside of " + "the IPv6 network.") % {"ip4": i, "ip6": i6}) + if self.network6: + tpl, prefixlen = self._magic_ipv6_template(self.network4, + self.network6) + if not self.ipv6_template: + self.ipv6_template = tpl + if not self.host_ipv6_prefixlen: + self.host_ipv6_prefixlen = prefixlen + + @staticmethod + def _host_bytes(prefixlen, maxbytes): + return int(ceil((maxbytes - prefixlen / 8.0))) + + @staticmethod + def _append_hexa(s, v, lasthalf): + if lasthalf: # can use last half word + assert s[-1] == "0" or s[-1].endswith("00") + if s[-1].endswith("00"): + s[-1] = s[-1][:-2] + s[-1] += "%({})02x".format(v) + s[-1].lstrip("0") + else: + s.append("%({})02x00".format(v)) + + @classmethod + def _magic_ipv6_template(cls, network4, network6, verbose=None): + """Offer a sensible ipv6_template value. + + Based on prefix lengths the method magically selects verbose (decimal) + format: + >>> Vlan._magic_ipv6_template(IPNetwork("198.51.100.0/24"), + ... IPNetwork("2001:0DB8:1:1::/64")) + ('2001:db8:1:1:%(d)d::', 80) + + However you can explicitly select non-verbose, i.e. hexa format: + >>> Vlan._magic_ipv6_template(IPNetwork("198.51.100.0/24"), + ... IPNetwork("2001:0DB8:1:1::/64"), False) + ('2001:db8:1:1:%(d)02x00::', 72) + """ + host4_bytes = cls._host_bytes(network4.prefixlen, 4) + host6_bytes = cls._host_bytes(network6.prefixlen, 16) + if host4_bytes > host6_bytes: + raise ValidationError( + _("IPv6 network is too small to map IPv4 addresses to it.")) + letters = ascii_letters[4-host4_bytes:4] + remove = host6_bytes // 2 + ipstr = network6.network.format(ipv6_full) + s = ipstr.split(":")[0:-remove] + if verbose is None: # use verbose format if net6 much wider + verbose = 2 * (host4_bytes + 1) < host6_bytes + if verbose: + for i in letters: + s.append("%({})d".format(i)) + else: + remain = host6_bytes + for i in letters: + cls._append_hexa(s, i, remain % 2 == 1) + remain -= 1 + if host6_bytes > host4_bytes: + s.append(":") + tpl = ":".join(s) + # compute prefix length + mask = int(IPAddress(tpl % {"a": 1, "b": 1, "c": 1, "d": 1})) + prefixlen = 128 + while mask % 2 == 0: + mask /= 2 + prefixlen -= 1 + return (tpl, prefixlen) + def __unicode__(self): return "%s - %s" % ("managed" if self.managed else "unmanaged", self.name) @@ -402,7 +497,7 @@ class Vlan(AclBase, models.Model): logger.debug("Found unused IPv4 address %s.", ipv4) ipv6 = None if self.network6 is not None: - ipv6 = convert_ipv4_to_ipv6(self.ipv6_template, ipv4) + ipv6 = self.convert_ipv4_to_ipv6(ipv4) if ipv6 in used_v6: continue else: @@ -411,6 +506,20 @@ class Vlan(AclBase, models.Model): else: raise ValidationError(_("All IP addresses are already in use.")) + def convert_ipv4_to_ipv6(self, ipv4): + """Convert IPv4 address string to IPv6 address string.""" + if isinstance(ipv4, basestring): + ipv4 = IPAddress(ipv4, 4) + nums = {ascii_letters[i]: int(ipv4.words[i]) for i in range(4)} + return IPAddress(self.ipv6_template % nums) + + def get_dhcp_clients(self): + macs = set(i.mac for i in self.host_set.all()) + return [{"mac": k, "ip": v["ip"], "hostname": v["hostname"]} + for k, v in chain(*(fw.get_dhcp_clients().iteritems() + for fw in Firewall.objects.all() if fw)) + if v["interface"] == self.name and EUI(k) not in macs] + class VlanGroup(models.Model): """ @@ -581,8 +690,7 @@ class Host(models.Model): def save(self, *args, **kwargs): if not self.id and self.ipv6 == "auto": - self.ipv6 = convert_ipv4_to_ipv6(self.vlan.ipv6_template, - self.ipv4) + self.ipv6 = self.vlan.convert_ipv4_to_ipv6(self.ipv4) self.full_clean() super(Host, self).save(*args, **kwargs) @@ -716,9 +824,6 @@ class Host(models.Model): proto=proto, nat=False, action='accept', host=self, foreign_network=vg) if self.behind_nat: - if public < 1024: - raise ValidationError( - _("Only ports above 1024 can be used.")) rule.nat_external_port = public rule.nat = True rule.full_clean() @@ -838,7 +943,7 @@ class Firewall(models.Model): return self.name @method_cache(30) - def get_remote_queue_name(self, queue_id): + def get_remote_queue_name(self, queue_id="firewall"): """Returns the name of the remote celery queue for this node. Throws Exception if there is no worker on the queue. @@ -851,6 +956,20 @@ class Firewall(models.Model): else: raise WorkerNotFound() + @method_cache(20) + def get_dhcp_clients(self): + try: + return get_dhcp_clients.apply_async( + queue=self.get_remote_queue_name(), expires=60).get(timeout=2) + except TimeoutError: + logger.info("get_dhcp_clients task timed out") + except IOError: + logger.exception("get_dhcp_clients failed. " + "maybe syslog isn't readble by firewall worker") + except: + logger.exception("get_dhcp_clients failed") + return {} + class Domain(models.Model): name = models.CharField(max_length=40, validators=[val_domain], diff --git a/circle/firewall/tasks/remote_tasks.py b/circle/firewall/tasks/remote_tasks.py index 742101d..cf57ba7 100644 --- a/circle/firewall/tasks/remote_tasks.py +++ b/circle/firewall/tasks/remote_tasks.py @@ -62,5 +62,6 @@ def reload_blacklist(data): @celery.task(name='firewall.get_dhcp_clients') -def get_dhcp_clients(data): +def get_dhcp_clients(): + # {'00:21:5a:73:72:cd': {'interface': 'OFF', 'ip': None, 'hostname': None}} pass diff --git a/circle/firewall/tests/test_firewall.py b/circle/firewall/tests/test_firewall.py index 99ced76..3707343 100644 --- a/circle/firewall/tests/test_firewall.py +++ b/circle/firewall/tests/test_firewall.py @@ -78,6 +78,7 @@ class GetNewAddressTestCase(TestCase): self.vlan = Vlan(vid=1, name='test', network4='10.0.0.0/29', network6='2001:738:2001:4031::/80', domain=d, owner=self.u1) + self.vlan.clean() self.vlan.save() self.vlan.host_set.all().delete() for i in [1] + range(3, 6): @@ -85,6 +86,9 @@ class GetNewAddressTestCase(TestCase): ipv4='10.0.0.%d' % i, vlan=self.vlan, owner=self.u1).save() + def tearDown(self): + self.vlan.delete() + def test_new_addr_w_empty_vlan(self): self.vlan.host_set.all().delete() self.vlan.get_new_address() @@ -96,12 +100,6 @@ class GetNewAddressTestCase(TestCase): owner=self.u1).save() self.assertRaises(ValidationError, self.vlan.get_new_address) - def test_all_addr_in_use_w_ipv6(self): - Host(hostname='h-x', mac='01:02:03:04:05:06', - ipv4='10.0.0.6', ipv6='2001:738:2001:4031:0:0:2:0', - vlan=self.vlan, owner=self.u1).save() - self.assertRaises(ValidationError, self.vlan.get_new_address) - def test_new_addr(self): used_v4 = IPSet(self.vlan.host_set.values_list('ipv4', flat=True)) assert self.vlan.get_new_address()['ipv4'] not in used_v4 @@ -313,11 +311,6 @@ class ReloadTestCase(TestCase): new_rules = h.rules.count() self.assertEqual(new_rules, old_rules) - def test_host_add_port_w_validationerror(self): - h = self.h1 - self.assertRaises(ValidationError, h.add_port, - 'tcp', public=1000, private=22) - def test_periodic_task(self): # TODO with patch('firewall.tasks.local_tasks.cache') as cache: diff --git a/circle/locale/hu/LC_MESSAGES/django.po b/circle/locale/hu/LC_MESSAGES/django.po index b8c8759..f8d8d23 100644 --- a/circle/locale/hu/LC_MESSAGES/django.po +++ b/circle/locale/hu/LC_MESSAGES/django.po @@ -6,16 +6,17 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2014-10-20 12:09+0200\n" -"PO-Revision-Date: 2014-10-20 13:01+0200\n" -"Last-Translator: Mate Ory \n" +"POT-Creation-Date: 2014-11-14 13:44+0100\n" +"PO-Revision-Date: 2014-11-14 14:00+0100\n" +"Last-Translator: \n" "Language-Team: Hungarian \n" -"Language: hu\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Language: hu\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Lokalize 1.5\n" +"X-Translated-Using: django-rosetta 0.7.4\n" #: circle/settings/base.py:123 msgid "English" @@ -57,7 +58,7 @@ msgstr "feladat uuid" #: common/models.py:157 #: dashboard/templates/dashboard/instanceactivity_detail.html:37 -#: firewall/models.py:273 vm/models/common.py:84 vm/models/instance.py:131 +#: firewall/models.py:284 vm/models/common.py:84 vm/models/instance.py:131 #: vm/models/instance.py:212 msgid "user" msgstr "felhasználó" @@ -138,10 +139,10 @@ msgid "realtime" msgstr "valós idejű" #: dashboard/forms.py:88 dashboard/forms.py:805 dashboard/forms.py:895 -#: dashboard/forms.py:1196 dashboard/tables.py:225 +#: dashboard/forms.py:1246 dashboard/tables.py:228 #: dashboard/templates/dashboard/_vm-create-2.html:20 #: dashboard/templates/dashboard/vm-list.html:60 -#: dashboard/templates/dashboard/vm-detail/home.html:8 firewall/models.py:285 +#: dashboard/templates/dashboard/vm-detail/home.html:8 firewall/models.py:296 #: network/templates/network/index.html:24 #: network/templates/network/switch-port-edit.html:45 msgid "Name" @@ -204,22 +205,25 @@ msgstr "" msgid "Create" msgstr "Létrehozás" -#: dashboard/forms.py:277 dashboard/forms.py:1116 dashboard/forms.py:1133 -#: dashboard/forms.py:1159 dashboard/forms.py:1209 dashboard/forms.py:1250 -#: dashboard/forms.py:1270 dashboard/forms.py:1299 +#: dashboard/forms.py:277 dashboard/forms.py:1166 dashboard/forms.py:1183 +#: dashboard/forms.py:1209 dashboard/forms.py:1259 dashboard/forms.py:1300 +#: dashboard/forms.py:1320 dashboard/forms.py:1349 #: dashboard/templates/dashboard/_manage_access.html:73 #: dashboard/templates/dashboard/connect-command-create.html:37 #: dashboard/templates/dashboard/connect-command-edit.html:37 -#: dashboard/templates/dashboard/group-detail.html:132 +#: dashboard/templates/dashboard/group-detail.html:140 #: dashboard/templates/dashboard/lease-edit.html:96 +#: dashboard/templates/dashboard/template-tx-owner.html:12 #: dashboard/templates/dashboard/vm-detail/tx-owner.html:12 -#: network/forms.py:82 network/forms.py:103 network/forms.py:139 -#: network/forms.py:164 network/forms.py:203 network/forms.py:224 -#: network/forms.py:273 network/forms.py:295 +#: network/forms.py:82 network/forms.py:103 network/forms.py:143 +#: network/forms.py:168 network/forms.py:207 network/forms.py:228 +#: network/forms.py:279 network/forms.py:304 msgid "Save" msgstr "Mentés" -#: dashboard/forms.py:307 dashboard/templates/dashboard/vm-detail.html:92 +#: dashboard/forms.py:307 dashboard/forms.py:966 +#: dashboard/templates/dashboard/_vm-remove-port.html:15 +#: dashboard/templates/dashboard/vm-detail.html:99 msgid "Host" msgstr "Gép" @@ -286,9 +290,10 @@ msgid "" "service interruption of at most some seconds. Please note that it can take " "very long and cause much network traffic in case of busy machines." msgstr "" -"A live migration lehetővé teszi virtuális gépek csomópontok közti mozgatását " -"legfeljebb néhány másodperces szolgáltatáskimaradással. Vegye figyelembe, " -"hogy ez terhelt gépek esetén sokáig tarthat és nagy hálózati forgalommal jár." +"A live migration lehetővé teszi virtuális gépek csomópontok közti mozgatását" +" legfeljebb néhány másodperces szolgáltatáskimaradással. Vegye figyelembe, " +"hogy ez terhelt gépek esetén sokáig tarthat és nagy hálózati forgalommal " +"jár." #: dashboard/forms.py:782 msgid "Forcibly interrupt all running activities." @@ -350,7 +355,8 @@ msgid "Could not find filename in URL, please specify a name explicitly." msgstr "Az URL-ben nem található fájlnév. Kérem adja meg explicite." #: dashboard/forms.py:917 -#: dashboard/templates/dashboard/node-detail/resources.html:17 +#: dashboard/templates/dashboard/_vm-remove-port.html:17 +#: dashboard/templates/dashboard/node-detail/resources.html:27 msgid "Vlan" msgstr "Vlan" @@ -365,72 +371,86 @@ msgstr "" "A virtuális gép elindítása ezen a csomóponton (üresen hagyva automatikus " "ütemezés)." -#: dashboard/forms.py:956 dashboard/templates/dashboard/profile.html:31 -#: dashboard/templates/dashboard/vm-detail.html:108 +#: dashboard/forms.py:947 dashboard/forms.py:953 +#: dashboard/templates/dashboard/_vm-remove-port.html:13 +msgid "Port" +msgstr "Port" + +#: dashboard/forms.py:956 dashboard/templates/dashboard/vm-detail.html:97 +msgid "Protocol" +msgstr "Protokoll" + +#: dashboard/forms.py:978 +#, python-brace-format +msgid " {0}" +msgstr " {0}" + +#: dashboard/forms.py:1006 dashboard/templates/dashboard/profile.html:31 +#: dashboard/templates/dashboard/vm-detail.html:115 msgid "Username" msgstr "Felhasználónév" -#: dashboard/forms.py:970 dashboard/templates/dashboard/vm-detail.html:110 +#: dashboard/forms.py:1020 dashboard/templates/dashboard/vm-detail.html:117 msgid "Password" msgstr "Jelszó" -#: dashboard/forms.py:975 +#: dashboard/forms.py:1025 msgid "Sign in" msgstr "Bejelentkezés" -#: dashboard/forms.py:998 dashboard/templates/dashboard/profile.html:37 +#: dashboard/forms.py:1048 dashboard/templates/dashboard/profile.html:37 msgid "Email address" msgstr "E-mail cím" -#: dashboard/forms.py:1003 +#: dashboard/forms.py:1053 msgid "Reset password" msgstr "Új jelszó" -#: dashboard/forms.py:1019 dashboard/forms.py:1142 +#: dashboard/forms.py:1069 dashboard/forms.py:1192 msgid "Change password" msgstr "Jelszóváltoztatás" -#: dashboard/forms.py:1091 +#: dashboard/forms.py:1141 msgid "Add trait" msgstr "Jellemző hozzáadása" -#: dashboard/forms.py:1173 dashboard/templates/dashboard/lease-edit.html:86 +#: dashboard/forms.py:1223 dashboard/templates/dashboard/lease-edit.html:86 msgid "Name of group or user" msgstr "Csoport vagy felhasználó neve" -#: dashboard/forms.py:1181 dashboard/forms.py:1190 +#: dashboard/forms.py:1231 dashboard/forms.py:1240 msgid "Name of user" msgstr "Felhasználó neve" -#: dashboard/forms.py:1183 dashboard/forms.py:1192 +#: dashboard/forms.py:1233 dashboard/forms.py:1242 msgid "E-mail address or identifier of user" msgstr "A felhasználó e-mail címe vagy azonosítója" -#: dashboard/forms.py:1198 +#: dashboard/forms.py:1248 msgid "Key" msgstr "Kulcs" -#: dashboard/forms.py:1199 +#: dashboard/forms.py:1249 msgid "For example: ssh-rsa AAAAB3NzaC1yc2ED..." msgstr "Például: ssh-rsa AAAAB3NzaC1yc2ED…" -#: dashboard/forms.py:1285 +#: dashboard/forms.py:1335 msgid "permissions" msgstr "jogosultságok" -#: dashboard/forms.py:1342 +#: dashboard/forms.py:1392 msgid "owned" msgstr "saját" -#: dashboard/forms.py:1343 +#: dashboard/forms.py:1393 msgid "shared" msgstr "osztott" -#: dashboard/forms.py:1344 +#: dashboard/forms.py:1394 msgid "all" msgstr "összes" -#: dashboard/forms.py:1351 dashboard/forms.py:1375 +#: dashboard/forms.py:1401 dashboard/forms.py:1425 #: dashboard/templates/dashboard/index-groups.html:21 #: dashboard/templates/dashboard/index-nodes.html:61 #: dashboard/templates/dashboard/index-vm.html:57 @@ -438,7 +458,7 @@ msgid "Search..." msgstr "Keresés..." #: dashboard/models.py:65 dashboard/templates/dashboard/index-groups.html:39 -#: dashboard/templates/dashboard/index-nodes.html:78 +#: dashboard/templates/dashboard/index-nodes.html:79 #: dashboard/templates/dashboard/index-templates.html:38 #: dashboard/templates/dashboard/index-vm.html:76 #: dashboard/templates/dashboard/store/_list-box.html:101 @@ -461,8 +481,8 @@ msgstr "elérés módja" msgid "Type of the remote access method." msgstr "Távoli elérési mód típusa." -#: dashboard/models.py:110 firewall/models.py:413 firewall/models.py:440 -#: firewall/models.py:828 firewall/models.py:850 firewall/models.py:871 +#: dashboard/models.py:110 firewall/models.py:529 firewall/models.py:556 +#: firewall/models.py:943 firewall/models.py:979 firewall/models.py:1000 #: storage/models.py:47 storage/models.py:86 vm/models/common.py:65 #: vm/models/common.py:89 vm/models/common.py:165 vm/models/instance.py:135 #: vm/models/instance.py:225 vm/models/node.py:65 @@ -529,14 +549,14 @@ msgstr "Lemezkvóta mebibyte-okban." msgid "Can use autocomplete." msgstr "Használhat automatikus kiegészítést." -#: dashboard/models.py:229 firewall/models.py:274 vm/models/common.py:85 +#: dashboard/models.py:229 firewall/models.py:285 vm/models/common.py:85 #: vm/models/instance.py:132 vm/models/instance.py:213 msgid "operator" msgstr "operátor" -#: dashboard/models.py:230 firewall/models.py:100 firewall/models.py:369 -#: firewall/models.py:422 firewall/models.py:445 firewall/models.py:510 -#: firewall/models.py:851 firewall/models.py:880 vm/models/common.py:86 +#: dashboard/models.py:230 firewall/models.py:104 firewall/models.py:390 +#: firewall/models.py:538 firewall/models.py:561 firewall/models.py:626 +#: firewall/models.py:980 firewall/models.py:1009 vm/models/common.py:86 #: vm/models/instance.py:133 vm/models/instance.py:214 msgid "owner" msgstr "tulajdonos" @@ -561,57 +581,66 @@ msgstr "VM-ek száma" msgid "Monitor" msgstr "Állapot" -#: dashboard/tables.py:145 dashboard/templates/dashboard/_vm-create-2.html:38 -#: dashboard/templates/dashboard/node-detail.html:69 -#: dashboard/templates/dashboard/vm-detail.html:177 +#: dashboard/tables.py:91 +msgid "Number of users" +msgstr "Felhasználók száma" + +#: dashboard/tables.py:98 dashboard/templates/dashboard/base.html:48 +msgid "Admin" +msgstr "Adminisztráció" + +#: dashboard/tables.py:105 dashboard/tables.py:178 dashboard/tables.py:209 +#: dashboard/tables.py:243 dashboard/tables.py:272 +msgid "Actions" +msgstr "Műveletek" + +#: dashboard/tables.py:148 dashboard/templates/dashboard/_vm-create-2.html:38 +#: dashboard/templates/dashboard/node-detail.html:71 +#: dashboard/templates/dashboard/vm-detail.html:191 msgid "Resources" msgstr "Erőforrások" -#: dashboard/tables.py:151 dashboard/templates/dashboard/vm-list.html:72 +#: dashboard/tables.py:154 dashboard/templates/dashboard/vm-list.html:72 #: vm/models/instance.py:104 msgid "Lease" msgstr "Bérlet" -#: dashboard/tables.py:162 dashboard/templates/dashboard/vm-list.html:68 +#: dashboard/tables.py:165 dashboard/templates/dashboard/template-edit.html:84 +#: dashboard/templates/dashboard/vm-list.html:68 #: dashboard/templates/dashboard/vm-detail/access.html:2 msgid "Owner" msgstr "Tulajdonos" -#: dashboard/tables.py:167 dashboard/tables.py:235 +#: dashboard/tables.py:170 dashboard/tables.py:238 msgid "Created at" msgstr "Létrehozva" -#: dashboard/tables.py:171 +#: dashboard/tables.py:174 msgid "Running" msgstr "Fut" -#: dashboard/tables.py:175 dashboard/tables.py:206 dashboard/tables.py:240 -#: dashboard/tables.py:269 -msgid "Actions" -msgstr "Műveletek" - -#: dashboard/tables.py:218 +#: dashboard/tables.py:221 msgid "No available leases." msgstr "Nincs elérhető bérlési mód." -#: dashboard/tables.py:230 +#: dashboard/tables.py:233 msgid "Fingerprint" msgstr "Ujjlenyomat" -#: dashboard/tables.py:251 +#: dashboard/tables.py:254 msgid "You haven't added any public keys yet." msgstr "Még nem adott meg publikus kulcsot." -#: dashboard/tables.py:261 +#: dashboard/tables.py:264 msgid "Access method" msgstr "Elérés módja" -#: dashboard/tables.py:265 +#: dashboard/tables.py:268 #: dashboard/templates/dashboard/vm-detail/home.html:129 msgid "Template" msgstr "Sablon" -#: dashboard/tables.py:282 +#: dashboard/tables.py:285 msgid "" "You don't have any custom connection commands yet. You can specify commands " "to be displayed on VM detail pages instead of the defaults." @@ -641,7 +670,7 @@ msgid "Policy" msgstr "Szabályzat" #: dashboard/templates/base.html:64 -#: dashboard/templates/dashboard/group-detail.html:13 +#: dashboard/templates/dashboard/group-detail.html:18 #: templates/info/help.html:4 templates/info/help.html.py:9 msgid "Help" msgstr "Súgó" @@ -658,40 +687,29 @@ msgstr "Megerősítés" #: dashboard/templates/dashboard/_client-check.html:4 msgid "" "\n" -" To effortlessly connect to all kind of virtual machines you have to " -"install the CIRCLE Client.\n" +" To effortlessly connect to all kind of virtual machines you have to install the CIRCLE Client.\n" " " msgstr "" "\n" -" A virtuális gépekhez való könnyű csatlakozáshoz telepítse a " -"CIRCLE klienst.\n" +" A virtuális gépekhez való könnyű csatlakozáshoz telepítse a CIRCLE klienst.\n" " " #: dashboard/templates/dashboard/_client-check.html:9 msgid "" "\n" -" To install the CIRCLE Client click on the " -"Download the Client button. \n" -" The button takes you to the installation detail page, where you can " -"choose your operating system and start \n" -" the download or read more detailed information about the Client. The program can be installed on Windows XP (and above)\n" -" or Debian based Linux operating systems. To successfully install the " -"client you have to have admin (root or elevated) rights.\n" -" After the installation complete clicking on the I have the " -"Client installed button will launch the appropriate tool\n" -" designed for that connection with necessarily predefined configurations. " -"This option will also save your answer and this prompt about\n" +" To install the CIRCLE Client click on the Download the Client button. \n" +" The button takes you to the installation detail page, where you can choose your operating system and start \n" +" the download or read more detailed information about the Client. The program can be installed on Windows XP (and above)\n" +" or Debian based Linux operating systems. To successfully install the client you have to have admin (root or elevated) rights.\n" +" After the installation complete clicking on the I have the Client installed button will launch the appropriate tool\n" +" designed for that connection with necessarily predefined configurations. This option will also save your answer and this prompt about\n" " installation will not pop up again.\n" " " msgstr "" "\n" -" A CIRCLE kliens letöltéséhez kattintson a " -"Kliens letöltése gombra. \n" -" A gomb a letöltőoldalra visz, ahol kiválaszthatja a megfelelő " -"kliens telepítőcsomagot.\n" -" A telepítés után kattintson a Már telepítve van gombra " -"a megfelelő eszköz indításához. Ezt a választást a rendszer megjegyzi.\n" +" A CIRCLE kliens letöltéséhez kattintson a Kliens letöltése gombra. \n" +" A gomb a letöltőoldalra visz, ahol kiválaszthatja a megfelelő kliens telepítőcsomagot.\n" +" A telepítés után kattintson a Már telepítve van gombra a megfelelő eszköz indításához. Ezt a választást a rendszer megjegyzi.\n" " " #: dashboard/templates/dashboard/_client-check.html:23 @@ -724,11 +742,11 @@ msgstr "Már telepítve van" #: dashboard/templates/dashboard/_disk-list-element.html:12 #: dashboard/templates/dashboard/_manage_access.html:34 #: dashboard/templates/dashboard/_manage_access.html:56 -#: dashboard/templates/dashboard/group-detail.html:93 +#: dashboard/templates/dashboard/group-detail.html:99 #: dashboard/templates/dashboard/lease-edit.html:60 #: dashboard/templates/dashboard/lease-edit.html:80 -#: dashboard/templates/dashboard/template-edit.html:107 -#: dashboard/templates/dashboard/template-edit.html:108 +#: dashboard/templates/dashboard/template-edit.html:127 +#: dashboard/templates/dashboard/template-edit.html:128 #: dashboard/templates/dashboard/confirm/base-remove.html:12 #: dashboard/templates/dashboard/store/_list-box.html:133 #: dashboard/templates/dashboard/store/remove.html:36 @@ -751,7 +769,7 @@ msgid "username" msgstr "felhasználónév" #: dashboard/templates/dashboard/_manage_access.html:7 -#: dashboard/templates/dashboard/group-detail.html:93 +#: dashboard/templates/dashboard/group-detail.html:99 #: dashboard/templates/dashboard/lease-edit.html:35 msgid "Who" msgstr "Ki" @@ -797,7 +815,8 @@ msgstr "RAM-méret mebibyte-okban." #: dashboard/templates/dashboard/_template-choose.html:5 msgid "Customize an existing template or create a brand new one from scratch." -msgstr "Szabjon testre egy meglévő sablont, vagy készítsen egyet az alapoktól." +msgstr "" +"Szabjon testre egy meglévő sablont, vagy készítsen egyet az alapoktól." #: dashboard/templates/dashboard/_template-choose.html:7 msgid "Customize an existing template." @@ -859,9 +878,9 @@ msgstr "Lemezek" #: dashboard/templates/dashboard/_vm-create-1.html:40 #: dashboard/templates/dashboard/_vm-create-2.html:65 -#: dashboard/templates/dashboard/base.html:46 -#: dashboard/templates/dashboard/vm-detail.html:191 -#: dashboard/views/graph.py:192 dashboard/views/graph.py:215 +#: dashboard/templates/dashboard/base.html:47 +#: dashboard/templates/dashboard/vm-detail.html:205 +#: dashboard/views/graph.py:198 dashboard/views/graph.py:221 #: network/forms.py:123 network/templates/network/base.html:7 msgid "Network" msgstr "Hálózat" @@ -907,7 +926,8 @@ msgstr "Újraütemezés" #: dashboard/templates/dashboard/_vm-mass-migrate.html:17 msgid "This option will reschedule each virtual machine to the optimal node." -msgstr "Ez a lehetőség minden virtuális gépet az optimális csomópontra migrál." +msgstr "" +"Ez a lehetőség minden virtuális gépet az optimális csomópontra migrál." #: dashboard/templates/dashboard/_vm-mass-migrate.html:29 #: dashboard/templates/dashboard/_vm-migrate.html:31 @@ -948,28 +968,24 @@ msgstr "" msgid "Name of template" msgstr "Sablon neve" -#: dashboard/templates/dashboard/base.html:26 +#: dashboard/templates/dashboard/base.html:27 #: dashboard/templates/dashboard/notifications.html:9 msgid "Notifications" msgstr "Értesítések" -#: dashboard/templates/dashboard/base.html:32 +#: dashboard/templates/dashboard/base.html:33 msgid "Loading..." msgstr "Betöltés..." -#: dashboard/templates/dashboard/base.html:38 +#: dashboard/templates/dashboard/base.html:39 msgid "Log out" msgstr "Kijelentkezés" -#: dashboard/templates/dashboard/base.html:40 +#: dashboard/templates/dashboard/base.html:41 msgid "User profile" msgstr "Felhasználói profil" -#: dashboard/templates/dashboard/base.html:47 -msgid "Admin" -msgstr "Adminisztráció" - -#: dashboard/templates/dashboard/base.html:50 +#: dashboard/templates/dashboard/base.html:51 msgid "Log in " msgstr "Bejelentkezés" @@ -988,8 +1004,8 @@ msgstr "Parancssablon létrehozása" #: dashboard/templates/dashboard/confirm/base-renew.html:26 #: dashboard/templates/dashboard/confirm/node-flush.html:26 #: network/forms.py:61 network/forms.py:83 network/forms.py:104 -#: network/forms.py:140 network/forms.py:165 network/forms.py:204 -#: network/forms.py:225 network/forms.py:274 network/forms.py:296 +#: network/forms.py:144 network/forms.py:169 network/forms.py:208 +#: network/forms.py:229 network/forms.py:280 network/forms.py:305 msgid "Back" msgstr "Vissza" @@ -1015,15 +1031,15 @@ msgstr "" "A felhasználói csoportok lehetővé teszik sablonok és más erőforrások " "együttes megosztását több felhasználóval." -#: dashboard/templates/dashboard/group-detail.html:5 +#: dashboard/templates/dashboard/group-detail.html:6 msgid "group" msgstr "csoport" -#: dashboard/templates/dashboard/group-detail.html:11 -#: dashboard/templates/dashboard/group-detail.html:20 -#: dashboard/templates/dashboard/group-detail.html:33 -#: dashboard/templates/dashboard/node-detail.html:13 -#: dashboard/templates/dashboard/node-detail.html:21 +#: dashboard/templates/dashboard/group-detail.html:12 +#: dashboard/templates/dashboard/group-detail.html:27 +#: dashboard/templates/dashboard/group-detail.html:40 +#: dashboard/templates/dashboard/node-detail.html:14 +#: dashboard/templates/dashboard/node-detail.html:23 #: dashboard/templates/dashboard/vm-detail.html:63 #: dashboard/templates/dashboard/group-list/column-name.html:7 #: dashboard/templates/dashboard/node-list/column-name.html:7 @@ -1032,9 +1048,9 @@ msgstr "csoport" msgid "Rename" msgstr "Átnevezés" -#: dashboard/templates/dashboard/group-detail.html:12 -#: dashboard/templates/dashboard/group-detail.html:37 -#: dashboard/templates/dashboard/node-detail.html:14 +#: dashboard/templates/dashboard/group-detail.html:15 +#: dashboard/templates/dashboard/group-detail.html:44 +#: dashboard/templates/dashboard/node-detail.html:15 #: dashboard/templates/dashboard/template-edit.html:75 #: dashboard/templates/dashboard/confirm/ajax-delete.html:18 #: dashboard/templates/dashboard/confirm/mass-delete.html:12 @@ -1045,41 +1061,41 @@ msgstr "Átnevezés" msgid "Delete" msgstr "Törlés" -#: dashboard/templates/dashboard/group-detail.html:34 +#: dashboard/templates/dashboard/group-detail.html:41 msgid "Change the name of the group." msgstr "Válasszon csoportnevet." -#: dashboard/templates/dashboard/group-detail.html:38 +#: dashboard/templates/dashboard/group-detail.html:45 msgid "Delete group." msgstr "Csoport törlése." -#: dashboard/templates/dashboard/group-detail.html:55 +#: dashboard/templates/dashboard/group-detail.html:59 msgid "Available objects for this group" msgstr "Csoport számára elérhető objektumok" -#: dashboard/templates/dashboard/group-detail.html:85 +#: dashboard/templates/dashboard/group-detail.html:89 msgid "User list" msgstr "Felhasználók" -#: dashboard/templates/dashboard/group-detail.html:87 +#: dashboard/templates/dashboard/group-detail.html:92 msgid "Create user" msgstr "Új felhasználó" -#: dashboard/templates/dashboard/group-detail.html:104 -#: dashboard/templates/dashboard/group-detail.html:117 +#: dashboard/templates/dashboard/group-detail.html:111 +#: dashboard/templates/dashboard/group-detail.html:125 #: dashboard/templates/dashboard/vm-detail/network.html:28 msgid "remove" msgstr "eltávolítás" -#: dashboard/templates/dashboard/group-detail.html:130 +#: dashboard/templates/dashboard/group-detail.html:138 msgid "Add multiple users at once (one identifier per line)." msgstr "Több felhasználó hozzáadása (egy azonosító soronként)." -#: dashboard/templates/dashboard/group-detail.html:137 +#: dashboard/templates/dashboard/group-detail.html:144 msgid "Access permissions" msgstr "Hozzáférési jogosultságok" -#: dashboard/templates/dashboard/group-detail.html:146 +#: dashboard/templates/dashboard/group-detail.html:154 msgid "Group permissions" msgstr "Csoportjogosultságok" @@ -1087,6 +1103,14 @@ msgstr "Csoportjogosultságok" msgid "Group list" msgstr "Csoportok" +#: dashboard/templates/dashboard/group-list.html:13 +#: dashboard/templates/dashboard/index-groups.html:7 +#: dashboard/templates/dashboard/profile.html:56 +#: dashboard/templates/dashboard/vm-detail/network.html:39 +#: network/templates/network/host-edit.html:32 templates/info/help.html:192 +msgid "Groups" +msgstr "Csoportok" + #: dashboard/templates/dashboard/groupprofile_form.html:10 msgid "Update group" msgstr "Csoport frissítése" @@ -1095,13 +1119,6 @@ msgstr "Csoport frissítése" msgid "List of groups that you have access to." msgstr "Azon csoportok, amelyekhez hozzáférése van." -#: dashboard/templates/dashboard/index-groups.html:7 -#: dashboard/templates/dashboard/profile.html:56 -#: dashboard/templates/dashboard/vm-detail/network.html:39 -#: network/templates/network/host-edit.html:32 templates/info/help.html:192 -msgid "Groups" -msgstr "Csoportok" - #: dashboard/templates/dashboard/index-groups.html:30 #, python-format msgid "" @@ -1132,8 +1149,8 @@ msgid "" "List of compute nodes, also called worker nodes or hypervisors, which run " "the virtual machines." msgstr "" -"A virtuális gépeket futtató számítási csomópontok (más néven worker node-ok, " -"hypervisorok) listája." +"A virtuális gépeket futtató számítási csomópontok (más néven worker node-ok," +" hypervisorok) listája." #: dashboard/templates/dashboard/index-nodes.html:16 #: dashboard/templates/dashboard/node-list.html:5 @@ -1200,10 +1217,12 @@ msgid "Virtual machines" msgstr "Virtuális gépek" #: dashboard/templates/dashboard/index-vm.html:34 +#: dashboard/templates/dashboard/vm-detail.html:75 msgid "Unfavourite" msgstr "Kedvencnek jelölés törlése" #: dashboard/templates/dashboard/index-vm.html:36 +#: dashboard/templates/dashboard/vm-detail.html:77 msgid "Mark as favorite" msgstr "Kedvencnek jelölés" @@ -1265,13 +1284,18 @@ msgstr "%(count)s leállítva" msgid "Index" msgstr "Kezdőoldal" -#: dashboard/templates/dashboard/index.html:16 +#: dashboard/templates/dashboard/index.html:10 +#, python-format +msgid "%(name)s virtual machines" +msgstr "%(name)s virtuális gépek" + +#: dashboard/templates/dashboard/index.html:23 msgid "You have no permission to start or manage virtual machines." msgstr "Nincs jogosultsága virtuális gépek indítására vagy kezelésére." #: dashboard/templates/dashboard/instanceactivity_detail.html:25 -#: dashboard/templates/dashboard/node-detail.html:82 -#: dashboard/templates/dashboard/vm-detail.html:196 +#: dashboard/templates/dashboard/node-detail.html:84 +#: dashboard/templates/dashboard/vm-detail.html:210 #: dashboard/templates/dashboard/node-detail/activity.html:3 #: dashboard/templates/dashboard/vm-detail/activity.html:3 msgid "Activity" @@ -1287,7 +1311,7 @@ msgid "time" msgstr "idő" #: dashboard/templates/dashboard/instanceactivity_detail.html:40 -#: firewall/models.py:876 firewall/models.py:1002 +#: firewall/models.py:1005 firewall/models.py:1131 msgid "type" msgstr "típus" @@ -1343,8 +1367,8 @@ msgid "Edit lease" msgstr "Bérlési mód szerkesztése" #: dashboard/templates/dashboard/lease-edit.html:27 -#: dashboard/templates/dashboard/template-edit.html:84 -#: network/templates/network/vlan-edit.html:26 +#: dashboard/templates/dashboard/template-edit.html:104 +#: network/templates/network/vlan-edit.html:33 msgid "Manage access" msgstr "Jogosultságok kezelése" @@ -1352,56 +1376,52 @@ msgstr "Jogosultságok kezelése" #, python-format msgid "" "\n" -"Do you want to perform the %(op)s operation on the " -"following instance?\n" +"Do you want to perform the %(op)s operation on the following instance?\n" msgid_plural "" "\n" -"Do you want to perform the %(op)s operation on the " -"following %(count)s instances?\n" +"Do you want to perform the %(op)s operation on the following %(count)s instances?\n" msgstr[0] "" "\n" -"Biztosan végrehajtja a(z) %(op)s műveletet a következő " -"példányon?\n" +"Biztosan végrehajtja a(z) %(op)s műveletet a következő példányon?\n" msgstr[1] "" "\n" -"Biztosan végrehajtja a(z) %(op)s műveletet a következő " -"%(count)s példányon?\n" +"Biztosan végrehajtja a(z) %(op)s műveletet a következő %(count)s példányon?\n" #: dashboard/templates/dashboard/node-add-trait.html:19 msgid "Add Trait" msgstr "Jellemző hozzáadása" -#: dashboard/templates/dashboard/node-detail.html:41 +#: dashboard/templates/dashboard/node-detail.html:43 #: dashboard/templates/dashboard/node-detail/resources.html:10 msgid "Enabled" msgstr "Engedélyezve" -#: dashboard/templates/dashboard/node-detail.html:43 +#: dashboard/templates/dashboard/node-detail.html:45 msgid "Schedule enabled" msgstr "Ütemezés engedélyezve" -#: dashboard/templates/dashboard/node-detail.html:45 +#: dashboard/templates/dashboard/node-detail.html:47 msgid "Schedule disabled" msgstr "Ütemezés tiltva" -#: dashboard/templates/dashboard/node-detail.html:48 +#: dashboard/templates/dashboard/node-detail.html:50 msgid "Disabled" msgstr "Tiltás" -#: dashboard/templates/dashboard/node-detail.html:51 +#: dashboard/templates/dashboard/node-detail.html:53 msgid "Online" msgstr "Elérhető" -#: dashboard/templates/dashboard/node-detail.html:53 +#: dashboard/templates/dashboard/node-detail.html:55 msgid "Offline" msgstr "Offline" -#: dashboard/templates/dashboard/node-detail.html:63 -#: dashboard/templates/dashboard/vm-detail.html:172 +#: dashboard/templates/dashboard/node-detail.html:65 +#: dashboard/templates/dashboard/vm-detail.html:186 msgid "Home" msgstr "Kezdőoldal" -#: dashboard/templates/dashboard/node-detail.html:76 +#: dashboard/templates/dashboard/node-detail.html:78 msgid "Virtual Machines" msgstr "Virtuális gépek" @@ -1418,8 +1438,7 @@ msgstr "Grafikonok" msgid "" "\n" "Do you want to perform the following operation on\n" -"
%(obj)s: %(op)s?\n" +"%(obj)s: %(op)s?\n" msgstr "" "\n" "Biztosan végrehajtja a(z) %(op)s műveletet\n" @@ -1537,11 +1556,30 @@ msgstr "Szülősablon" msgid "Delete template" msgstr "Sablon törlése" -#: dashboard/templates/dashboard/template-edit.html:94 +#: dashboard/templates/dashboard/template-edit.html:88 +msgid "You are the current owner of this template." +msgstr "Ön a jelenlegi tulajdonosa a sablonnak." + +#: dashboard/templates/dashboard/template-edit.html:91 +#, python-format +msgid "" +"\n" +" The current owner of this template is %(name)s (%(owner)s).\n" +" " +msgstr "" +"\n" +"A sablon jelenlegi tulajdonosa %(name)s (%(owner)s)." + +#: dashboard/templates/dashboard/template-edit.html:97 +#: dashboard/templates/dashboard/vm-detail/access.html:15 +msgid "Transfer ownership..." +msgstr "Tulajdon átruházása..." + +#: dashboard/templates/dashboard/template-edit.html:114 msgid "Disk list" msgstr "Lemezek" -#: dashboard/templates/dashboard/template-edit.html:99 +#: dashboard/templates/dashboard/template-edit.html:119 msgid "No disks are added!" msgstr "Egy lemez sincs hozzáadva!" @@ -1628,78 +1666,78 @@ msgstr "Kattintson a Mentés sablonként gombra" msgid "Delete this virtual machine (optional)" msgstr "Törölje a virtális gépet (ha szükséges)" -#: dashboard/templates/dashboard/vm-detail.html:88 +#: dashboard/templates/dashboard/vm-detail.html:95 msgid "Connection details" msgstr "Kapcsolat részletei" -#: dashboard/templates/dashboard/vm-detail.html:90 -msgid "Protocol" -msgstr "Protokoll" - -#: dashboard/templates/dashboard/vm-detail.html:97 +#: dashboard/templates/dashboard/vm-detail.html:104 msgid "The VM doesn't have any network interface." msgstr "A VM-nek nincs hálózati interfésze." -#: dashboard/templates/dashboard/vm-detail.html:99 +#: dashboard/templates/dashboard/vm-detail.html:106 msgid "The required port for this protocol is not forwarded." msgstr "A csatlakozáshoz szükséges port nincs továbbítva." -#: dashboard/templates/dashboard/vm-detail.html:104 +#: dashboard/templates/dashboard/vm-detail.html:111 msgid "Host (IPv6)" msgstr "Gép (IPv6)" -#: dashboard/templates/dashboard/vm-detail.html:116 +#: dashboard/templates/dashboard/vm-detail.html:123 msgid "Show password" msgstr "Jelszó megjelenítése" -#: dashboard/templates/dashboard/vm-detail.html:124 +#: dashboard/templates/dashboard/vm-detail.html:135 msgid "Start the VM to change the password." msgstr "Jelszóváltoztatáshoz el kell indítani a gépet." -#: dashboard/templates/dashboard/vm-detail.html:124 +#: dashboard/templates/dashboard/vm-detail.html:135 +msgid "This machine has no agent installed." +msgstr "A gépre nincs ügynök telepítve." + +#: dashboard/templates/dashboard/vm-detail.html:137 msgid "Generate new password!" msgstr "Új jelszó generálása" -#: dashboard/templates/dashboard/vm-detail.html:131 -#: dashboard/templates/dashboard/vm-detail.html:143 +#: dashboard/templates/dashboard/vm-detail.html:145 +#: dashboard/templates/dashboard/vm-detail.html:157 msgid "Command" msgstr "Parancs" -#: dashboard/templates/dashboard/vm-detail.html:136 -#: dashboard/templates/dashboard/vm-detail.html:147 +#: dashboard/templates/dashboard/vm-detail.html:150 +#: dashboard/templates/dashboard/vm-detail.html:161 #: dashboard/templates/dashboard/vm-list.html:22 msgid "Select all" msgstr "Összes kiválasztása" -#: dashboard/templates/dashboard/vm-detail.html:144 +#: dashboard/templates/dashboard/vm-detail.html:158 msgid "Connection is not possible." msgstr "A csatlakozás nem lehetséges." -#: dashboard/templates/dashboard/vm-detail.html:154 +#: dashboard/templates/dashboard/vm-detail.html:168 msgid "Connect via the CIRCLE Client" msgstr "Csatlakozás CIRCLE klienssel" -#: dashboard/templates/dashboard/vm-detail.html:155 +#: dashboard/templates/dashboard/vm-detail.html:169 msgid "Connect" msgstr "Csatlakozás" -#: dashboard/templates/dashboard/vm-detail.html:157 +#: dashboard/templates/dashboard/vm-detail.html:171 msgid "Download client" msgstr "Kliens letöltése" -#: dashboard/templates/dashboard/vm-detail.html:159 +#: dashboard/templates/dashboard/vm-detail.html:173 msgid "Download the CIRCLE Client" msgstr "A CIRCLE kliens letöltése" -#: dashboard/templates/dashboard/vm-detail.html:160 +#: dashboard/templates/dashboard/vm-detail.html:174 msgid "Connect (download client)" msgstr "Csatlakozás (kliens letöltése)" -#: dashboard/templates/dashboard/vm-detail.html:182 +#: dashboard/templates/dashboard/vm-detail.html:196 msgid "Console" msgstr "Konzol" -#: dashboard/templates/dashboard/vm-detail.html:186 +#: dashboard/templates/dashboard/vm-detail.html:200 msgid "Access" msgstr "Hozzáférés" @@ -1733,8 +1771,8 @@ msgstr "Nincs eredmény." #: dashboard/templates/dashboard/vm-list.html:152 msgid "" -"You can select multiple vm instances while holding down the CTRL key." +"You can select multiple vm instances while holding down the " +"CTRL key." msgstr "" "Több virtuális gépet is kiválaszthat a CTRL billentyű " "lenyomásával." @@ -1744,8 +1782,8 @@ msgid "" "If you want to select multiple instances by one click select an instance " "then hold down SHIFT key and select another one!" msgstr "" -"Ha több egymást követő példányt szeretne kiválasztani, válassza ki az elsőt, " -"majd a SHIFT billentyűt lenyomva tartva az utolsót." +"Ha több egymást követő példányt szeretne kiválasztani, válassza ki az elsőt," +" majd a SHIFT billentyűt lenyomva tartva az utolsót." #: dashboard/templates/dashboard/confirm/ajax-delete.html:9 #, python-format @@ -1763,13 +1801,11 @@ msgstr "" #, python-format msgid "" "\n" -" Are you sure you want to change %(object)s " -"status?\n" +" Are you sure you want to change %(object)s status?\n" " " msgstr "" "\n" -" Biztosan megváltoztatja a következő állapotát: " -"%(object)s?\n" +" Biztosan megváltoztatja a következő állapotát: %(object)s?\n" " " #: dashboard/templates/dashboard/confirm/ajax-node-status.html:19 @@ -1782,13 +1818,11 @@ msgstr "Igen, %(status)s" #, python-format msgid "" "\n" -"\t Are you sure you want to remove %(member)s from " -"%(object)s?\n" +" Are you sure you want to remove %(member)s from %(object)s?\n" " " msgstr "" "\n" -"\t Biztosan eltávolítja a(z) %(member)s tagot a " -"következőből: %(object)s?\n" +"Biztosan eltávolítja a(z) %(member)s tagot a következőből: %(object)s?\n" " " #: dashboard/templates/dashboard/confirm/base-delete.html:12 @@ -1807,8 +1841,9 @@ msgstr "" " " #: dashboard/templates/dashboard/confirm/base-delete.html:31 -#: dashboard/templates/dashboard/confirm/base-transfer-ownership.html:23 #: dashboard/templates/dashboard/confirm/node-flush.html:28 +#: dashboard/templates/dashboard/confirm/transfer-instance-ownership.html:23 +#: dashboard/templates/dashboard/confirm/transfer-template-ownership.html:23 msgid "Yes" msgstr "Igen" @@ -1853,37 +1888,13 @@ msgid "" msgstr "" "\n" " A példány felfüggesztése %(suspend)s időpontban,\n" -" törlése %(delete)s időpontban történik, ha most " -"megújítja.\n" +" törlése %(delete)s időpontban történik, ha most megújítja.\n" " " #: dashboard/templates/dashboard/confirm/base-renew.html:27 msgid "Renew" msgstr "Megújítás" -#: dashboard/templates/dashboard/confirm/base-transfer-ownership.html:9 -msgid "Ownership transfer" -msgstr "Átruházás" - -#: dashboard/templates/dashboard/confirm/base-transfer-ownership.html:13 -#, python-format -msgid "" -"\n" -" %(owner)s offered to take the ownership of\n" -" virtual machine %(name)s (%(id)s).\n" -" Do you accept the responsility of being the host's owner?\n" -" " -msgstr "" -"\n" -" %(owner)s kezdeményezte a(z) %(name)s\n" -" (%(id)s) virtuális gép átruházását.\n" -" Elfogadja a gép birtoklásával járó felelősséget?\n" -" " - -#: dashboard/templates/dashboard/confirm/base-transfer-ownership.html:21 -msgid "No" -msgstr "Nem" - #: dashboard/templates/dashboard/confirm/mass-delete.html:6 msgid "Are you sure you want to delete the following objects?" msgstr "Biztosan törli a következő objektumokat?" @@ -1903,6 +1914,42 @@ msgstr "" msgid "Status changing confirmation" msgstr "Állapotváltozás megerősítése" +#: dashboard/templates/dashboard/confirm/transfer-instance-ownership.html:9 +#: dashboard/templates/dashboard/confirm/transfer-template-ownership.html:9 +msgid "Ownership transfer" +msgstr "Átruházás" + +#: dashboard/templates/dashboard/confirm/transfer-instance-ownership.html:13 +#, python-format +msgid "" +"\n" +" %(owner)s offered to take the ownership of\n" +" virtual machine %(name)s (%(id)s).\n" +" Do you accept the responsility of being the host's owner?\n" +" " +msgstr "" +"\n" +"%(owner)s kezdeményezte a(z) %(name)s (%(id)s) virtuális gép átruházását.\n" +"Elfogadja a gép birtoklásával járó felelősséget?" + +#: dashboard/templates/dashboard/confirm/transfer-instance-ownership.html:21 +#: dashboard/templates/dashboard/confirm/transfer-template-ownership.html:21 +msgid "No" +msgstr "Nem" + +#: dashboard/templates/dashboard/confirm/transfer-template-ownership.html:13 +#, python-format +msgid "" +"\n" +" %(owner)s offered to take the ownership of\n" +" template %(name)s (%(id)s).\n" +" Do you accept the responsility of being the template's owner?\n" +" " +msgstr "" +"\n" +"%(owner)s kezdeményezte a(z) %(name)s (%(id)s) sablon átruházását.\n" +"Elfogadja a sablon birtoklásával járó felelősséget?" + #: dashboard/templates/dashboard/connect-command-list/column-command-actions.html:2 #: dashboard/templates/dashboard/template-list/column-lease-actions.html:2 #: dashboard/templates/dashboard/template-list/column-template-actions.html:6 @@ -1952,14 +1999,22 @@ msgid "Priority" msgstr "Prioritás" #: dashboard/templates/dashboard/node-detail/resources.html:13 +msgid "Driver Version:" +msgstr "Driver verziója:" + +#: dashboard/templates/dashboard/node-detail/resources.html:19 +msgid "with uncommitted changes!" +msgstr "beküldetlen változásokkal!" + +#: dashboard/templates/dashboard/node-detail/resources.html:23 msgid "Host owner" msgstr "Gép tulajdonosa" -#: dashboard/templates/dashboard/node-detail/resources.html:18 +#: dashboard/templates/dashboard/node-detail/resources.html:28 msgid "Host name" msgstr "Gépnév" -#: dashboard/templates/dashboard/node-detail/resources.html:23 +#: dashboard/templates/dashboard/node-detail/resources.html:34 msgid "Edit host" msgstr "Gép szerkesztése" @@ -2043,13 +2098,11 @@ msgstr "A legújabb fájlok listája." #, python-format msgid "" "\n" -" You are currently using %(used)s, your soft limit is %(soft)s, your " -"hard limit is %(hard)s.\n" +" You are currently using %(used)s, your soft limit is %(soft)s, your hard limit is %(hard)s.\n" " " msgstr "" "\n" -" Jelenlegi használat: %(used)s, puha korlát: %(soft)s, kemény korlát: " -"%(hard)s.\n" +" Jelenlegi használat: %(used)s, puha korlát: %(soft)s, kemény korlát: %(hard)s.\n" " " #: dashboard/templates/dashboard/store/index-files.html:16 @@ -2126,8 +2179,7 @@ msgstr "Fájl helye" #, python-format msgid "" "\n" -" Are you sure you want to remove the file at %(path)s?\n" +" Are you sure you want to remove the file at %(path)s?\n" " " msgstr "" "\n" @@ -2138,13 +2190,11 @@ msgstr "" #, python-format msgid "" "\n" -" Are you sure you want to remove the directory " -"%(directory)s?\n" +" Are you sure you want to remove the directory %(directory)s?\n" " " msgstr "" "\n" -" Biztosan törli a következő könyvtárat: %(directory)s?\n" +" Biztosan törli a következő könyvtárat: %(directory)s?\n" " " #: dashboard/templates/dashboard/store/upload.html:16 @@ -2182,7 +2232,7 @@ msgstr "Kevesebb tevékenység megjelenítése" msgid "Show all activities" msgstr "Összes tevékenység megjelenítése" -#: dashboard/templates/dashboard/vm-detail/_network-port-add.html:15 +#: dashboard/templates/dashboard/vm-detail/_network-port-add.html:16 msgid "Add" msgstr "Hozzáadás" @@ -2190,22 +2240,17 @@ msgstr "Hozzáadás" msgid "You are the current owner of this instance." msgstr "Ön a jelenlegi tulajdonosa a példánynak." -#: dashboard/templates/dashboard/vm-detail/access.html:7 +#: dashboard/templates/dashboard/vm-detail/access.html:8 #, python-format msgid "" "\n" -" The current owner of this instance is %(owner)s.\n" +" The current owner of this instance is %(name)s (%(owner)s).\n" " " msgstr "" "\n" -" A példány jelenlegi tulajdonosa: %(owner)s.\n" -" " +"A példány jelenlegi tulajdonosa: %(name)s (%(owner)s)." -#: dashboard/templates/dashboard/vm-detail/access.html:14 -msgid "Transfer ownership..." -msgstr "Tulajdon átruházása..." - -#: dashboard/templates/dashboard/vm-detail/access.html:18 +#: dashboard/templates/dashboard/vm-detail/access.html:19 msgid "Permissions" msgstr "Jogosultságok" @@ -2275,12 +2320,12 @@ msgid "edit" msgstr "szerkesztés" #: dashboard/templates/dashboard/vm-detail/network.html:36 -#: firewall/models.py:482 +#: firewall/models.py:598 msgid "IPv4 address" msgstr "IPv4 cím" #: dashboard/templates/dashboard/vm-detail/network.html:37 -#: firewall/models.py:492 +#: firewall/models.py:608 msgid "IPv6 address" msgstr "IPv6 cím" @@ -2289,12 +2334,12 @@ msgid "DNS name" msgstr "DNS név" #: dashboard/templates/dashboard/vm-detail/network.html:51 -#: network/forms.py:246 +#: network/forms.py:250 msgid "IPv4" msgstr "IPv4" #: dashboard/templates/dashboard/vm-detail/network.html:52 -#: network/forms.py:253 +#: network/forms.py:257 msgid "IPv6" msgstr "IPv6" @@ -2327,23 +2372,23 @@ msgstr "Elvárt jellemzők" msgid "Raw data" msgstr "Nyers adat" -#: dashboard/views/graph.py:166 dashboard/views/graph.py:167 +#: dashboard/views/graph.py:172 dashboard/views/graph.py:173 msgid "RAM usage (%)" msgstr "RAM-használat (%)" -#: dashboard/views/graph.py:178 dashboard/views/graph.py:179 +#: dashboard/views/graph.py:184 dashboard/views/graph.py:185 msgid "CPU usage (%)" msgstr "CPU-használat (%)" -#: dashboard/views/graph.py:231 dashboard/views/graph.py:281 +#: dashboard/views/graph.py:237 dashboard/views/graph.py:287 msgid "Instance count" msgstr "Példányok száma" -#: dashboard/views/graph.py:232 +#: dashboard/views/graph.py:238 msgid "instance count" msgstr "példányok száma" -#: dashboard/views/graph.py:241 dashboard/views/graph.py:261 +#: dashboard/views/graph.py:247 dashboard/views/graph.py:267 msgid "Allocated memory (bytes)" msgstr "Foglalt memória (byte)" @@ -2380,23 +2425,23 @@ msgstr "A csoport létrehozásra került." msgid "Group is successfully updated." msgstr "A csoport frissítésre került." -#: dashboard/views/node.py:114 +#: dashboard/views/node.py:121 msgid "Node successfully renamed." msgstr "A csomópont átnevezésre került." -#: dashboard/views/node.py:222 +#: dashboard/views/node.py:230 msgid "Node successfully created." msgstr "A csomópont létrehozásra került." -#: dashboard/views/node.py:250 +#: dashboard/views/node.py:258 msgid "Node successfully deleted." msgstr "A csomópont törlésre került." -#: dashboard/views/node.py:297 +#: dashboard/views/node.py:305 msgid "Trait successfully added to node." msgstr "A csomópontjellemző hozzáadásra került." -#: dashboard/views/node.py:342 +#: dashboard/views/node.py:350 msgid "Node successfully changed status." msgstr "A csomópont állapota megváltoztatásra került." @@ -2429,64 +2474,64 @@ msgstr "%s törlése sikertelen." msgid "Unable to create folder." msgstr "Mappa létrehozása sikertelen." -#: dashboard/views/template.py:65 +#: dashboard/views/template.py:68 msgid "Choose template" msgstr "Válasszon sablont" -#: dashboard/views/template.py:80 +#: dashboard/views/template.py:83 msgid "Select an option to proceed." msgstr "Válasszon a folytatáshoz." -#: dashboard/views/template.py:111 +#: dashboard/views/template.py:114 msgid "Create a new base VM" msgstr "Alap VM létrehozása" -#: dashboard/views/template.py:226 +#: dashboard/views/template.py:229 msgid "Error during filtering." msgstr "A szűrés sikertelen." -#: dashboard/views/template.py:245 +#: dashboard/views/template.py:248 msgid "Only the owners can delete the selected template." msgstr "A kiválasztott sablont csak a tulajdonosok törölhetik." -#: dashboard/views/template.py:261 +#: dashboard/views/template.py:264 msgid "Template successfully deleted." msgstr "A sablon törlésre került." -#: dashboard/views/template.py:277 +#: dashboard/views/template.py:280 msgid "Successfully modified template." msgstr "A sablon módosításra került." -#: dashboard/views/template.py:352 +#: dashboard/views/template.py:355 msgid "Disk remove confirmation" msgstr "Lemez törlésének megerősítése" -#: dashboard/views/template.py:353 +#: dashboard/views/template.py:356 #, python-format msgid "" -"Are you sure you want to remove %(disk)s from " -"%(app)s?" +"Are you sure you want to remove %(disk)s from " +"%(app)s?" msgstr "" "Biztosan eltávolítja a(z) %(disk)s lemezt a következőből: " "%(app)s?" -#: dashboard/views/template.py:372 +#: dashboard/views/template.py:375 msgid "Disk successfully removed." msgstr "A lemez eltávolításra került." -#: dashboard/views/template.py:390 +#: dashboard/views/template.py:393 msgid "Successfully created a new lease." msgstr "Új bérlési mód létrehozásra került." -#: dashboard/views/template.py:409 +#: dashboard/views/template.py:412 msgid "Successfully modified lease." msgstr "A bérlési mód megváltoztatásra került." -#: dashboard/views/template.py:423 +#: dashboard/views/template.py:426 msgid "Only the owners can modify the selected lease." msgstr "Csak a tulajdonosai törölhetik a kiválasztott bérleti módot." -#: dashboard/views/template.py:452 +#: dashboard/views/template.py:455 msgid "" "You can't delete this lease because some templates are still using it, " "modify these to proceed: " @@ -2494,14 +2539,24 @@ msgstr "" "Nem törölhető a bérleti mód, mivel az alábbi sablonok még használják. A " "folytatáshoz módosítsa őket: " -#: dashboard/views/template.py:463 +#: dashboard/views/template.py:466 msgid "Only the owners can delete the selected lease." msgstr "Csak a tulajdonos törölheti a kiválasztott bérleti módot." -#: dashboard/views/template.py:481 +#: dashboard/views/template.py:484 msgid "Lease successfully deleted." msgstr "A bérlési mód törlésre került." +#: dashboard/views/template.py:505 +#, python-format +msgid "" +"%(user)s offered you to take the ownership of his/her template called " +"%(instance)s. Accept" +msgstr "" +"%(user)s át kívánja ruházni %(instance)s nevű sablonját Önre. Elfogadás" + #: dashboard/views/user.py:134 #, python-format msgid "Logged in as user %s." @@ -2539,484 +2594,485 @@ msgstr "A parancssablon törlésre került." msgid "Successfully created a new command template." msgstr "A parancssablon létrehozásra került." -#: dashboard/views/util.py:268 +#: dashboard/views/util.py:270 msgid "Could not start operation." msgstr "A művelet megkezdése meghiúsult." -#: dashboard/views/util.py:285 +#: dashboard/views/util.py:287 msgid "Operation failed." msgstr "A művelet meghiúsult." -#: dashboard/views/util.py:290 +#: dashboard/views/util.py:292 msgid "Operation succeeded." msgstr "A művelet sikeresen végrehajtásra került." -#: dashboard/views/util.py:292 +#: dashboard/views/util.py:294 msgid "Operation is started." msgstr "A művelet megkezdődött." -#: dashboard/views/util.py:386 +#: dashboard/views/util.py:388 #, python-format msgid "Acl user/group %(w)s successfully modified." msgstr "A(z) %(w)s ACL felhasználó/csoport módosításra került." -#: dashboard/views/util.py:388 +#: dashboard/views/util.py:390 #, python-format msgid "Acl user/group %(w)s successfully added." msgstr "A(z) %(w)s ACL felhasználó/csoport hozzáadásra került." -#: dashboard/views/util.py:390 +#: dashboard/views/util.py:392 #, python-format msgid "Acl user/group %(w)s successfully removed." msgstr "A(z) %(w)s ACL felhasználó/csoport törlésre került." -#: dashboard/views/util.py:475 +#: dashboard/views/util.py:477 msgid "" "The original owner cannot be removed, however you can transfer ownership." msgstr "Az eredeti tulajdonos nem törölhető, azonban a tulajdon átruházható." -#: dashboard/views/util.py:511 +#: dashboard/views/util.py:513 #, python-format msgid "User \"%s\" has already access to this object." msgstr "„%s” felhasználó már hozzáfér az objektumhoz." -#: dashboard/views/util.py:520 +#: dashboard/views/util.py:522 #, python-format msgid "Group \"%s\" has already access to this object." msgstr "„%s” csoport már hozzáfér az objektumhoz." -#: dashboard/views/util.py:525 +#: dashboard/views/util.py:527 #, python-format msgid "User or group \"%s\" not found." msgstr "Nem található „%s” felhasználó vagy csoport." -#: dashboard/views/util.py:541 +#: dashboard/views/util.py:543 msgid "1 hour" msgstr "1 óra" -#: dashboard/views/util.py:542 +#: dashboard/views/util.py:544 msgid "6 hours" msgstr "6 óra" -#: dashboard/views/util.py:543 +#: dashboard/views/util.py:545 msgid "1 day" msgstr "1 nap" -#: dashboard/views/util.py:544 +#: dashboard/views/util.py:546 msgid "1 week" msgstr "1 hét" -#: dashboard/views/util.py:545 +#: dashboard/views/util.py:547 msgid "1 month" msgstr "1 hónap" -#: dashboard/views/util.py:546 +#: dashboard/views/util.py:548 msgid "6 months" msgstr "6 hónap" -#: dashboard/views/util.py:555 +#: dashboard/views/util.py:557 msgid "Bad graph time format, available periods are: h, d, w, and y." msgstr "Hibás grafikon időformátum. Lehetséges egységek: h, d, w és y." -#: dashboard/views/vm.py:84 +#: dashboard/views/util.py:582 +msgid "Transfer ownership" +msgstr "Tulajdon átruházása" + +#: dashboard/views/util.py:595 +msgid "Can not find specified user." +msgstr "Nem található a megadott felhasználó." + +#: dashboard/views/util.py:611 +msgid "Ownership offer" +msgstr "Átruházási ajánlat" + +#: dashboard/views/util.py:615 +msgid "Can not notify selected user." +msgstr "A kiválaszott felhasználó értesítése sikertelen." + +#: dashboard/views/util.py:618 +#, python-format +msgid "User %s is notified about the offer." +msgstr "%s felhasználó értesítésre került az ajánlatról." + +#: dashboard/views/util.py:628 +msgid "Ownership successfully transferred to you." +msgstr "A tulajdon átruházásra került." + +#: dashboard/views/util.py:641 +msgid "This token is for an other user." +msgstr "A token más felhasználó nevére szól." + +#: dashboard/views/util.py:644 +msgid "This token is invalid or has expired." +msgstr "A token érvénytelen vagy lejárt." + +#: dashboard/views/util.py:666 +msgid "Ownership accepted" +msgstr "Átruházás elfogadva" + +#: dashboard/views/util.py:667 +#, python-format +msgid "Your ownership offer of %(instance)s has been accepted by %(user)s." +msgstr "%(instance)s gépre vonatkozó átruházási ajánlatát elfogadta %(user)s." + +#: dashboard/views/vm.py:86 msgid "console access" msgstr "konzolhozzáférés" -#: dashboard/views/vm.py:193 +#: dashboard/views/vm.py:195 msgid "VM successfully renamed." msgstr "A virtuális gép átnevezésre került." -#: dashboard/views/vm.py:217 +#: dashboard/views/vm.py:219 msgid "VM description successfully updated." msgstr "A VM leírása megváltoztatásra került." -#: dashboard/views/vm.py:294 -msgid "There is a problem with your input." -msgstr "A megadott érték nem megfelelő." - -#: dashboard/views/vm.py:296 -msgid "Unknown error." -msgstr "Ismeretlen hiba." - -#: dashboard/views/vm.py:543 +#: dashboard/views/vm.py:567 msgid "The token has expired." msgstr "A token lejárt." -#: dashboard/views/vm.py:757 +#: dashboard/views/vm.py:783 #, python-format msgid "Failed to execute %(op)s operation on instance %(instance)s." msgstr "%(op)s végrehajtása meghiúsult a következőn: %(instance)s." -#: dashboard/views/vm.py:773 +#: dashboard/views/vm.py:799 #, python-format msgid "You are not permitted to execute %(op)s on instance %(instance)s." msgstr "Nem engedélyezett a(z) %(op)s végrehajtása a(z) %(instance)s gépen." -#: dashboard/views/vm.py:955 +#: dashboard/views/vm.py:981 msgid "Customize VM" msgstr "VM testreszabása" -#: dashboard/views/vm.py:963 +#: dashboard/views/vm.py:989 msgid "Create a VM" msgstr "VM létrehozása" -#: dashboard/views/vm.py:1028 +#: dashboard/views/vm.py:1054 #, python-format msgid "Successfully created %(count)d VM." msgid_plural "Successfully created %(count)d VMs." msgstr[0] "%(count)d VM létrehozásra került." msgstr[1] "%(count)d VM létrehozásra került." -#: dashboard/views/vm.py:1033 +#: dashboard/views/vm.py:1059 msgid "VM successfully created." msgstr "VM létrehozásra került." -#: dashboard/views/vm.py:1062 +#: dashboard/views/vm.py:1088 #, python-format msgid "Instance limit (%d) exceeded." msgstr "A példányok létrehozási korlátját (%d) túllépte." -#: dashboard/views/vm.py:1100 +#: dashboard/views/vm.py:1126 #, python-format msgid "" "Are you sure you want to remove this interface from %(vm)s?" msgstr "" "Biztosan eltávolítja az interfészt a(z) %(vm)s gépből?" -#: dashboard/views/vm.py:1114 +#: dashboard/views/vm.py:1140 msgid "Interface successfully deleted." msgstr "Az interfész törlésre került." -#: dashboard/views/vm.py:1183 -msgid "Port delete confirmation" -msgstr "Porteltávolítás megerősítése" - -#: dashboard/views/vm.py:1184 -#, python-format -msgid "Are you sure you want to close %(port)d/%(proto)s on %(vm)s?" -msgstr "Biztosan bezárja a(z) %(port)d/%(proto)s portot a következőn: %(vm)s?" - -#: dashboard/views/vm.py:1199 -msgid "Port successfully removed." -msgstr "A port eltávolításra került." - -#: dashboard/views/vm.py:1226 +#: dashboard/views/vm.py:1206 msgid "About CIRCLE Client" msgstr "A CIRCLE kliensről" -#: dashboard/views/vm.py:1323 -msgid "Transfer ownership" -msgstr "Tulajdon átruházása" - -#: dashboard/views/vm.py:1336 -msgid "Can not find specified user." -msgstr "Nem található a megadott felhasználó." +#: dashboard/views/vm.py:1296 +msgid "transfer ownership" +msgstr "tulajdon átruházása" -#: dashboard/views/vm.py:1352 -msgid "Ownership offer" -msgstr "Átruházási ajánlat" - -#: dashboard/views/vm.py:1353 +#: dashboard/views/vm.py:1306 #, python-format msgid "" -"%(user)s offered you to take the ownership of his/her virtual machine called " -"%(instance)s. Accept" +"%(user)s offered you to take the ownership of his/her virtual machine called" +" %(instance)s. Accept" msgstr "" -"%(user)s át kívánja ruházni %(instance)s nevű virtuális gépét Önre. Elfogadás" - -#: dashboard/views/vm.py:1359 -msgid "Can not notify selected user." -msgstr "A kiválaszott felhasználó értesítése sikertelen." - -#: dashboard/views/vm.py:1362 -#, python-format -msgid "User %s is notified about the offer." -msgstr "%s felhasználó értesítésre került az ajánlatról." - -#: dashboard/views/vm.py:1373 -msgid "Ownership successfully transferred to you." -msgstr "A tulajdon átruházásra került." - -#: dashboard/views/vm.py:1386 -msgid "This token is for an other user." -msgstr "A token más felhasználó nevére szól." - -#: dashboard/views/vm.py:1389 -msgid "This token is invalid or has expired." -msgstr "A token érvénytelen vagy lejárt." - -#: dashboard/views/vm.py:1411 -msgid "Ownership accepted" -msgstr "Átruházás elfogadva" - -#: dashboard/views/vm.py:1412 -#, python-format -msgid "Your ownership offer of %(instance)s has been accepted by %(user)s." -msgstr "%(instance)s gépre vonatkozó átruházási ajánlatát elfogadta %(user)s." +"%(user)s át kívánja ruházni %(instance)s nevű virtuális gépét Önre. Elfogadás" -#: firewall/fields.py:39 +#: firewall/fields.py:43 #, python-format msgid "Enter a valid MAC address. %s" msgstr "Érvénytelen MAC cím. %s" -#: firewall/fields.py:51 +#: firewall/fields.py:55 msgid "MAC Address object" msgstr "MAC cím objektum" -#: firewall/fields.py:90 +#: firewall/fields.py:91 #, python-format msgid "Enter a valid IP address. %s" msgstr "Érvénytelen IP cím. %s" -#: firewall/fields.py:107 firewall/fields.py:165 +#: firewall/fields.py:108 firewall/fields.py:166 msgid "IP Network object" msgstr "IP hálózat objektum" -#: firewall/fields.py:148 +#: firewall/fields.py:149 #, python-format msgid "Enter a valid IP network. %s" msgstr "Érvénytelen IP hálózat. %s" -#: firewall/fields.py:211 +#: firewall/fields.py:212 #, python-format msgid "%s - only letters, numbers, underscores and hyphens are allowed!" msgstr "%s – csak betűk, számok, alulvonások és kötőjelek." -#: firewall/fields.py:228 firewall/fields.py:234 +#: firewall/fields.py:229 firewall/fields.py:235 #, python-format msgid "%s - invalid domain name" msgstr "%s – érvénytelen tartománynév" -#: firewall/fields.py:267 +#: firewall/fields.py:281 +#, python-format +msgid "%s: invalid template" +msgstr "%s: érvénytelen sablon" + +#: firewall/fields.py:292 +#, python-format +msgid "template doesn't use parameter %s" +msgstr "a sablon nem használja a(z) %s paramétert" + +#: firewall/fields.py:296 +msgid "template renders invalid IPv6 address" +msgstr "a sablon érvénytelen IPv6 címet ad" + +#: firewall/fields.py:302 +msgid "template results in IPv4 address" +msgstr "a sablon IPv4 címet ad" + +#: firewall/fields.py:313 #, python-format msgid "%s - not an IPv4 address" msgstr "%s – nem egy IPv4 cím" -#: firewall/fields.py:273 +#: firewall/fields.py:319 #, python-format msgid "%s - not an IPv6 address" msgstr "%s – nem egy IPv6 cím" -#: firewall/fields.py:284 +#: firewall/fields.py:330 msgid "Bad MX address format. Should be: :" msgstr "Érvénytelen MX címformátum. Elvárt formátum: :" -#: firewall/models.py:60 +#: firewall/models.py:64 msgid "out" msgstr "ki" -#: firewall/models.py:60 +#: firewall/models.py:64 msgid "in" msgstr "be" -#: firewall/models.py:61 +#: firewall/models.py:65 msgid "accept" msgstr "elfogadás" -#: firewall/models.py:61 +#: firewall/models.py:65 msgid "drop" msgstr "eldobás" -#: firewall/models.py:62 +#: firewall/models.py:66 msgid "ignore" msgstr "ignorálás" -#: firewall/models.py:65 +#: firewall/models.py:69 msgid "direction" msgstr "irány" -#: firewall/models.py:66 +#: firewall/models.py:70 msgid "If the rule matches egress or ingress packets." msgstr "A szabály kimenő vagy bejövő csomagokra illeszkedik." -#: firewall/models.py:68 firewall/models.py:334 firewall/models.py:419 -#: firewall/models.py:442 firewall/models.py:499 firewall/models.py:857 -#: firewall/models.py:881 firewall/models.py:951 vm/models/instance.py:137 +#: firewall/models.py:72 firewall/models.py:345 firewall/models.py:535 +#: firewall/models.py:558 firewall/models.py:615 firewall/models.py:986 +#: firewall/models.py:1010 firewall/models.py:1080 vm/models/instance.py:137 #: vm/models/instance.py:227 msgid "description" msgstr "leírás" -#: firewall/models.py:69 +#: firewall/models.py:73 msgid "Why is the rule needed, or how does it work." msgstr "Miért szükséges a szabály, vagy hogyan működik." -#: firewall/models.py:72 +#: firewall/models.py:76 msgid "foreign network" msgstr "idegen hálózat" -#: firewall/models.py:73 +#: firewall/models.py:77 msgid "" "The group of vlans the matching packet goes to (direction out) or from (in)." msgstr "" "A vlanok azon csoportja, amelybe a csomag megy (ki irány) vagy emelyből jön " "(be irány)." -#: firewall/models.py:77 +#: firewall/models.py:81 msgid "dest. port" msgstr "célport" -#: firewall/models.py:79 +#: firewall/models.py:83 msgid "Destination port number of packets that match." msgstr "Az illeszkedő csomagok célportjának száma." -#: firewall/models.py:81 +#: firewall/models.py:85 msgid "source port" msgstr "forrásport" -#: firewall/models.py:83 +#: firewall/models.py:87 msgid "Source port number of packets that match." msgstr "Az illeszkedő csomagok forrásportjának száma." -#: firewall/models.py:85 +#: firewall/models.py:89 msgid "weight" msgstr "súly" -#: firewall/models.py:87 +#: firewall/models.py:91 msgid "Rule weight" msgstr "A szabály súlya" -#: firewall/models.py:90 +#: firewall/models.py:94 msgid "protocol" msgstr "protokoll" -#: firewall/models.py:91 +#: firewall/models.py:95 msgid "Protocol of packets that match." msgstr "Az illeszkedő csomagok protokollja." -#: firewall/models.py:92 +#: firewall/models.py:96 msgid "extra arguments" msgstr "további argumentumok" -#: firewall/models.py:93 +#: firewall/models.py:97 msgid "Additional arguments passed literally to the iptables-rule." msgstr "Az iptables-szabályhoz változtatás nélkül hozzáadott argumentumok." -#: firewall/models.py:96 +#: firewall/models.py:100 msgid "action" msgstr "művelet" -#: firewall/models.py:97 +#: firewall/models.py:101 msgid "Accept, drop or ignore the matching packets." msgstr "Az illeszkedő csomagok elfogadása, eldobása vagy ignorálása." -#: firewall/models.py:101 +#: firewall/models.py:105 msgid "The user responsible for this rule." msgstr "A szabályért felelős felhasználó." -#: firewall/models.py:104 +#: firewall/models.py:108 msgid "NAT" msgstr "NAT" -#: firewall/models.py:105 +#: firewall/models.py:109 msgid "If network address translation should be done." msgstr "Hálózati címfordítás engedélyezése." -#: firewall/models.py:109 +#: firewall/models.py:113 msgid "Rewrite destination port number to this if NAT is needed." msgstr "Célport számának átírása a megadottra NAT esetén." -#: firewall/models.py:114 +#: firewall/models.py:118 msgid "external IPv4 address" msgstr "külső IPv4 cím" -#: firewall/models.py:118 firewall/models.py:367 firewall/models.py:424 -#: firewall/models.py:447 firewall/models.py:518 +#: firewall/models.py:122 firewall/models.py:388 firewall/models.py:540 +#: firewall/models.py:563 firewall/models.py:634 msgid "created at" msgstr "létrehozva" -#: firewall/models.py:121 firewall/models.py:371 firewall/models.py:426 -#: firewall/models.py:449 firewall/models.py:520 +#: firewall/models.py:125 firewall/models.py:392 firewall/models.py:542 +#: firewall/models.py:565 firewall/models.py:636 msgid "modified at" msgstr "módosítva" -#: firewall/models.py:124 firewall/models.py:507 +#: firewall/models.py:128 firewall/models.py:623 #: network/templates/network/vlan-create.html:8 #: network/templates/network/vlan-edit.html:8 vm/models/network.py:39 #: vm/models/network.py:64 msgid "vlan" msgstr "vlan" -#: firewall/models.py:125 +#: firewall/models.py:129 msgid "Vlan the rule applies to (if type is vlan)." msgstr "Erre a vlanra vonatkozik a szabály (ha a típus vlan)." -#: firewall/models.py:129 network/templates/network/vlan-group-create.html:8 +#: firewall/models.py:133 network/templates/network/vlan-group-create.html:8 #: network/templates/network/vlan-group-edit.html:8 msgid "vlan group" msgstr "vlan-csoport" -#: firewall/models.py:130 +#: firewall/models.py:134 msgid "Group of vlans the rule applies to (if type is vlan)." msgstr "Erre a vlan-csoportra vonatkozik a szabály (ha a típus vlan)." -#: firewall/models.py:133 firewall/models.py:874 firewall/models.py:994 +#: firewall/models.py:137 firewall/models.py:1003 firewall/models.py:1123 #: network/templates/network/host-create.html:8 #: network/templates/network/host-edit.html:8 vm/models/network.py:66 #: vm/models/node.py:70 msgid "host" msgstr "gép" -#: firewall/models.py:134 +#: firewall/models.py:138 msgid "Host the rule applies to (if type is host)." msgstr "Erre a gépre vonatkozik a szabály (ha a típus gép)." -#: firewall/models.py:137 network/templates/network/group-create.html:8 +#: firewall/models.py:141 network/templates/network/group-create.html:8 #: network/templates/network/group-edit.html:8 msgid "host group" msgstr "gépcsoport" -#: firewall/models.py:138 +#: firewall/models.py:142 msgid "Group of hosts the rule applies to (if type is host)." msgstr "Erre a gépcsoportra vonatkozik a szabály (ha a típus gép)." -#: firewall/models.py:141 +#: firewall/models.py:145 msgid "firewall" msgstr "tűzfal" -#: firewall/models.py:142 +#: firewall/models.py:146 msgid "Firewall the rule applies to (if type is firewall)." msgstr "Erre a tűzfalra vonatkozik a szabály (ha a típus tűzfal)." -#: firewall/models.py:154 +#: firewall/models.py:158 msgid "Only one field can be selected." msgstr "Csak egy mező választható ki." -#: firewall/models.py:247 network/templates/network/rule-create.html:8 +#: firewall/models.py:258 network/templates/network/rule-create.html:8 #: network/templates/network/rule-edit.html:8 msgid "rule" msgstr "szabály" -#: firewall/models.py:248 +#: firewall/models.py:259 msgid "rules" msgstr "szabályok" -#: firewall/models.py:276 +#: firewall/models.py:287 msgid "public" msgstr "nyilvános" -#: firewall/models.py:277 +#: firewall/models.py:288 msgid "portforward" msgstr "porttovábbítás" -#: firewall/models.py:279 +#: firewall/models.py:290 msgid "VID" msgstr "VID" -#: firewall/models.py:280 +#: firewall/models.py:291 msgid "The vlan ID of the subnet." msgstr "Az alhálózat vlan-azonosítója." -#: firewall/models.py:286 +#: firewall/models.py:297 msgid "The short name of the subnet." msgstr "Az alhálózat rövid neve." -#: firewall/models.py:290 +#: firewall/models.py:301 msgid "IPv4 address/prefix" msgstr "IPv4 cím/prefixhossz" -#: firewall/models.py:292 +#: firewall/models.py:303 msgid "" "The IPv4 address and the prefix length of the gateway. Recommended value is " "the last valid address of the subnet, for example 10.4.255.254/16 for " @@ -3025,43 +3081,43 @@ msgstr "" "Az útválasztó IPv4 címe és prefixhossza. Az ajánlott érték az alhálózat " "utolsó érvényes címe, például 10.4.255.254/16 a 10.4.0.0/16 hálózat esetén." -#: firewall/models.py:299 +#: firewall/models.py:310 msgid "IPv6 prefixlen/host" msgstr "IPv6 prefixhossz/gép" -#: firewall/models.py:300 +#: firewall/models.py:311 msgid "" -"The prefix length of the subnet assigned to a host. For example /112 = 65536 " -"addresses/host." +"The prefix length of the subnet assigned to a host. For example /112 = 65536" +" addresses/host." msgstr "" "A géphez rendelt alhálózat prefixhossza. Például a /112 beállítás 65536 " "címet jelent gépenként." -#: firewall/models.py:308 +#: firewall/models.py:319 msgid "IPv6 address/prefix" msgstr "IPv6 cím/prefixhossz" -#: firewall/models.py:310 +#: firewall/models.py:321 msgid "The IPv6 address and the prefix length of the gateway." msgstr "Az útválasztó IPv6 címe és prefixhossza." -#: firewall/models.py:314 +#: firewall/models.py:325 msgid "NAT IP address" msgstr "NAT IP cím" -#: firewall/models.py:316 +#: firewall/models.py:327 msgid "" "Common IPv4 address used for address translation of connections to the " "networks selected below (typically to the internet)." msgstr "" -"Közös címfordításra használt IPv4 cím a kiválasztott hálózatok felé irányuló " -"kapcsolatokhoz (tipikusan az internet felé)." +"Közös címfordításra használt IPv4 cím a kiválasztott hálózatok felé irányuló" +" kapcsolatokhoz (tipikusan az internet felé)." -#: firewall/models.py:322 +#: firewall/models.py:333 msgid "NAT to" msgstr "NAT ide" -#: firewall/models.py:324 +#: firewall/models.py:335 msgid "" "Connections to these networks should be network address translated, i.e. " "their source address is rewritten to the value of NAT IP address." @@ -3069,62 +3125,84 @@ msgstr "" "A megadott hálózatok felé induló kapcsolatok címfordításra kerülnek: a " "forráscímük a megadott NAT IP címre lesz átírva." -#: firewall/models.py:330 +#: firewall/models.py:341 msgid "network type" msgstr "hálózat típusa" -#: firewall/models.py:333 vm/models/network.py:41 +#: firewall/models.py:344 vm/models/network.py:41 msgid "managed" msgstr "menedzselt" -#: firewall/models.py:336 +#: firewall/models.py:347 msgid "Description of the goals and elements of the vlan network." msgstr "A vlan hálózat céljainak és elemeinek leírása." -#: firewall/models.py:338 +#: firewall/models.py:349 msgid "comment" msgstr "megjegyzés" -#: firewall/models.py:340 +#: firewall/models.py:351 msgid "Notes, comments about the network" msgstr "Jegyzetek, megjegyzések a hálózatról" -#: firewall/models.py:341 +#: firewall/models.py:352 msgid "domain name" msgstr "tartománynév" -#: firewall/models.py:342 +#: firewall/models.py:353 msgid "Domain name of the members of this network." msgstr "A hálózat tagjainak tartományneve." -#: firewall/models.py:346 +#: firewall/models.py:357 msgid "reverse domain" msgstr "reverz tartomány" -#: firewall/models.py:347 +#: firewall/models.py:358 #, python-format msgid "" "Template of the IPv4 reverse domain name that should be generated for each " -"host. The template should contain four tokens: \"%(a)d\", \"%(b)d\", \"%(c)d" -"\", and \"%(d)d\", representing the four bytes of the address, respectively, " -"in decimal notation. For example, the template for the standard reverse " -"address is: \"%(d)d.%(c)d.%(b)d.%(a)d.in-addr.arpa\"." +"host. The template should contain four tokens: \"%(a)d\", \"%(b)d\", " +"\"%(c)d\", and \"%(d)d\", representing the four bytes of the address, " +"respectively, in decimal notation. For example, the template for the " +"standard reverse address is: \"%(d)d.%(c)d.%(b)d.%(a)d.in-addr.arpa\"." msgstr "" "Az IPv4 reverz tartománynevek generálásához használt sablon. A sablon négy " "tokent kell tartalmazzon: \"%(a)d\", \"%(b)d\", \"%(c)d\" és \"%(d)d\", " "amelyek rendre a cím négy byte-ját reprezentálják, decimális jelölésben. " -"Például a szabványos reverz név sablonja: \"%(d)d.%(c)d.%(b)d.%(a)d.in-addr." -"arpa\"." - -#: firewall/models.py:357 +"Például a szabványos reverz név sablonja: \"%(d)d.%(c)d.%(b)d.%(a)d.in-" +"addr.arpa\"." + +#: firewall/models.py:368 +#, python-format +msgid "" +"Template for translating IPv4 addresses to IPv6. Automatically generated " +"hosts in dual-stack networks will get this address. The template can contain" +" four tokens: \"%(a)d\", \"%(b)d\", \"%(c)d\", and \"%(d)d\", representing " +"the four bytes of the IPv4 address, respectively, in decimal notation. " +"Moreover you can use any standard printf format specification like %(a)02x " +"to get the first byte as two hexadecimal digits. Usual choices for mapping " +"198.51.100.0/24 to 2001:0DB8:1:1::/64 would be \"2001:db8:1:1:%(d)d::\" and " +"\"2001:db8:1:1:%(d)02x00::\"." +msgstr "" +"Sablon az IPv4 címek IPv6-ra való fordításához. A dual-stack hálózatokban " +"automatikusan generált gépek ezt a címet fogják kapni. A sablon négy tokent " +"(\"%(a)d\", \"%(b)d\", \"%(c)d\" és \"%(d)d\") tartalmazhat, amelyek rendre " +"az IPv4 cím négy byte-ját tartalmazzák decimális formában. Ezen kívül más " +"szabványos printf formátumspecifikációk is használhatóak, mint például a " +"%(a)02x, amely az első byte-ot két hexadecimális számjegyként reprezentálja." +" Például a 198.51.100.0/24 hálózat 2001:0DB8:1:1::/64 alá képezésére " +"szokásos választás lehet a \"2001:db8:1:1:%(d)d::\" és a " +"\"2001:db8:1:1:%(d)02x00::\"." + +#: firewall/models.py:379 msgid "ipv6 template" msgstr "ipv6 sablon" -#: firewall/models.py:359 +#: firewall/models.py:380 msgid "DHCP pool" msgstr "DHCP készlet" -#: firewall/models.py:361 +#: firewall/models.py:382 msgid "" "The address range of the DHCP pool: empty for no DHCP service, \"manual\" " "for no DHCP pool, or the first and last address of the range separated by a " @@ -3134,180 +3212,194 @@ msgstr "" "tiltásához adja meg a „manual” értéket, engedélyezéséhez az első és utolsó " "érvényes címet szóközzel elválasztva." +#: firewall/models.py:399 +msgid "You cannot specify an IPv6 template if there is no IPv6 network set." +msgstr "Nem adhat meg IPv6 sablont, ha nincs IPv6 hálózat beállítva." + #: firewall/models.py:405 +#, python-format +msgid "%(ip6)s (translated from %(ip4)s) is outside of the IPv6 network." +msgstr "%(ip6)s (ebből képezve: %(ip4)s) kívül esik az IPv6 hálózaton." + +#: firewall/models.py:449 +msgid "IPv6 network is too small to map IPv4 addresses to it." +msgstr "Az IPv6 hálózat túl kicsi az IPv4 címek leképezéséhez." + +#: firewall/models.py:507 msgid "All IP addresses are already in use." msgstr "Minden IP cím használatban van." -#: firewall/models.py:414 firewall/models.py:441 +#: firewall/models.py:530 firewall/models.py:557 msgid "The name of the group." msgstr "A csoport neve." -#: firewall/models.py:416 +#: firewall/models.py:532 msgid "vlans" msgstr "vlanok" -#: firewall/models.py:417 +#: firewall/models.py:533 msgid "The vlans which are members of the group." msgstr "A csoport tagjait képező vlanok." -#: firewall/models.py:420 firewall/models.py:443 +#: firewall/models.py:536 firewall/models.py:559 msgid "Description of the group." msgstr "A csoport leírása." -#: firewall/models.py:465 storage/models.py:50 +#: firewall/models.py:581 network/tables.py:130 storage/models.py:50 msgid "hostname" msgstr "gépnév" -#: firewall/models.py:466 +#: firewall/models.py:582 msgid "The alphanumeric hostname of the host, the first part of the FQDN." msgstr "A gép alfanumerikus gépneve, az FQDN első része." -#: firewall/models.py:472 +#: firewall/models.py:588 msgid "reverse" msgstr "reverz" -#: firewall/models.py:473 +#: firewall/models.py:589 msgid "" -"The fully qualified reverse hostname of the host, if different than hostname." -"domain." +"The fully qualified reverse hostname of the host, if different than " +"hostname.domain." msgstr "" -"A gép teljes reverz tartományneve, amennyiben különbözik ettől: gépnév." -"tartomány." +"A gép teljes reverz tartományneve, amennyiben különbözik ettől: " +"gépnév.tartomány." -#: firewall/models.py:477 +#: firewall/models.py:593 network/tables.py:129 msgid "MAC address" msgstr "MAC cím" -#: firewall/models.py:478 +#: firewall/models.py:594 msgid "" -"The MAC (Ethernet) address of the network interface. For example: 99:AA:BB:" -"CC:DD:EE." +"The MAC (Ethernet) address of the network interface. For example: " +"99:AA:BB:CC:DD:EE." msgstr "A hálózati interfész MAC (Ethernet) címe. Például 99:AA:BB:CC:DD:EE." -#: firewall/models.py:483 +#: firewall/models.py:599 msgid "The real IPv4 address of the host, for example 10.5.1.34." msgstr "A gép valódi IPv4 címe, például 10.5.1.34." -#: firewall/models.py:487 +#: firewall/models.py:603 msgid "WAN IPv4 address" msgstr "WAN IPv4 cím" -#: firewall/models.py:488 +#: firewall/models.py:604 msgid "" "The public IPv4 address of the host on the wide area network, if different." msgstr "A gép nyilvános IPv4 címe a nagy kiterjedésű hálózaton, ha eltér." -#: firewall/models.py:493 +#: firewall/models.py:609 msgid "The global IPv6 address of the host, for example 2001:db:88:200::10." msgstr "A gép globális IPv6 címe, például 2001:db:88:200::10." -#: firewall/models.py:495 +#: firewall/models.py:611 msgid "shared IP" msgstr "osztott IP" -#: firewall/models.py:497 +#: firewall/models.py:613 msgid "If the given WAN IPv4 address is used by multiple hosts." msgstr "A WAN IPv4 címet több gép használja-e." -#: firewall/models.py:500 +#: firewall/models.py:616 msgid "What is this host for, what kind of machine is it." msgstr "Mi a gép célja, milyen gép ez." -#: firewall/models.py:503 +#: firewall/models.py:619 msgid "Notes" msgstr "Jegyzetek" -#: firewall/models.py:504 +#: firewall/models.py:620 msgid "location" msgstr "elhelyezés" -#: firewall/models.py:506 +#: firewall/models.py:622 msgid "The physical location of the machine." msgstr "A gép fizikai helye." -#: firewall/models.py:509 +#: firewall/models.py:625 msgid "Vlan network that the host is part of." msgstr "Az a vlan hálózat, amelynek a gép része." -#: firewall/models.py:512 +#: firewall/models.py:628 msgid "The person responsible for this host." msgstr "A gépért felelős személy." -#: firewall/models.py:514 +#: firewall/models.py:630 msgid "groups" msgstr "csoportok" -#: firewall/models.py:516 +#: firewall/models.py:632 msgid "Host groups the machine is part of." msgstr "Gépcsoportok, amelyeknek tagja a gép." -#: firewall/models.py:569 +#: firewall/models.py:685 msgid "If shared_ip has been checked, external_ipv4 has to be unique." msgstr "" -"Amennyiben az osztott IP mező igaz, a külső IPv4 cím mező egyedi kell legyen." +"Amennyiben az osztott IP mező igaz, a külső IPv4 cím mező egyedi kell " +"legyen." -#: firewall/models.py:572 +#: firewall/models.py:688 msgid "You can't use another host's NAT'd address as your own IPv4." msgstr "Nem használható másik gép NAT-olt címe saját IPv4 címként." -#: firewall/models.py:678 +#: firewall/models.py:793 #, python-format msgid "All %s ports are already in use." msgstr "Minden %s port használatban van." -#: firewall/models.py:696 +#: firewall/models.py:811 #, python-format msgid "Port %(proto)s %(public)s is already in use." msgstr "A(z) %(public)s %(proto)s port használatban van." -#: firewall/models.py:714 +#: firewall/models.py:829 msgid "Only ports above 1024 can be used." msgstr "Csak az 1024 feletti portok használhatóak." -#: firewall/models.py:853 firewall/models.py:883 firewall/models.py:953 -#: firewall/models.py:981 firewall/models.py:1005 +#: firewall/models.py:982 firewall/models.py:1012 firewall/models.py:1082 +#: firewall/models.py:1110 firewall/models.py:1134 msgid "created_at" msgstr "létrehozva" -#: firewall/models.py:855 firewall/models.py:885 firewall/models.py:955 -#: firewall/models.py:983 firewall/models.py:1007 +#: firewall/models.py:984 firewall/models.py:1014 firewall/models.py:1084 +#: firewall/models.py:1112 firewall/models.py:1136 msgid "modified_at" msgstr "módosítva" -#: firewall/models.py:856 firewall/models.py:879 +#: firewall/models.py:985 firewall/models.py:1008 msgid "ttl" msgstr "ttl" -#: firewall/models.py:872 network/templates/network/domain-create.html:8 +#: firewall/models.py:1001 network/templates/network/domain-create.html:8 #: network/templates/network/domain-edit.html:8 msgid "domain" msgstr "tartomány" -#: firewall/models.py:878 +#: firewall/models.py:1007 msgid "address" msgstr "cím" -#: firewall/models.py:900 +#: firewall/models.py:1029 msgid "Address must be specified!" msgstr "A cím megadása kötelező." -#: firewall/models.py:913 +#: firewall/models.py:1042 msgid "Unknown record type." msgstr "Ismeretlen rekordtípus." -#: firewall/models.py:947 +#: firewall/models.py:1076 msgid "untagged vlan" msgstr "untagged vlan" -#: firewall/models.py:950 +#: firewall/models.py:1079 msgid "tagged vlans" msgstr "tagged vlanok" -#: firewall/models.py:973 +#: firewall/models.py:1102 msgid "interface" msgstr "interfész" -#: firewall/models.py:974 +#: firewall/models.py:1103 msgid "" "The name of network interface the gateway should serve this network on. For " "example eth2." @@ -3315,24 +3407,24 @@ msgstr "" "Azon hálózati interfész nevve, amelyen az útválasztó ezt a hálózatot " "kiszolgálja. Például eth2." -#: firewall/models.py:979 network/templates/network/switch-port-create.html:8 +#: firewall/models.py:1108 network/templates/network/switch-port-create.html:8 #: network/templates/network/switch-port-edit.html:8 msgid "switch port" msgstr "switch port" -#: firewall/models.py:995 +#: firewall/models.py:1124 msgid "reason" msgstr "indok" -#: firewall/models.py:997 +#: firewall/models.py:1126 msgid "short message" msgstr "rövid üzenet" -#: firewall/models.py:1017 +#: firewall/models.py:1146 msgid "blacklist item" msgstr "tiltólista eleme" -#: firewall/models.py:1018 network/templates/network/blacklist-create.html:8 +#: firewall/models.py:1147 network/templates/network/blacklist-create.html:8 #: network/templates/network/blacklist-edit.html:8 msgid "blacklist" msgstr "tiltólista" @@ -3395,96 +3487,117 @@ msgstr "" #: manager/scheduler.py:49 msgid "" -"No node can satisfy the required traits of the new virtual machine currently." +"No node can satisfy the required traits of the new virtual machine " +"currently." msgstr "" "Egy csomópont sem biztosítja a virtuális gép indításához szükséges " "jellemzőket." -#: network/forms.py:131 +#: network/forms.py:127 +msgid "Generate random address." +msgstr "Véletlenszerű cím generálása." + +#: network/forms.py:130 +msgid "Generate IPv6 pair of IPv4 address." +msgstr "IPv4-es cím IPv6-os párjának generálása." + +#: network/forms.py:135 msgid "Information" msgstr "Információ" -#: network/forms.py:194 +#: network/forms.py:198 msgid "External" msgstr "Külső" -#: network/forms.py:259 +#: network/forms.py:261 +msgid "Generate sensible template." +msgstr "Ésszerű sablon generálása." + +#: network/forms.py:265 msgid "Domain name service" msgstr "DNS szolgáltatás" -#: network/forms.py:264 +#: network/forms.py:270 msgid "Info" msgstr "Infó" -#: network/tables.py:202 +#: network/tables.py:125 network/tables.py:138 +msgid "No hosts." +msgstr "Nincs gép." + +#: network/tables.py:131 +msgid "requested IP" +msgstr "kért IP" + +#: network/tables.py:230 msgid "No records." msgstr "Nincs rekord." -#: network/views.py:104 +#: network/views.py:132 #, python-format msgid "Successfully modified blacklist item%(ipv4)s - %(type)s!" msgstr "Tiltólista eleme sikeresen módosítva (%(ipv4)s %(type)s)." -#: network/views.py:122 +#: network/views.py:150 #, python-format msgid "Successfully created blacklist item %(ipv4)s - %(type)s!" msgstr "Tiltólista eleme sikeresen létrehozva (%(ipv4)s %(type)s)." -#: network/views.py:160 +#: network/views.py:188 #, python-format msgid "Successfully modified domain %(name)s!" msgstr "A(z) %(name)s tartománynév módosításra került." -#: network/views.py:187 +#: network/views.py:215 #, python-format msgid "Successfully created domain %(name)s!" msgstr "A(z) %(name)s tartománynév létrehozásra került." -#: network/views.py:204 network/views.py:442 network/views.py:699 +#: network/views.py:232 network/views.py:507 network/views.py:774 msgid "Object name does not match!" msgstr "Az objektum neve nem egyezik." -#: network/views.py:208 +#: network/views.py:236 msgid "Domain successfully deleted!" msgstr "A tartománynév törlésre került." -#: network/views.py:214 +#: network/views.py:242 msgid "Records from hosts" msgstr "A gépek rekordjai" -#: network/views.py:220 network/templates/network/menu.html:8 +#: network/views.py:248 network/templates/network/menu.html:8 #: network/templates/network/vlan-list.html:7 msgid "Vlans" msgstr "Vlanok" -#: network/views.py:228 network/views.py:714 +#: network/views.py:256 network/views.py:789 #: network/templates/network/host-list.html:7 #: network/templates/network/host-list.html:13 #: network/templates/network/menu.html:5 msgid "Hosts" msgstr "Gépek" -#: network/views.py:271 +#: network/views.py:299 #, python-format msgid "Successfully created host group %(name)s!" msgstr "%(name)s gépcsoport létrehozásra került." -#: network/views.py:279 +#: network/views.py:307 #, python-format msgid "Successfully modified host group %(name)s!" msgstr "%(name)s gépcsoport módosításra került." -#: network/views.py:339 +#: network/views.py:386 #, python-format msgid "Successfully modified host %(hostname)s!" msgstr "%(hostname)s gép módosításra került." -#: network/views.py:410 +#: network/views.py:459 #, python-format msgid "Successfully created host %(hostname)s!" msgstr "%(hostname)s gép létrehozásra került." -#: network/views.py:431 network/views.py:722 +#: network/views.py:496 network/views.py:797 #: network/templates/network/host-edit.html:75 #: network/templates/network/menu.html:14 #: network/templates/network/record-list.html:7 @@ -3492,83 +3605,83 @@ msgstr "%(hostname)s gép létrehozásra került." msgid "Records" msgstr "Rekordok" -#: network/views.py:446 +#: network/views.py:511 msgid "Host successfully deleted!" msgstr "A gép törlésre került." -#: network/views.py:476 +#: network/views.py:541 msgid "Successfully modified record!" msgstr "A rekord módosításra került." -#: network/views.py:495 +#: network/views.py:560 msgid "Successfully created record!" msgstr "A rekord létrehozásra került." -#: network/views.py:546 +#: network/views.py:611 msgid "Successfully modified rule!" msgstr "A szabály módosításra került." -#: network/views.py:566 +#: network/views.py:631 msgid "Successfully created rule!" msgstr "A szabály létrehozásra került." -#: network/views.py:602 +#: network/views.py:667 msgid "Succesfully modified switch port!" msgstr "A switch-port módosításra került." -#: network/views.py:621 +#: network/views.py:686 msgid "Successfully created switch port!" msgstr "A switch-port létrehozásra került." -#: network/views.py:654 +#: network/views.py:733 #, python-format msgid "Succesfully modified vlan %(name)s!" msgstr "A(z) %(name)s vlan módosításra került." -#: network/views.py:678 +#: network/views.py:753 #, python-format msgid "Successfully created vlan %(name)s!" msgstr "A(z) %(name)s vlan létrehozásra került." -#: network/views.py:703 +#: network/views.py:778 msgid "Vlan successfully deleted!" msgstr "A vlan törlésre került." -#: network/views.py:745 +#: network/views.py:820 #, python-format msgid "Successfully modified vlan group %(name)s!" msgstr "A(z) %(name)s vlan-csoport módosításra került." -#: network/views.py:758 +#: network/views.py:833 #, python-format msgid "Successfully created vlan group %(name)s!" msgstr "A(z) %(name)s vlan-csoport módosításra került." -#: network/views.py:790 +#: network/views.py:865 #, python-format msgid "Successfully removed %(host)s from %(group)s group!" msgstr "A(z) %(host)s csoport törlésre került a(z) %(group)s csoportból." -#: network/views.py:806 +#: network/views.py:881 #, python-format msgid "Successfully added %(host)s to group %(group)s!" msgstr "A(z) %(host)s csoport hozzáadásra került a(z) %(group)s csoporthoz." -#: network/views.py:825 +#: network/views.py:900 #, python-format msgid "Successfully deleted ethernet device %(name)s!" msgstr "A(z) %(name)s ethernet-eszköz törlésre került." -#: network/views.py:843 +#: network/views.py:918 #, python-format msgid "Successfully added %(name)s to this switch port" msgstr "%(name)s hozzáadásra került a switch-porthoz." -#: network/views.py:850 +#: network/views.py:925 msgid "Ethernet device name cannot be empty!" msgstr "Az ethernet-eszköz megadása kötelező." -#: network/views.py:853 +#: network/views.py:928 msgid "There is already an ethernet device with that name!" msgstr "Már létezik a megadott nevű ethernet-eszköz." @@ -3652,6 +3765,7 @@ msgstr "Gépcsoportok" #: network/templates/network/host-create.html:12 #: network/templates/network/host-list.html:11 +#: network/templates/network/vlan-edit.html:22 msgid "Create a new host" msgstr "Gép létrehozása" @@ -3818,10 +3932,14 @@ msgstr "Vlan törlése" msgid "details of vlan" msgstr "vlan részletei" -#: network/templates/network/vlan-edit.html:22 +#: network/templates/network/vlan-edit.html:23 msgid "Host list" msgstr "Gépek" +#: network/templates/network/vlan-edit.html:28 +msgid "Unregistered hosts" +msgstr "Regisztrálatlan gépek" + #: network/templates/network/vlan-group-create.html:12 #: network/templates/network/vlan-group-list.html:11 msgid "Create a new vlan group" @@ -3831,10 +3949,9 @@ msgstr "Vlan-csoport létrehozása" msgid "list of all vlans" msgstr "összes vlan" -#: network/templates/network/columns/mac.html:3 -#, python-format -msgid "Vendor: %(vendor)s" -msgstr "Gyártó: %(vendor)s" +#: network/templates/network/columns/host-register.html:3 +msgid "register host" +msgstr "gép regisztrálása" #: network/templates/network/confirm/base_delete.html:8 #, python-format @@ -3929,8 +4046,8 @@ msgid "" "The requested operation can't be performed on disk '%(name)s' because it is " "in use." msgstr "" -"A kért művelet nem hajtható végre a(z) „%(name)s” lemezen, mivel használatban " -"van." +"A kért művelet nem hajtható végre a(z) „%(name)s” lemezen, mivel " +"használatban van." #: storage/models.py:139 #, python-format @@ -3944,11 +4061,11 @@ msgstr "" #: storage/models.py:148 #, python-format msgid "" -"The requested operation can't be performed on disk '%(name)s' because it has " -"never been deployed." +"The requested operation can't be performed on disk '%(name)s' because it has" +" never been deployed." msgstr "" -"A kért művelet nem hajtható végre a(z) „%(name)s” lemezen, mivel nem volt még " -"csatolva." +"A kért művelet nem hajtható végre a(z) „%(name)s” lemezen, mivel nem volt " +"még csatolva." #: storage/models.py:152 #, python-format @@ -3972,8 +4089,8 @@ msgstr "" #, python-format msgid "" "The requested operation can't be performed on disk '%(name)s' (%(pk)s) " -"[%(filename)s] because its base '%(b_name)s' (%(b_pk)s) [%(b_filename)s] has " -"never beendeployed." +"[%(filename)s] because its base '%(b_name)s' (%(b_pk)s) [%(b_filename)s] has" +" never beendeployed." msgstr "" "A kért művelet nem hajtható végre a(z) „%(name)s” (%(pk)s) [%(filename)s] " "lemezen, mivel az alapja, „%(b_name)s” (%(b_pk)s) [%(b_filename)s] nem " @@ -4016,49 +4133,41 @@ msgid "" msgstr "" "\n" " Ez a CIRCLE\n" -" Cloud szoftver egy telepítése. A CIRCLE egy szabad, nyílt " -"forrású felhőmenedzser.\n" +" Cloud szoftver egy telepítése. A CIRCLE egy szabad, nyílt forrású felhőmenedzser.\n" " " #: templates/info/help.html:20 msgid "" "\n" -" Its most important function is starting and managing virtual " -"machine\n" +" Its most important function is starting and managing virtual machine\n" " instances based on templates.\n" " These templates are also easy to create.\n" " " msgstr "" "\n" -"Legfontosabb funkciója a virtuális gépek indítása és kezelése könnyen " -"létrehozható sablonok alapján." +"Legfontosabb funkciója a virtuális gépek indítása és kezelése könnyen létrehozható sablonok alapján." #: templates/info/help.html:26 msgid "" "\n" -" Apart from this tutorial we recommend to try the system, it is " -"quite\n" +" Apart from this tutorial we recommend to try the system, it is quite\n" " intuitive, and the web interface shows detailed instructions on\n" " advanced options.\n" " " msgstr "" "\n" -"Ezen az útmutatón kívül javasoljuk, hogy próbálja ki a rendszert, amelynek " -"használata magától értetődő. A webes felületen részletes útmutatást talál a " -"haladó lehetőségekről." +"Ezen az útmutatón kívül javasoljuk, hogy próbálja ki a rendszert, amelynek használata magától értetődő. A webes felületen részletes útmutatást talál a haladó lehetőségekről." #: templates/info/help.html:34 #, python-format msgid "" "\n" -" You can reach this service at https://%(host)s/ where you " -"can log in\n" +" You can reach this service at https://%(host)s/ where you can log in\n" " to the dashboard.\n" " " msgstr "" "\n" -"A szolgáltatást a https://%(host)s/ címen érheti el. Itt " -"bejelentkezhet az irányítópultra." +"A szolgáltatást a https://%(host)s/ címen érheti el. Itt bejelentkezhet az irányítópultra." #: templates/info/help.html:39 msgid "" @@ -4069,8 +4178,7 @@ msgid "" " " msgstr "" "\n" -"Az irányítópult összefoglalja a virtuális gépeket és más erőforrásokat. Ez a " -"kiindulópont a rendszer lehetőségeinek eléréséhez." +"Az irányítópult összefoglalja a virtuális gépeket és más erőforrásokat. Ez a kiindulópont a rendszer lehetőségeinek eléréséhez." #: templates/info/help.html:49 msgid "Sorry, you have no permission to launch virtual machines." @@ -4088,10 +4196,7 @@ msgid "" " " msgstr "" "\n" -"A virtuális gépek dobozban találja legutóbbi virtuális gépeit. Egy " -"összefoglaló nézet is elérhető az műszer gombra () kattintva. Kattintson a virtuális gép nevére a kapcsolódási adatok, " -"beállítások megtekintéséhez, vagy az állapotának megváltoztatásához." +"A virtuális gépek dobozban találja legutóbbi virtuális gépeit. Egy összefoglaló nézet is elérhető az műszer gombra () kattintva. Kattintson a virtuális gép nevére a kapcsolódási adatok, beállítások megtekintéséhez, vagy az állapotának megváltoztatásához." #: templates/info/help.html:61 msgid "" @@ -4107,32 +4212,22 @@ msgid "" " " msgstr "" "\n" -"A fontos vagy gyakran használt gépeket megjelölheti kedvencként (). A keresés mező inkrementálisan mutatja az " -"eredményeket, beküldésével (⏎) közvetlenül a megtalált gépre ugrik, ha " -"pontosan egy találat van. Új virtuális gépeket az új " -"gombra kattintva, majd a sablont kiválasztva indíthat. " +"A fontos vagy gyakran használt gépeket megjelölheti kedvencként (). A keresés mező inkrementálisan mutatja az eredményeket, beküldésével (⏎) közvetlenül a megtalált gépre ugrik, ha pontosan egy találat van. Új virtuális gépeket az új gombra kattintva, majd a sablont kiválasztva indíthat. " #: templates/info/help.html:72 msgid "" "\n" " If you select a virtual machine, you get to a page with all the\n" -" details and operations listed. On the left, you will see the " -"state\n" +" details and operations listed. On the left, you will see the state\n" " of the machine and a summary about how you can\n" " connect to the\n" " machine.\n" -" In the middle there is a tabbed pane, which contains details " -"about\n" +" In the middle there is a tabbed pane, which contains details about\n" " the machine in categories.\n" " " msgstr "" "\n" -"Ha kiválaszt egy virtuális gépet, a gép adatait és műveleteit elérhetővé " -"tévő oldalra jut. Baloldalt a gép állapotát és a csatlakozáshoz szükséges adatokat találja. Középen egy több lapból álló panel van, " -"amely a gép összes részletét kategorizálva mutatja be." +"Ha kiválaszt egy virtuális gépet, a gép adatait és műveleteit elérhetővé tévő oldalra jut. Baloldalt a gép állapotát és a csatlakozáshoz szükséges adatokat találja. Középen egy több lapból álló panel van, amely a gép összes részletét kategorizálva mutatja be." #: templates/info/help.html:81 msgid "" @@ -4143,14 +4238,12 @@ msgid "" " " msgstr "" "\n" -"A jobb felső sarokban a műveleteket tartalmazó eszköztár található a gép " -"életciklusát befolyásoló, legfontosabb műveletekkel." +"A jobb felső sarokban a műveleteket tartalmazó eszköztár található a gép életciklusát befolyásoló, legfontosabb műveletekkel." #: templates/info/help.html:87 msgid "" "\n" -" The tool buttons are color coded by their effect, and enabled/" -"disabled\n" +" The tool buttons are color coded by their effect, and enabled/disabled\n" " based on the current state of the machine.\n" " The recommended operation is always the biggest tool button with\n" " the name displayed.\n" @@ -4159,11 +4252,7 @@ msgid "" " " msgstr "" "\n" -"Az eszköztár gombjai színkódoltak a hatásuk szerint, valamint a gép " -"állapotától függően kerülnek engedélyezésre/tiltásra. Az ajánlott művelet " -"gombja a legnagyobb, amelyen szerepel az adott művelet megnevezése is. " -"Nyugodtan rákattinthat a gombokra, a megerősítő ablak részletesen bemutatja " -"az egyes műveleteket." +"Az eszköztár gombjai színkódoltak a hatásuk szerint, valamint a gép állapotától függően kerülnek engedélyezésre/tiltásra. Az ajánlott művelet gombja a legnagyobb, amelyen szerepel az adott művelet megnevezése is. Nyugodtan rákattinthat a gombokra, a megerősítő ablak részletesen bemutatja az egyes műveleteket." #: templates/info/help.html:96 msgid "" @@ -4181,29 +4270,18 @@ msgid "" " " msgstr "" "\n" -"A Kezdőoldal lap " -"statisztikát mutat be a gép működéséről, valamint itt változtathatja meg a " -"gép nevét, leírását és címkéit. Kifejezetten ajánljuk a leírás kitöltését, " -"amely megkönnyíti a felhő üzemeltetőinek dolgát karbantartás esetén. Itt " -"található a lejárati idők összefoglalása is. Minden " -"virtuális gépnek van egy-egy határideje, amikor felfüggesztésre és amikor " -"törlésre kerül. Ez előre megadott bérlési módok szerint kerül beállításra. A " -"megújítás gomb segítségével ezeket a határidőket frissítheti. Természetesen " -"értesítjük, ha egy gépe a lejárathoz közeledik." +"A Kezdőoldal lap statisztikát mutat be a gép működéséről, valamint itt változtathatja meg a gép nevét, leírását és címkéit. Kifejezetten ajánljuk a leírás kitöltését, amely megkönnyíti a felhő üzemeltetőinek dolgát karbantartás esetén. Itt található a lejárati idők összefoglalása is. Minden virtuális gépnek van egy-egy határideje, amikor felfüggesztésre és amikor törlésre kerül. Ez előre megadott bérlési módok szerint kerül beállításra. A megújítás gomb segítségével ezeket a határidőket frissítheti. Természetesen értesítjük, ha egy gépe a lejárathoz közeledik." #: templates/info/help.html:109 msgid "" "\n" -" Resources pane " -"shows\n" +" Resources pane shows\n" " details about how much memory and CPU the VM has, and how is it\n" " scheduled.\n" " " msgstr "" "\n" -"Az Erőforrások lap " -"bemutatja, hogy a virtuális gép mennyi CPU-val és memóriával rendelkezik, " -"valamint milyen az ütemezése. " +"Az Erőforrások lap bemutatja, hogy a virtuális gép mennyi CPU-val és memóriával rendelkezik, valamint milyen az ütemezése. " #: templates/info/help.html:115 msgid "" @@ -4212,22 +4290,18 @@ msgid "" " the machine is stopped." msgstr "" "\n" -"A megfelelő jogosultsággal rendelkező felhasználók megváltoztathatják ezeket " -"a beállításokat, ha a gépet leállították." +"A megfelelő jogosultsággal rendelkező felhasználók megváltoztathatják ezeket a beállításokat, ha a gépet leállították." #: templates/info/help.html:119 msgid "" "\n" -" Console pane " -"allows\n" +" Console pane allows\n" " to see the console of the virutal machine for troubleshooting and\n" " operating system installation." msgstr "" "\n" "A\n" -" Konzol lap " -"lehetővé teszi a virtuális gépek hibaelhárítását és az operációs rendszer " -"telepítését." +" Konzol lap lehetővé teszi a virtuális gépek hibaelhárítását és az operációs rendszer telepítését." #: templates/info/help.html:124 msgid "You can also use the keyboard and mouse." @@ -4260,10 +4334,7 @@ msgid "" " " msgstr "" "\n" -"A Hozzáférés lap a gép " -"megosztását és a tulajdon átruházását teszi lehetővé. A gép felhasználói " -"láthatják a gép részleteit, az operátorok használhatják a legtöbb műveletet, " -"a tulajdonosok törölhetik is a gépet." +"A Hozzáférés lap a gép megosztását és a tulajdon átruházását teszi lehetővé. A gép felhasználói láthatják a gép részleteit, az operátorok használhatják a legtöbb műveletet, a tulajdonosok törölhetik is a gépet." #: templates/info/help.html:140 msgid "" @@ -4276,27 +4347,20 @@ msgid "" msgstr "" "\n" "A\n" -" Hálózat lap a " -"virtuális gép hálózati kapcsolatait mutatja be. Lehetőség van interfészek " -"hozzáadására és törlésére, valamint a különböző TCP/UDP portok távoli " -"elérését is itt lehet engedélyezni." +" Hálózat lap a virtuális gép hálózati kapcsolatait mutatja be. Lehetőség van interfészek hozzáadására és törlésére, valamint a különböző TCP/UDP portok távoli elérését is itt lehet engedélyezni." #: templates/info/help.html:147 msgid "" "\n" -" Activity pane " -"shows\n" +" Activity pane shows\n" " the full life history of the virtual machine. This is where you\n" -" can see the causes of failed actions (just point the mouse to the " -"name of\n" +" can see the causes of failed actions (just point the mouse to the name of\n" " the action).\n" " " msgstr "" "\n" "A \n" -" Tevékenységek " -"lapon látszik a virtuális gép teljes élettörténete. Itt lehet a műveletek " -"meghiúsulásának okait is megtekinteni (húzza az egeret a művelet nevére)." +" Tevékenységek lapon látszik a virtuális gép teljes élettörténete. Itt lehet a műveletek meghiúsulásának okait is megtekinteni (húzza az egeret a művelet nevére)." #: templates/info/help.html:159 msgid "Sorry, you have no permission to create templates." @@ -4312,37 +4376,30 @@ msgid "" " " msgstr "" "\n" -"A sablonok a virtuálisgép-példányok prototípusai, " -"megadják a létrehozandó VM különböző technikai beállításait, beleértve a " -"hálózati interfészeket és a csatolandó lemezeket." +"A sablonok a virtuálisgép-példányok prototípusai, megadják a létrehozandó VM különböző technikai beállításait, beleértve a hálózati interfészeket és a csatolandó lemezeket." #: templates/info/help.html:170 msgid "" "\n" " In the dashboard box you see your own templates and those, for\n" -" which you have operator permission. This means that you " -"can\n" +" which you have operator permission. This means that you can\n" " share them with your groups or other users.\n" " " msgstr "" "\n" -"Az irányítópulti dobozban a saját sablonait, valamint azokat látja, " -"amelyekhez legalább operátor jogosultsága van. Ez azt jelenti, hogy " -"megoszthatja őket csoportjaival vagy egyes felhasználókkal." +"Az irányítópulti dobozban a saját sablonait, valamint azokat látja, amelyekhez legalább operátor jogosultsága van. Ez azt jelenti, hogy megoszthatja őket csoportjaival vagy egyes felhasználókkal." #: templates/info/help.html:176 msgid "" "\n" " You can create templates from any virtual machine with the\n" -" \n" +" \n" " save as template\n" " button.\n" " " msgstr "" "\n" -" Bármely virtuális gépből létrehozhat sablont a \n" +" Bármely virtuális gépből létrehozhat sablont a \n" " mentés sablonként\n" " gomb segítségével.\n" " " @@ -4357,9 +4414,7 @@ msgid "" " " msgstr "" "\n" -"Ezen felül a sablonok dobozban lévő új gombbal is elindíthat " -"egy sablonkészítő varázslót." +"Ezen felül a sablonok dobozban lévő új gombbal is elindíthat egy sablonkészítő varázslót." #: templates/info/help.html:195 msgid "Sorry, you have no permission to create groups." @@ -4373,8 +4428,7 @@ msgid "" " " msgstr "" "\n" -"A csoportok a jogosultságkezelés epítőelemei. Az irányítópulton azon " -"csoportokat látja, amelykhez hozzáférése van." +"A csoportok a jogosultságkezelés epítőelemei. Az irányítópulton azon csoportokat látja, amelykhez hozzáférése van." #: templates/info/help.html:204 msgid "" @@ -4386,15 +4440,12 @@ msgid "" " " msgstr "" "\n" -"Saját csoportokat is létrehozhat a csoportok dobozban lévő új " -"gombbal." +"Saját csoportokat is létrehozhat a csoportok dobozban lévő új gombbal." #: templates/info/help.html:211 msgid "" "\n" -" Users logged in with SSO authentication can automatically " -"become\n" +" Users logged in with SSO authentication can automatically become\n" " members of groups based on its organizational identifier.\n" " Those who are administrators of an organizational group (or a\n" " professor of a subject in academics) can create groups with the\n" @@ -4403,11 +4454,7 @@ msgid "" " " msgstr "" "\n" -"SSO azonosítással belépett felhasználók automatikusan tagjai lehetnek " -"csoportoknak a szervezeti azonosítójuk alapján. Aki adminisztrátorai egy " -"csoportnak (vagy oktatói egy tantárgynak az akadémiai szférában) olyan " -"csoportokat is létrehozhatnak, amelyeknek a tagjai bejelentkezéskor " -"automatikusan bekerülnek." +"SSO azonosítással belépett felhasználók automatikusan tagjai lehetnek csoportoknak a szervezeti azonosítójuk alapján. Aki adminisztrátorai egy csoportnak (vagy oktatói egy tantárgynak az akadémiai szférában) olyan csoportokat is létrehozhatnak, amelyeknek a tagjai bejelentkezéskor automatikusan bekerülnek." #: templates/info/help.html:219 msgid "" @@ -4417,8 +4464,7 @@ msgid "" " " msgstr "" "\n" -"Azonosítójuk alapján is hozzáadhat felhasználókat, akkor is, ha még nem " -"léptek be a rendszerbe." +"Azonosítójuk alapján is hozzáadhat felhasználókat, akkor is, ha még nem léptek be a rendszerbe." #: templates/info/help.html:230 msgid "Sorry, this deployment of CIRCLE does not support file store." @@ -4427,14 +4473,12 @@ msgstr "Ez a CIRCLE-telepítés nem támogatja a tárhelyet." #: templates/info/help.html:234 msgid "" "\n" -" Each user has a simple personal file store, which is the " -"easiest\n" +" Each user has a simple personal file store, which is the easiest\n" " way to keep and retrieve your work done on virtual machines.\n" " " msgstr "" "\n" -"Minden felhasználónak van egy személyes tárhelye, ami a egyszerű módot ad a " -"virtuális gépeken elkészített munka tárolására és letöltésére." +"Minden felhasználónak van egy személyes tárhelye, ami a egyszerű módot ad a virtuális gépeken elkészített munka tárolására és letöltésére." #: templates/info/help.html:239 msgid "" @@ -4451,12 +4495,7 @@ msgid "" " " msgstr "" "\n" -"Fájljait a webes felületről és a virtuális gépekről is eléri. A webes " -"felület olyan, mint bármelyik fájlböngésző. A virtuális gépek alapesetben " -"nem kapják meg a tárhely eléréséhez szükséges azonosítókat elkerülendő " -"megosztásukat a gép esetleges többi használójával. A tárhely használatához " -"nyomja meg a tárhely csatolása gombot a virtuális gépen." +"Fájljait a webes felületről és a virtuális gépekről is eléri. A webes felület olyan, mint bármelyik fájlböngésző. A virtuális gépek alapesetben nem kapják meg a tárhely eléréséhez szükséges azonosítókat elkerülendő megosztásukat a gép esetleges többi használójával. A tárhely használatához nyomja meg a tárhely csatolása gombot a virtuális gépen." #: templates/info/help.html:251 msgid "" @@ -4470,13 +4509,11 @@ msgstr "" msgid "" "\n" " CIRCLE Cloud is a complete and open source cloud solution \n" -" that can be deployed with minimal effort on a single computer as " -"well as on a larger cluster.\n" +" that can be deployed with minimal effort on a single computer as well as on a larger cluster.\n" " " msgstr "" "\n" -"A CIRCLE Cloud egy teljeskörű nyílt forrású felhőmegoldás, amely könnyen " -"telepíthető egy gépre, vagy akár egy nagyobb fürtre." +"A CIRCLE Cloud egy teljeskörű nyílt forrású felhőmegoldás, amely könnyen telepíthető egy gépre, vagy akár egy nagyobb fürtre." #: templates/info/legal.html:23 #, python-format @@ -4505,10 +4542,8 @@ msgstr "" #: templates/info/policy.html:22 msgid "" " \n" -" Every virtual machine has an expiration date, when this date is " -"reached\n" -" the machine will be stopped, if the user doesn't renew the " -"machine\n" +" Every virtual machine has an expiration date, when this date is reached\n" +" the machine will be stopped, if the user doesn't renew the machine\n" " it will be deleted and all data on it will be lost.\n" " " msgstr "" @@ -4519,41 +4554,32 @@ msgstr "" msgid "" "\n" " Running the the virtual machine safely and \n" -" updating the operating system is the responsibility of the " -"user.\n" +" updating the operating system is the responsibility of the user.\n" " " msgstr "" "\n" -"A virtuális gépek biztonságos üzemeltetése, a rajtuk futó szoftverek " -"frissítése a felhasználó felelőssége." +"A virtuális gépek biztonságos üzemeltetése, a rajtuk futó szoftverek frissítése a felhasználó felelőssége." #: templates/info/policy.html:41 msgid "" "\n" -" You can connect to the running virtual machines the usual way: " -"for Windows machines\n" -" this mean RDP (remote desktop), Linux machines can be accessed " -"either via SSH\n" +" You can connect to the running virtual machines the usual way: for Windows machines\n" +" this mean RDP (remote desktop), Linux machines can be accessed either via SSH\n" " or NoMachine NX (GUI).\n" " " msgstr "" "\n" -"A gépekhez az adott operációs rendszeren szokásos módon csatlakozhat: Window " -"alatt RDP-vel (távoli asztali kapcsolat), Linuxot futtató gépekhez SSH-val " -"vagy grafikusan a NoMachine NX rendszerrel." +"A gépekhez az adott operációs rendszeren szokásos módon csatlakozhat: Window alatt RDP-vel (távoli asztali kapcsolat), Linuxot futtató gépekhez SSH-val vagy grafikusan a NoMachine NX rendszerrel." #: templates/info/support.html:14 msgid "" "\n" -" CIRCLE Cloud is an open source cloud solution. If you notice any " -"bugs or\n" -" you have an idea for a feature please contact the maintainer of the " -"site.\n" +" CIRCLE Cloud is an open source cloud solution. If you notice any bugs or\n" +" you have an idea for a feature please contact the maintainer of the site.\n" " " msgstr "" "\n" -"A CIRCLE Cloud egy nyílt forrású felhőmegoldás. Amennyiben hibát tapasztal, " -"vagy fejlesztési javaslata van, keresse meg a szolgáltatás üzemeltetőjét." +"A CIRCLE Cloud egy nyílt forrású felhőmegoldás. Amennyiben hibát tapasztal, vagy fejlesztési javaslata van, keresse meg a szolgáltatás üzemeltetőjét." #: templates/registration/login.html:6 msgid "Login" @@ -4590,8 +4616,7 @@ msgstr "Megerősítés jelszó-visszaállításról" #: templates/registration/password_reset_confirm.html:15 msgid "" "\n" -" Please enter your new password twice so we can verify you typed it in " -"correctly.\n" +" Please enter your new password twice so we can verify you typed it in correctly.\n" " " msgstr "" "\n" @@ -4601,8 +4626,8 @@ msgstr "" #: templates/registration/password_reset_confirm.html:25 #, python-format msgid "" -"This token is expired, please request a new password " -"reset link again." +"This token is expired, please request a new password" +" reset link again." msgstr "" "A token lejárt, igényeljen új jelszó-visszaállítást." @@ -4676,8 +4701,7 @@ msgid "" "Resize the virtual disk image. Size must be greater value than the actual " "size." msgstr "" -"Virtuális lemezkép átméretezése. Az új méret meg kell haladja " -"a jelenlegit." +"Virtuális lemezkép átméretezése. Az új méret meg kell haladja a jelenlegit." #: vm/operations.py:298 #, python-format @@ -4725,11 +4749,11 @@ msgstr "" msgid "virtual machine successfully deployed to node: %(node)s" msgstr "a virtuális gép sikeresen elindítva a következő csomóponton: %(node)s" -#: vm/operations.py:388 vm/operations.py:563 vm/operations.py:889 +#: vm/operations.py:388 vm/operations.py:563 vm/operations.py:929 msgid "deploy network" msgstr "hálózati kapcsolat létrehozása" -#: vm/operations.py:400 vm/operations.py:581 vm/operations.py:645 +#: vm/operations.py:400 vm/operations.py:581 vm/operations.py:680 msgid "wait operating system loading" msgstr "várakozás az operációs rendszer betöltésére" @@ -4812,7 +4836,7 @@ msgstr "ütemezés" msgid "migrate to %(node)s" msgstr "migrálás %(node)s csomópontra" -#: vm/operations.py:553 vm/operations.py:838 +#: vm/operations.py:553 vm/operations.py:878 msgid "shutdown network" msgstr "hálózati kapcsolat leállítása" @@ -4824,7 +4848,8 @@ msgstr "újraindítás" msgid "" "Warm reboot virtual machine by sending Ctrl+Alt+Del signal to its console." msgstr "" -"Virtuális gép újraindítása a konzoljára a Ctrl+Alt+Del kombináció küldésével." +"Virtuális gép újraindítása a konzoljára a Ctrl+Alt+Del kombináció " +"küldésével." #: vm/operations.py:587 msgid "remove interface" @@ -4844,55 +4869,81 @@ msgid "remove %(vlan)s interface" msgstr "%(vlan)s interfész törlése" #: vm/operations.py:611 +msgid "close port" +msgstr "port bezárása" + +#: vm/operations.py:612 +msgid "Close the specified port." +msgstr "A megadott port bezárása." + +#: vm/operations.py:621 +#, python-format +msgid "close %(proto)s/%(port)d on %(host)s" +msgstr "%(proto)s/%(port)d bezárása ezen: %(host)s" + +#: vm/operations.py:629 +msgid "open port" +msgstr "port nyitása" + +#: vm/operations.py:630 +msgid "Open the specified port." +msgstr "A megadott port kinyitása." + +#: vm/operations.py:639 +#, python-format +msgid "open %(proto)s/%(port)d on %(host)s" +msgstr "%(proto)s/%(port)d kinyitása ezen: %(host)s" + +#: vm/operations.py:646 msgid "remove disk" msgstr "lemez eltávolítása" -#: vm/operations.py:612 +#: vm/operations.py:647 msgid "" "Remove the specified disk from the virtual machine, and destroy the data." msgstr "A megadott lemez eltávolítása a virtuális gépből és az adat törlése." -#: vm/operations.py:622 +#: vm/operations.py:657 msgid "destroy disk" msgstr "lemez megsemmisítése" -#: vm/operations.py:628 +#: vm/operations.py:663 #, python-format msgid "remove disk %(name)s" msgstr "%(name)s lemez eltávolítása" -#: vm/operations.py:635 vm/operations.py:1041 +#: vm/operations.py:670 vm/operations.py:1081 msgid "reset" msgstr "reset" -#: vm/operations.py:636 +#: vm/operations.py:671 msgid "Cold reboot virtual machine (power cycle)." msgstr "Virtuális gép hideg újraindítása (hálózati tápellátás megszakítása)." -#: vm/operations.py:651 +#: vm/operations.py:686 msgid "save as template" msgstr "mentés sablonként" -#: vm/operations.py:652 +#: vm/operations.py:687 msgid "" "Save virtual machine as a template so they can be shared with users and " "groups. Anyone who has access to a template (and to the networks it uses) " "will be able to start an instance of it." msgstr "" "Virtuális gép mentése sablonként, amelyet meg lehet osztani más " -"felhasználókkal és csoportokkal. Mindenki, aki hozzáférést kap egy sablonhoz " -"(és az általa használt hálózatokhoz), képes lesz egy példányát elindítani." +"felhasználókkal és csoportokkal. Mindenki, aki hozzáférést kap egy sablonhoz" +" (és az általa használt hálózatokhoz), képes lesz egy példányát elindítani." -#: vm/operations.py:728 +#: vm/operations.py:763 #, python-format msgid "saving disk %(name)s" msgstr "%(name)s lemez mentése" -#: vm/operations.py:755 +#: vm/operations.py:795 msgid "shutdown" msgstr "leállítás" -#: vm/operations.py:756 +#: vm/operations.py:796 msgid "" "Try to halt virtual machine by a standard ACPI signal, allowing the " "operating system to keep a consistent state. The operation will fail if the " @@ -4902,62 +4953,62 @@ msgstr "" "operációs rendszer számár a szabályos leállást. A művelet meghiúsul, ha a " "gép nem áll le." -#: vm/operations.py:775 +#: vm/operations.py:815 msgid "" "The virtual machine did not switch off in the provided time limit. Most of " "the time this is caused by incorrect ACPI settings. You can also try to " "power off the machine from the operating system manually." msgstr "" -"A virtuális gép nem állt le a biztosított időkorlát alatt. A legtöbb esetben " -"ez a nem megfelelő ACPI beállítások miatt van. Megpróbálhatja a gépet az " +"A virtuális gép nem állt le a biztosított időkorlát alatt. A legtöbb esetben" +" ez a nem megfelelő ACPI beállítások miatt van. Megpróbálhatja a gépet az " "operációs rendszerből, kézzel leállítani." -#: vm/operations.py:787 +#: vm/operations.py:827 msgid "shut off" msgstr "kikapcsolás" -#: vm/operations.py:788 +#: vm/operations.py:828 msgid "" -"Forcibly halt a virtual machine without notifying the operating system. This " -"operation will even work in cases when shutdown does not, but the operating " -"system and the file systems are likely to be in an inconsistent state, so " +"Forcibly halt a virtual machine without notifying the operating system. This" +" operation will even work in cases when shutdown does not, but the operating" +" system and the file systems are likely to be in an inconsistent state, so " "data loss is also possible. The effect of this operation is the same as " "interrupting the power supply of a physical machine." msgstr "" -"Virtuális gép erőltetett leállítása az operációs rendszer értesítése nélkül. " -"Ez a művelet akkor is működik, ha a normál leállítás nem, de az operációs " -"rendszer és a fájlrendszer sérülhet, adatvesztés történhet. A művelet hatása " -"hasonló, mint egy fizikai gép tápellátásának megszüntetése." +"Virtuális gép erőltetett leállítása az operációs rendszer értesítése nélkül." +" Ez a művelet akkor is működik, ha a normál leállítás nem, de az operációs " +"rendszer és a fájlrendszer sérülhet, adatvesztés történhet. A művelet hatása" +" hasonló, mint egy fizikai gép tápellátásának megszüntetése." -#: vm/operations.py:811 +#: vm/operations.py:851 msgid "sleep" msgstr "altatás" -#: vm/operations.py:812 +#: vm/operations.py:852 msgid "" -"Suspend virtual machine. This means the machine is stopped and its memory is " -"saved to disk, so if the machine is waked up, all the applications will keep " -"running. Most of the applications will be able to continue even after a long " -"suspension, but those which need a continous network connection may fail " -"when resumed. In the meantime, the machine will only use storage resources, " -"and keep network resources allocated." +"Suspend virtual machine. This means the machine is stopped and its memory is" +" saved to disk, so if the machine is waked up, all the applications will " +"keep running. Most of the applications will be able to continue even after a" +" long suspension, but those which need a continous network connection may " +"fail when resumed. In the meantime, the machine will only use storage " +"resources, and keep network resources allocated." msgstr "" "Virtuális gép felfüggesztése. A virtuális gép megállításra, memóriája " "lemezre mentésre kerül. Így a gép ébresztése után minden futó alkalmazás " "folytatódik. A legtöbb alkalmazás elviseli akár a hosszabb idejű " "felfüggesztést, azonban a folyamatos hálózati kapcsolatot igénylő programok " -"megállhatnak visszaállítás után. A felfüggesztés ideje alatt a virtuális gép " -"csak tárterületet és hálózati erőforrásokat foglal." +"megállhatnak visszaállítás után. A felfüggesztés ideje alatt a virtuális gép" +" csak tárterületet és hálózati erőforrásokat foglal." -#: vm/operations.py:846 +#: vm/operations.py:886 msgid "suspend virtual machine" msgstr "virtuális gép felfüggesztése" -#: vm/operations.py:860 +#: vm/operations.py:900 msgid "wake up" msgstr "virtuális gép ébresztése" -#: vm/operations.py:861 +#: vm/operations.py:901 msgid "" "Wake up sleeping (suspended) virtual machine. This will load the saved " "memory of the system and start the virtual machine from this state." @@ -4965,25 +5016,25 @@ msgstr "" "Alvó (felfüggesztett) gép ébresztése: az elmentett memóriatartalom " "visszatöltése és a virtuális gép indítása ebből a mentett állapotból." -#: vm/operations.py:900 +#: vm/operations.py:940 msgid "resume virtual machine" msgstr "virtuális gép ébresztése" -#: vm/operations.py:914 +#: vm/operations.py:954 msgid "renew" msgstr "megújítás" -#: vm/operations.py:915 +#: vm/operations.py:955 msgid "" "Virtual machines are suspended and destroyed after they expire. This " "operation renews expiration times according to the lease type. If the " "machine is close to the expiration, its owner will be notified." msgstr "" -"A virtuális gépek lejáratuk után felfüggesztésre, majd törlésre kerülnek. Ez " -"a művelet megújítja a bérletet a kiválasztott típusnak megfelelően. Ha egy " +"A virtuális gépek lejáratuk után felfüggesztésre, majd törlésre kerülnek. Ez" +" a művelet megújítja a bérletet a kiválasztott típusnak megfelelően. Ha egy " "gép közeledik a lejárathoz, a tulajdonost értesítjük." -#: vm/operations.py:928 +#: vm/operations.py:968 msgid "" "Renewing the machine with the selected lease would result in its suspension " "time get earlier than before." @@ -4991,25 +5042,25 @@ msgstr "" "A gép megújítása a kiválasztott bérleti mód mellett a felfüggesztési időt " "korábbra állította volna, mint a jelenlegi érték." -#: vm/operations.py:933 +#: vm/operations.py:973 msgid "" -"Renewing the machine with the selected lease would result in its delete time " -"get earlier than before." +"Renewing the machine with the selected lease would result in its delete time" +" get earlier than before." msgstr "" "A gép megújítása a kiválasztott bérleti mód mellett a törlési időt korábbra " "állította volna, mint a jelenlegi érték." -#: vm/operations.py:941 +#: vm/operations.py:981 #, python-format msgid "Renewed to suspend at %(suspend)s and destroy at %(delete)s." msgstr "" "Megújítás után felfüggesztés ideje: %(suspend)s, a törlésé: %(delete)s." -#: vm/operations.py:948 +#: vm/operations.py:988 msgid "emergency state change" msgstr "vész-állapotváltás" -#: vm/operations.py:949 +#: vm/operations.py:989 msgid "" "Change the virtual machine state to NOSTATE. This should only be used if " "manual intervention was needed in the virtualization layer, and the machine " @@ -5020,101 +5071,102 @@ msgstr "" "rétegben, és úgy szeretné a gépet újból elindítani, hogy ne vesszenek el " "lemezei vagy hálózati erőforrásai." -#: vm/operations.py:962 +#: vm/operations.py:1002 msgid "Activity is forcibly interrupted." msgstr "A tevékenység erőszakos megszakításra került." -#: vm/operations.py:977 +#: vm/operations.py:1017 msgid "redeploy" msgstr "újbóli létrehozás" -#: vm/operations.py:978 +#: vm/operations.py:1018 msgid "" "Change the virtual machine state to NOSTATE and redeploy the VM. This " "operation allows starting machines formerly running on a failed node." msgstr "" "A virtuális gép állapotának átállítása NOSTATE-re, majd a VM újbóli " -"létrehozása. " -"Ez a művelet lehetővé teszi olyan gépek elindítását, amelyek korábban egy " -"meghibásodott csomóponton futnak." +"létrehozása. Ez a művelet lehetővé teszi olyan gépek elindítását, amelyek " +"korábban egy meghibásodott csomóponton futnak." -#: vm/operations.py:1014 +#: vm/operations.py:1054 msgid "You cannot call this operation on an offline node." msgstr "Nem hívható ez a művelet elérhetetlen csomópontra." -#: vm/operations.py:1042 +#: vm/operations.py:1082 msgid "Disable missing node and redeploy all instances on other ones." msgstr "Hiányzó csomópont letiltása és az összes példány elindítása a többin." -#: vm/operations.py:1052 +#: vm/operations.py:1092 msgid "You cannot reset a disabled or online node." msgstr "Tiltott vagy elérhető csomópont resetelése nem lehetséges." -#: vm/operations.py:1060 vm/operations.py:1080 +#: vm/operations.py:1100 vm/operations.py:1120 #, python-format msgid "migrate %(instance)s (%(pk)s)" msgstr "%(instance)s (%(pk)s) migrálása" -#: vm/operations.py:1069 +#: vm/operations.py:1109 msgid "flush" msgstr "ürítés" -#: vm/operations.py:1070 +#: vm/operations.py:1110 msgid "Passivate node and move all instances to other ones." msgstr "" "A csomópont passzívra állítása és az összes példány másikakra mozgatása." -#: vm/operations.py:1089 +#: vm/operations.py:1129 msgid "activate" msgstr "aktiválás" -#: vm/operations.py:1090 +#: vm/operations.py:1130 msgid "" -"Make node active, i.e. scheduler is allowed to deploy virtual machines to it." -msgstr "Csomópont aktívvá tétele: az ütemező indíthat virtuális gépeket rajta." +"Make node active, i.e. scheduler is allowed to deploy virtual machines to " +"it." +msgstr "" +"Csomópont aktívvá tétele: az ütemező indíthat virtuális gépeket rajta." -#: vm/operations.py:1098 +#: vm/operations.py:1138 msgid "You cannot activate an active node." msgstr "Aktív csomópont aktiválása nem lehetséges." -#: vm/operations.py:1109 +#: vm/operations.py:1150 msgid "passivate" msgstr "passziválás" -#: vm/operations.py:1110 +#: vm/operations.py:1151 msgid "" "Make node passive, i.e. scheduler is denied to deploy virtual machines to " "it, but remaining instances and the ones manually migrated will continue " "running." msgstr "" -"Csomópont passzívvá tétele: az ütemező nem indíthat rajta virtuális gépeket, " -"azonban a megmaradt példányok és a kézzel idemigráltak tovább működnek." +"Csomópont passzívvá tétele: az ütemező nem indíthat rajta virtuális gépeket," +" azonban a megmaradt példányok és a kézzel idemigráltak tovább működnek." -#: vm/operations.py:1118 +#: vm/operations.py:1159 msgid "You cannot passivate a passive node." msgstr "Passzív csomópont passziválása nem lehetséges." -#: vm/operations.py:1130 +#: vm/operations.py:1172 msgid "disable" msgstr "tiltás" -#: vm/operations.py:1131 +#: vm/operations.py:1173 msgid "Disable node." msgstr "Csomópont tiltása." -#: vm/operations.py:1138 +#: vm/operations.py:1180 msgid "You cannot disable a disabled node." msgstr "Tiltott csomópont tiltása nem lehetséges." -#: vm/operations.py:1141 +#: vm/operations.py:1183 msgid "You cannot disable a node which is hosting instances." msgstr "Nem tiltható le olyan csomópont, amelyen még futnak példányok." -#: vm/operations.py:1154 +#: vm/operations.py:1196 msgid "screenshot" msgstr "képernyőkép" -#: vm/operations.py:1155 +#: vm/operations.py:1197 msgid "" "Get a screenshot about the virtual machine's console. A key will be pressed " "on the keyboard to stop screensaver." @@ -5122,29 +5174,33 @@ msgstr "" "Képernyőkép készítése a virtuális gép konzoljáról. Egy billentyűnyomást " "követően készül a kép a képernyővédő miatt." -#: vm/operations.py:1167 +#: vm/operations.py:1209 msgid "recover" msgstr "visszaállítás" -#: vm/operations.py:1168 +#: vm/operations.py:1210 msgid "" -"Try to recover virtual machine disks from destroyed state. Network resources " -"(allocations) are already lost, so you will have to manually add interfaces " -"afterwards." +"Try to recover virtual machine disks from destroyed state. Network resources" +" (allocations) are already lost, so you will have to manually add interfaces" +" afterwards." msgstr "" "Megsemmisített virtuális gép lemezeinek visszaállítását kísérli meg. A " "hálózati erőforrások foglalásai már végleg elvesztek, így az interfészeket " "kézzel kell a visszaállítás után pótolni." -#: vm/operations.py:1194 +#: vm/operations.py:1227 +msgid "recover instance" +msgstr "példány helyreállítása" + +#: vm/operations.py:1250 msgid "resources change" msgstr "erőforrások módosítása" -#: vm/operations.py:1195 +#: vm/operations.py:1251 msgid "Change resources of a stopped virtual machine." msgstr "Leállított virtuális gép erőforrásainak változtatása." -#: vm/operations.py:1212 +#: vm/operations.py:1268 #, python-format msgid "" "Priority: %(priority)s, Num cores: %(num_cores)s, Ram size: %(ram_size)s" @@ -5152,66 +5208,66 @@ msgstr "" "Prioritás: %(priority)s, magok száma: %(num_cores)s, memória mérete: " "%(ram_size)s" -#: vm/operations.py:1221 +#: vm/operations.py:1277 msgid "password reset" msgstr "jelszó visszaállítása" -#: vm/operations.py:1222 +#: vm/operations.py:1278 msgid "" -"Generate and set a new login password on the virtual machine. This operation " -"requires the agent running. Resetting the password is not warranted to allow " -"you logging in as other settings are possible to prevent it." +"Generate and set a new login password on the virtual machine. This operation" +" requires the agent running. Resetting the password is not warranted to " +"allow you logging in as other settings are possible to prevent it." msgstr "" "Egy új belépési jelszó generálása és beállítása a virtuális gépen. Ez a " "művelet megköveteli az ügynök futását. A jelszó átállítása nem garantálja a " "sikeres belépést, mivel más beállítások is megakadályozhatják ezt." -#: vm/operations.py:1246 +#: vm/operations.py:1302 msgid "agent" msgstr "ügynök" -#: vm/operations.py:1287 +#: vm/operations.py:1343 msgid "starting" msgstr "indítás" -#: vm/operations.py:1305 +#: vm/operations.py:1361 msgid "wait agent restarting" msgstr "várakozás az ügynök újraindulására" -#: vm/operations.py:1322 +#: vm/operations.py:1378 msgid "cleanup" msgstr "takarítás" -#: vm/operations.py:1328 +#: vm/operations.py:1384 msgid "set time" msgstr "óra beállítása" -#: vm/operations.py:1339 +#: vm/operations.py:1395 msgid "set hostname" msgstr "gépnév beállítása" -#: vm/operations.py:1350 +#: vm/operations.py:1406 msgid "restart networking" msgstr "hálózat újratöltése" -#: vm/operations.py:1356 +#: vm/operations.py:1412 msgid "change ip" msgstr "IP cím beállítása" -#: vm/operations.py:1371 +#: vm/operations.py:1427 msgid "update agent" msgstr "ügynök frissítése" -#: vm/operations.py:1377 +#: vm/operations.py:1433 #, python-format msgid "update agent to %(version)s" msgstr "ügynökfrissítés erre: %(version)s" -#: vm/operations.py:1460 +#: vm/operations.py:1516 msgid "mount store" msgstr "tárhely csatolása" -#: vm/operations.py:1462 +#: vm/operations.py:1518 msgid "" "This operation attaches your personal file store. Other users who have " "access to this machine can see these files as well." @@ -5219,28 +5275,28 @@ msgstr "" "Ez a művelet csatolja az ön személyes tárhelyét. A gép más felhasználói is " "elérhetik fájljait." -#: vm/operations.py:1496 +#: vm/operations.py:1552 msgid "attach disk" msgstr "lemez csatolása" -#: vm/operations.py:1507 +#: vm/operations.py:1563 msgid "Resource was not found." msgstr "Nem található az erőforrás." -#: vm/operations.py:1508 +#: vm/operations.py:1564 #, python-format msgid "Resource was not found. %(exception)s" msgstr "Nem található az erőforrás. %(exception)s" -#: vm/operations.py:1517 +#: vm/operations.py:1573 msgid "detach disk" msgstr "lemez leválasztása" -#: vm/operations.py:1532 +#: vm/operations.py:1588 msgid "attach network" msgstr "hálózat csatolása" -#: vm/operations.py:1539 +#: vm/operations.py:1595 msgid "detach network" msgstr "hálózat lecsatolása" @@ -5277,7 +5333,8 @@ msgstr "csomópont" #: vm/models/activity.py:267 msgid "Manager is restarted, activity is cleaned up. You can try again now." msgstr "" -"A menedzser újraindítása miatt a tevékenység lezárásra került. Próbálja újra." +"A menedzser újraindítása miatt a tevékenység lezárásra került. Próbálja " +"újra." #: vm/models/common.py:39 msgid "number of cores" @@ -5355,8 +5412,8 @@ msgstr "rendszerbetöltő menüje" #: vm/models/instance.py:102 msgid "Show boot device selection menu on boot." msgstr "" -"A rendszerbetöltés eszközének kiválasztását lehetővé tevő menü megjelenítése " -"indításkor." +"A rendszerbetöltés eszközének kiválasztását lehetővé tevő menü megjelenítése" +" indításkor." #: vm/models/instance.py:103 msgid "Preferred expiration periods." @@ -5585,13 +5642,11 @@ msgstr "VM állapota erre változott: %(state)s (ezen: %(node)s)" #, python-format msgid "" "Your instance %(instance)s is going to expire. It " -"will be suspended at %(suspend)s and destroyed at %(delete)s. Please, either " -"renew or destroy it now." +"will be suspended at %(suspend)s and destroyed at %(delete)s. Please, either" +" renew or destroy it now." msgstr "" "%(instance)s gépe hamarosan lejár:\n" -"%(suspend)s időpontban felfüggesztésre, %(delete)s időpontban törlésre " -"kerül. Kérjük, újítsa meg vagy törölje most." +"%(suspend)s időpontban felfüggesztésre, %(delete)s időpontban törlésre kerül. Kérjük, újítsa meg vagy törölje most." #: vm/models/instance.py:658 #, python-format @@ -5656,8 +5711,8 @@ msgstr "Az interfész létrehozásra került." #: vm/models/network.py:136 #, python-format msgid "" -"Interface successfully created. New addresses: ipv4: %(ip4)s, ipv6: %(ip6)s, " -"vlan: %(vlan)s." +"Interface successfully created. New addresses: ipv4: %(ip4)s, ipv6: %(ip6)s," +" vlan: %(vlan)s." msgstr "" "Az interfész létrehozásra került.Az új címek: %(ip4)s (ipv4), %(ip6)s " "(ipv6). Vlan: %(vlan)s." @@ -5706,23 +5761,27 @@ msgstr "túlfoglalási arány" msgid "The ratio of total memory with to without overcommit." msgstr "Az összes memória és a túlfoglalható memória aránya." -#: vm/models/node.py:138 +#: vm/models/node.py:92 +msgid "Can view Node box and statistics." +msgstr "Láthatja a csomópontok dobozt és a statisztikát." + +#: vm/models/node.py:140 msgid "missing" msgstr "eltűnt" -#: vm/models/node.py:139 +#: vm/models/node.py:141 msgid "offline" msgstr "nem elérhető" -#: vm/models/node.py:140 +#: vm/models/node.py:142 msgid "disabled" msgstr "tiltva" -#: vm/models/node.py:141 +#: vm/models/node.py:143 msgid "passive" msgstr "passzív" -#: vm/models/node.py:142 +#: vm/models/node.py:144 msgid "active" msgstr "aktív" @@ -5738,8 +5797,8 @@ msgstr "%(instance)s megsemmisítve" #: vm/tasks/local_periodic_tasks.py:53 #, python-format msgid "" -"Your instance %(instance)s has been destroyed due to " -"expiration." +"Your instance %(instance)s has been destroyed due to" +" expiration." msgstr "" "%(instance)s gépe megsemmisítésre került, mivel " "lejárt." @@ -5752,16 +5811,34 @@ msgstr "%(instance)s felfüggesztve" #: vm/tasks/local_periodic_tasks.py:67 #, python-format msgid "" -"Your instance %(instance)s has been suspended due to " -"expiration. You can resume or destroy it." +"Your instance %(instance)s has been suspended due to" +" expiration. You can resume or destroy it." msgstr "" "%(instance)s gépe felfüggesztésre került, mivel " "lejárt. Felébresztheti vagy megsemmisítheti." -#: vm/tests/test_models.py:218 +#: vm/tests/test_models.py:219 msgid "x" msgstr "x" +#~ msgid "There is a problem with your input." +#~ msgstr "A megadott érték nem megfelelő." + +#~ msgid "Unknown error." +#~ msgstr "Ismeretlen hiba." + +#~ msgid "Port delete confirmation" +#~ msgstr "Porteltávolítás megerősítése" + +#~ msgid "Are you sure you want to close %(port)d/%(proto)s on %(vm)s?" +#~ msgstr "Biztosan bezárja a(z) %(port)d/%(proto)s portot a következőn: %(vm)s?" + +#~ msgid "Port successfully removed." +#~ msgstr "A port eltávolításra került." + +#~ msgid "Vendor: %(vendor)s" +#~ msgstr "Gyártó: %(vendor)s" + #~ msgid "Visit" #~ msgstr "Megtekintés" @@ -5846,8 +5923,7 @@ msgstr "x" #~ "Virtuális gép mentése sablonként.\n" #~ "\n" #~ " A sablonokat megoszthatja csoportokkal vagy felhasználókkal.\n" -#~ " A felhasználók virtuális gépeket példányosíthatnak a " -#~ "sablonokból.\n" +#~ " A felhasználók virtuális gépeket példányosíthatnak a sablonokból.\n" #~ " " #~ msgid "Shutdown virtual machine with ACPI signal." @@ -5945,13 +6021,11 @@ msgstr "x" #~ msgid "" #~ "\n" -#~ "Please, either renew or destroy\n" +#~ "Please, either renew or destroy\n" #~ "it now.\n" #~ msgstr "" #~ "\n" -#~ "Újítsa meg vagy törölje\n" +#~ "Újítsa meg vagy törölje\n" #~ "most.\n" #~ msgid "Add new network interface!" @@ -5963,9 +6037,6 @@ msgstr "x" #~ msgid "Disk this activity works on." #~ msgstr "A lemez, amelyre a művelet vonatkozik." -#~ msgid "Add the specified disk to the VM." -#~ msgstr "A megadott lemez hozzáadása a VM-hez." - #~ msgid "None" #~ msgstr "Nincs" diff --git a/circle/locale/hu/LC_MESSAGES/djangojs.po b/circle/locale/hu/LC_MESSAGES/djangojs.po index 8add889..572b4d5 100644 --- a/circle/locale/hu/LC_MESSAGES/djangojs.po +++ b/circle/locale/hu/LC_MESSAGES/djangojs.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2014-10-20 12:09+0200\n" +"POT-Creation-Date: 2014-11-14 13:43+0100\n" "PO-Revision-Date: 2014-10-20 12:21+0200\n" "Last-Translator: Mate Ory \n" "Language-Team: Hungarian \n" @@ -17,7 +17,7 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Lokalize 1.5\n" -#: dashboard/static/dashboard/dashboard.js:68 +#: dashboard/static/dashboard/dashboard.js:83 #: static_collected/all.047675ebf594.js:3443 #: static_collected/all.0aecd87e873a.js:3443 #: static_collected/all.0db607331718.js:3443 @@ -34,13 +34,13 @@ msgstr "" #: static_collected/dashboard/dashboard.be8725cd91bf.js:68 #: static_collected/dashboard/dashboard.e740d80401b2.js:68 #: static_collected/dashboard/dashboard.fe0a2f126346.js:68 -#: static_collected/dashboard/dashboard.js:68 +#: static_collected/dashboard/dashboard.js:83 msgid "Select an option to proceed!" msgstr "Válasszon a folytatáshoz." -#: dashboard/static/dashboard/dashboard.js:259 -#: dashboard/static/dashboard/dashboard.js:307 -#: dashboard/static/dashboard/dashboard.js:317 +#: dashboard/static/dashboard/dashboard.js:274 +#: dashboard/static/dashboard/dashboard.js:322 +#: dashboard/static/dashboard/dashboard.js:332 #: static_collected/all.047675ebf594.js:3633 #: static_collected/all.047675ebf594.js:3681 #: static_collected/all.047675ebf594.js:3691 @@ -88,9 +88,9 @@ msgstr "Válasszon a folytatáshoz." #: static_collected/dashboard/dashboard.fe0a2f126346.js:258 #: static_collected/dashboard/dashboard.fe0a2f126346.js:306 #: static_collected/dashboard/dashboard.fe0a2f126346.js:316 -#: static_collected/dashboard/dashboard.js:259 -#: static_collected/dashboard/dashboard.js:307 -#: static_collected/dashboard/dashboard.js:317 +#: static_collected/dashboard/dashboard.js:274 +#: static_collected/dashboard/dashboard.js:322 +#: static_collected/dashboard/dashboard.js:332 msgid "No result" msgstr "Nincs eredmény" @@ -129,10 +129,12 @@ msgid "Unknown error." msgstr "Ismeretlen hiba." #: dashboard/static/dashboard/template-list.js:103 +#: static_collected/dashboard/template-list.js:103 msgid "Only the owners can delete the selected object." msgstr "Csak a tulajdonos törölheti a kiválasztott elemet." #: dashboard/static/dashboard/template-list.js:105 +#: static_collected/dashboard/template-list.js:105 msgid "An error occurred. (" msgstr "Hiba történt. (" @@ -206,11 +208,12 @@ msgstr "Jelszó megjelenítése" #: static_collected/vm-detail.js:6391 #: static_collected/dashboard/vm-tour.1562cc89a659.js:22 #: static_collected/dashboard/vm-tour.7b4cf596f543.js:22 -#: static_collected/dashboard/vm-tour.js:22 +#: static_collected/dashboard/vm-tour.js:6 msgid "Next" msgstr "Tovább" #: dashboard/static/dashboard/vm-tour.js:7 +#: static_collected/dashboard/vm-tour.js:7 msgid "Previous" msgstr "Vissza" @@ -226,15 +229,17 @@ msgstr "Vissza" #: static_collected/vm-detail.js:6395 #: static_collected/dashboard/vm-tour.1562cc89a659.js:26 #: static_collected/dashboard/vm-tour.7b4cf596f543.js:26 -#: static_collected/dashboard/vm-tour.js:26 +#: static_collected/dashboard/vm-tour.js:8 msgid "End tour" msgstr "Befejezés" #: dashboard/static/dashboard/vm-tour.js:9 +#: static_collected/dashboard/vm-tour.js:9 msgid "Done" msgstr "Kész" #: dashboard/static/dashboard/vm-tour.js:56 +#: static_collected/dashboard/vm-tour.js:56 msgid "" "Welcome to the template tutorial. In this quick tour, we are going to show " "you how to do the steps described above." @@ -254,7 +259,7 @@ msgstr "" #: static_collected/vm-detail.js:6404 #: static_collected/dashboard/vm-tour.1562cc89a659.js:35 #: static_collected/dashboard/vm-tour.7b4cf596f543.js:35 -#: static_collected/dashboard/vm-tour.js:35 +#: static_collected/dashboard/vm-tour.js:57 msgid "" "For the next tour step press the \"Next\" button or the right arrow (or " "\"Back\" button/left arrow for the previous step)." @@ -263,6 +268,7 @@ msgstr "" "nyílbillentyűket." #: dashboard/static/dashboard/vm-tour.js:61 +#: static_collected/dashboard/vm-tour.js:61 msgid "" "In this tab you can extend the expiration date of your virtual machine, add " "tags and modify the name and description." @@ -271,24 +277,26 @@ msgstr "" "vagy módosíthatja a nevét, leírását." #: dashboard/static/dashboard/vm-tour.js:65 +#: static_collected/dashboard/vm-tour.js:65 msgid "" "Please add a meaningful description to the virtual machine. Changing the " "name is also recommended, however you can choose a new name when saving the " "template." msgstr "" -"Kérjük, adjon meg egy informatív leírást. A név megváltoztatása is " -"ajánlott, azonban a mentéskor is van a sablon nevének " -"megválasztására." +"Kérjük, adjon meg egy informatív leírást. A név megváltoztatása is ajánlott, " +"azonban a mentéskor is van a sablon nevének megválasztására." #: dashboard/static/dashboard/vm-tour.js:69 +#: static_collected/dashboard/vm-tour.js:69 msgid "" "You can change the lease to extend the expiration date. This will be the " "lease of the new template." msgstr "" -"Megváltoztathatja a bérleti módot is a lejárat bővítéséhez. Az gép " -"bérleti módját örökli majd a sablon is." +"Megváltoztathatja a bérleti módot is a lejárat bővítéséhez. Az gép bérleti " +"módját örökli majd a sablon is." #: dashboard/static/dashboard/vm-tour.js:73 +#: static_collected/dashboard/vm-tour.js:73 msgid "" "On the resources tab you can edit the CPU/RAM options and add/remove disks " "if you have required permissions." @@ -308,7 +316,7 @@ msgstr "" #: static_collected/vm-detail.js:6438 #: static_collected/dashboard/vm-tour.1562cc89a659.js:69 #: static_collected/dashboard/vm-tour.7b4cf596f543.js:69 -#: static_collected/dashboard/vm-tour.js:69 +#: static_collected/dashboard/vm-tour.js:81 msgid "CPU priority" msgstr "CPU prioritás" @@ -324,7 +332,7 @@ msgstr "CPU prioritás" #: static_collected/vm-detail.js:6438 #: static_collected/dashboard/vm-tour.1562cc89a659.js:69 #: static_collected/dashboard/vm-tour.7b4cf596f543.js:69 -#: static_collected/dashboard/vm-tour.js:69 +#: static_collected/dashboard/vm-tour.js:82 msgid "higher is better" msgstr "a nagyobb érték a jobb" @@ -340,7 +348,7 @@ msgstr "a nagyobb érték a jobb" #: static_collected/vm-detail.js:6439 #: static_collected/dashboard/vm-tour.1562cc89a659.js:70 #: static_collected/dashboard/vm-tour.7b4cf596f543.js:70 -#: static_collected/dashboard/vm-tour.js:70 +#: static_collected/dashboard/vm-tour.js:83 msgid "CPU count" msgstr "CPU-k száma" @@ -356,7 +364,7 @@ msgstr "CPU-k száma" #: static_collected/vm-detail.js:6439 #: static_collected/dashboard/vm-tour.1562cc89a659.js:70 #: static_collected/dashboard/vm-tour.7b4cf596f543.js:70 -#: static_collected/dashboard/vm-tour.js:70 +#: static_collected/dashboard/vm-tour.js:84 msgid "number of CPU cores." msgstr "A CPU-magok száma." @@ -372,7 +380,7 @@ msgstr "A CPU-magok száma." #: static_collected/vm-detail.js:6440 #: static_collected/dashboard/vm-tour.1562cc89a659.js:71 #: static_collected/dashboard/vm-tour.7b4cf596f543.js:71 -#: static_collected/dashboard/vm-tour.js:71 +#: static_collected/dashboard/vm-tour.js:85 msgid "RAM amount" msgstr "RAM mennyiség" @@ -388,7 +396,7 @@ msgstr "RAM mennyiség" #: static_collected/vm-detail.js:6440 #: static_collected/dashboard/vm-tour.1562cc89a659.js:71 #: static_collected/dashboard/vm-tour.7b4cf596f543.js:71 -#: static_collected/dashboard/vm-tour.js:71 +#: static_collected/dashboard/vm-tour.js:86 msgid "amount of RAM." msgstr "a memória mennyisége." @@ -404,7 +412,7 @@ msgstr "a memória mennyisége." #: static_collected/vm-detail.js:6451 #: static_collected/dashboard/vm-tour.1562cc89a659.js:82 #: static_collected/dashboard/vm-tour.7b4cf596f543.js:82 -#: static_collected/dashboard/vm-tour.js:82 +#: static_collected/dashboard/vm-tour.js:96 msgid "" "You can add empty disks, download new ones and remove existing ones here." msgstr "" @@ -423,7 +431,7 @@ msgstr "" #: static_collected/vm-detail.js:6462 #: static_collected/dashboard/vm-tour.1562cc89a659.js:93 #: static_collected/dashboard/vm-tour.7b4cf596f543.js:93 -#: static_collected/dashboard/vm-tour.js:93 +#: static_collected/dashboard/vm-tour.js:105 msgid "You can add new network interfaces or remove existing ones here." msgstr "Hozzáadhat új hálózati interfészeket, vagy törölheti a meglévőket." @@ -439,17 +447,18 @@ msgstr "Hozzáadhat új hálózati interfészeket, vagy törölheti a meglévők #: static_collected/vm-detail.js:6474 #: static_collected/dashboard/vm-tour.1562cc89a659.js:105 #: static_collected/dashboard/vm-tour.7b4cf596f543.js:105 -#: static_collected/dashboard/vm-tour.js:105 +#: static_collected/dashboard/vm-tour.js:109 msgid "Deploy the virtual machine." msgstr "A virtuális gép elindítása." #: dashboard/static/dashboard/vm-tour.js:113 +#: static_collected/dashboard/vm-tour.js:113 msgid "" "Use the CIRCLE client or the connection string to connect to the virtual " "machine." msgstr "" -"Használja a CIRCLE klienst vagy a kapcsolódási adatokat a " -"virtuális géphez való csatlakozáshoz." +"Használja a CIRCLE klienst vagy a kapcsolódási adatokat a virtuális géphez " +"való csatlakozáshoz." #: dashboard/static/dashboard/vm-tour.js:117 #: static_collected/vm-detail.09737c69abc3.js:5954 @@ -463,7 +472,7 @@ msgstr "" #: static_collected/vm-detail.js:6490 #: static_collected/dashboard/vm-tour.1562cc89a659.js:121 #: static_collected/dashboard/vm-tour.7b4cf596f543.js:121 -#: static_collected/dashboard/vm-tour.js:121 +#: static_collected/dashboard/vm-tour.js:117 msgid "" "After you have connected to the virtual machine do your modifications then " "log off." @@ -483,7 +492,7 @@ msgstr "" #: static_collected/vm-detail.js:6498 #: static_collected/dashboard/vm-tour.1562cc89a659.js:129 #: static_collected/dashboard/vm-tour.7b4cf596f543.js:129 -#: static_collected/dashboard/vm-tour.js:129 +#: static_collected/dashboard/vm-tour.js:121 msgid "" "Press the \"Save as template\" button and wait until the activity finishes." msgstr "" @@ -491,12 +500,11 @@ msgstr "" "elkészül." #: dashboard/static/dashboard/vm-tour.js:125 +#: static_collected/dashboard/vm-tour.js:125 msgid "" "This is the last message, if something is not clear you can do the the tour " "again." -msgstr "" -"A túra véget ért. Ha valami nem érthető, újrakezdheti az " -"útmutatót." +msgstr "A túra véget ért. Ha valami nem érthető, újrakezdheti az útmutatót." #: network/static/js/host.js:10 static_collected/all.047675ebf594.js:5239 #: static_collected/all.0aecd87e873a.js:5309 @@ -617,7 +625,6 @@ msgstr "Biztosan törli ezt az eszközt?" #: static_collected/vm-detail.js:6389 #: static_collected/dashboard/vm-tour.1562cc89a659.js:20 #: static_collected/dashboard/vm-tour.7b4cf596f543.js:20 -#: static_collected/dashboard/vm-tour.js:20 msgid "Prev" msgstr "Vissza" @@ -632,7 +639,6 @@ msgstr "Vissza" #: static_collected/vm-detail.js:6402 #: static_collected/dashboard/vm-tour.1562cc89a659.js:33 #: static_collected/dashboard/vm-tour.7b4cf596f543.js:33 -#: static_collected/dashboard/vm-tour.js:33 msgid "Template Tutorial Tour" msgstr "Sablon-kalauz" @@ -647,7 +653,6 @@ msgstr "Sablon-kalauz" #: static_collected/vm-detail.js:6403 #: static_collected/dashboard/vm-tour.1562cc89a659.js:34 #: static_collected/dashboard/vm-tour.7b4cf596f543.js:34 -#: static_collected/dashboard/vm-tour.js:34 msgid "" "Welcome to the template tutorial. In this quick tour, we gonna show you how " "to do the steps described above." @@ -665,7 +670,6 @@ msgstr "" #: static_collected/vm-detail.js:6405 #: static_collected/dashboard/vm-tour.1562cc89a659.js:36 #: static_collected/dashboard/vm-tour.7b4cf596f543.js:36 -#: static_collected/dashboard/vm-tour.js:36 msgid "" "During the tour please don't try the functions because it may lead to " "graphical glitches, however " @@ -682,7 +686,6 @@ msgstr "A túra során még ne próbálja ki a bemutatott funkciókat." #: static_collected/vm-detail.js:6414 #: static_collected/dashboard/vm-tour.1562cc89a659.js:45 #: static_collected/dashboard/vm-tour.7b4cf596f543.js:45 -#: static_collected/dashboard/vm-tour.js:45 msgid "Home tab" msgstr "Kezdőoldal" @@ -697,7 +700,6 @@ msgstr "Kezdőoldal" #: static_collected/vm-detail.js:6415 #: static_collected/dashboard/vm-tour.1562cc89a659.js:46 #: static_collected/dashboard/vm-tour.7b4cf596f543.js:46 -#: static_collected/dashboard/vm-tour.js:46 msgid "" "In this tab you can tag your virtual machine and modify the name and " "description." @@ -716,7 +718,6 @@ msgstr "" #: static_collected/vm-detail.js:6424 #: static_collected/dashboard/vm-tour.1562cc89a659.js:55 #: static_collected/dashboard/vm-tour.7b4cf596f543.js:55 -#: static_collected/dashboard/vm-tour.js:55 msgid "Resources tab" msgstr "Erőforrások lap" @@ -731,7 +732,6 @@ msgstr "Erőforrások lap" #: static_collected/vm-detail.js:6427 #: static_collected/dashboard/vm-tour.1562cc89a659.js:58 #: static_collected/dashboard/vm-tour.7b4cf596f543.js:58 -#: static_collected/dashboard/vm-tour.js:58 msgid "" "On the resources tab you can edit the CPU/RAM options and add/remove disks!" msgstr "" @@ -749,7 +749,6 @@ msgstr "" #: static_collected/vm-detail.js:6437 #: static_collected/dashboard/vm-tour.1562cc89a659.js:68 #: static_collected/dashboard/vm-tour.7b4cf596f543.js:68 -#: static_collected/dashboard/vm-tour.js:68 msgid "Resources" msgstr "Erőforrások" @@ -764,7 +763,6 @@ msgstr "Erőforrások" #: static_collected/vm-detail.js:6450 #: static_collected/dashboard/vm-tour.1562cc89a659.js:81 #: static_collected/dashboard/vm-tour.7b4cf596f543.js:81 -#: static_collected/dashboard/vm-tour.js:81 msgid "Disks" msgstr "Lemezek" @@ -779,7 +777,6 @@ msgstr "Lemezek" #: static_collected/vm-detail.js:6461 #: static_collected/dashboard/vm-tour.1562cc89a659.js:92 #: static_collected/dashboard/vm-tour.7b4cf596f543.js:92 -#: static_collected/dashboard/vm-tour.js:92 msgid "Network tab" msgstr "Hálózat lap" @@ -794,7 +791,6 @@ msgstr "Hálózat lap" #: static_collected/vm-detail.js:6471 #: static_collected/dashboard/vm-tour.1562cc89a659.js:102 #: static_collected/dashboard/vm-tour.7b4cf596f543.js:102 -#: static_collected/dashboard/vm-tour.js:102 msgid "Deploy" msgstr "Indítás" @@ -809,7 +805,6 @@ msgstr "Indítás" #: static_collected/vm-detail.js:6479 #: static_collected/dashboard/vm-tour.1562cc89a659.js:110 #: static_collected/dashboard/vm-tour.7b4cf596f543.js:110 -#: static_collected/dashboard/vm-tour.js:110 msgid "Connect" msgstr "Csatlakozás" @@ -824,7 +819,6 @@ msgstr "Csatlakozás" #: static_collected/vm-detail.js:6482 #: static_collected/dashboard/vm-tour.1562cc89a659.js:113 #: static_collected/dashboard/vm-tour.7b4cf596f543.js:113 -#: static_collected/dashboard/vm-tour.js:113 msgid "Use the connection string or connect with your choice of client!" msgstr "Használja a megadott parancsot, vagy kedvenc kliensét." @@ -839,7 +833,6 @@ msgstr "Használja a megadott parancsot, vagy kedvenc kliensét." #: static_collected/vm-detail.js:6489 #: static_collected/dashboard/vm-tour.1562cc89a659.js:120 #: static_collected/dashboard/vm-tour.7b4cf596f543.js:120 -#: static_collected/dashboard/vm-tour.js:120 msgid "Customize the virtual machine" msgstr "Szabja testre a gépet" @@ -854,7 +847,6 @@ msgstr "Szabja testre a gépet" #: static_collected/vm-detail.js:6495 #: static_collected/dashboard/vm-tour.1562cc89a659.js:126 #: static_collected/dashboard/vm-tour.7b4cf596f543.js:126 -#: static_collected/dashboard/vm-tour.js:126 msgid "Save as" msgstr "Mentés sablonként" @@ -869,7 +861,6 @@ msgstr "Mentés sablonként" #: static_collected/vm-detail.js:6504 #: static_collected/dashboard/vm-tour.1562cc89a659.js:135 #: static_collected/dashboard/vm-tour.7b4cf596f543.js:135 -#: static_collected/dashboard/vm-tour.js:135 msgid "Finish" msgstr "Befejezés" @@ -884,7 +875,6 @@ msgstr "Befejezés" #: static_collected/vm-detail.js:6507 #: static_collected/dashboard/vm-tour.1562cc89a659.js:138 #: static_collected/dashboard/vm-tour.7b4cf596f543.js:138 -#: static_collected/dashboard/vm-tour.js:138 msgid "" "This is the last message, if something is not clear you can do the the tour " "again!" diff --git a/circle/network/forms.py b/circle/network/forms.py index 7287488..af1417c 100644 --- a/circle/network/forms.py +++ b/circle/network/forms.py @@ -15,13 +15,13 @@ # You should have received a copy of the GNU General Public License along # with CIRCLE. If not, see . -from django.forms import ModelForm +from django.forms import ModelForm, widgets from django.core.urlresolvers import reverse_lazy from django.utils.translation import ugettext_lazy as _ from crispy_forms.helper import FormHelper from crispy_forms.layout import Layout, Fieldset, Div, Submit, BaseInput -from crispy_forms.bootstrap import FormActions +from crispy_forms.bootstrap import FormActions, FieldWithButtons, StrictButton from firewall.models import (Host, Vlan, Domain, Group, Record, BlacklistItem, Rule, VlanGroup, SwitchPort) @@ -122,8 +122,12 @@ class HostForm(ModelForm): Fieldset( _('Network'), 'vlan', - 'ipv4', - 'ipv6', + FieldWithButtons('ipv4', StrictButton( + '', css_id="ipv4-magic", + title=_("Generate random address."))), + FieldWithButtons('ipv6', StrictButton( + '', css_id="ipv6-magic", + title=_("Generate IPv6 pair of IPv4 address."))), 'shared_ip', 'external_ipv4', ), @@ -252,7 +256,9 @@ class VlanForm(ModelForm): Fieldset( _('IPv6'), 'network6', - 'ipv6_template', + FieldWithButtons('ipv6_template', StrictButton( + '', css_id="ipv6-tpl-magic", + title=_("Generate sensible template."))), 'host_ipv6_prefixlen', ), Fieldset( @@ -277,6 +283,9 @@ class VlanForm(ModelForm): class Meta: model = Vlan + widgets = { + 'ipv6_template': widgets.TextInput, + } class VlanGroupForm(ModelForm): diff --git a/circle/network/static/js/host.js b/circle/network/static/js/host.js index 997d65c..b63636c 100644 --- a/circle/network/static/js/host.js +++ b/circle/network/static/js/host.js @@ -1,4 +1,4 @@ -$('i[class="fa fa-times"]').click(function() { +$('#small_rule_table i[class="fa fa-times"]').click(function() { href = $(this).parent('a').attr('href'); csrf = getCookie('csrftoken'); var click_this = this; diff --git a/circle/network/static/js/network.js b/circle/network/static/js/network.js index e59d0e8..2061084 100644 --- a/circle/network/static/js/network.js +++ b/circle/network/static/js/network.js @@ -28,6 +28,49 @@ function getURLParameter(name) { ); } +function doBlink(id, count) { + if (count > 0) { + $(id).parent().delay(200).queue(function() { + $(this).delay(200).queue(function() { + $(this).removeClass("has-warning").dequeue(); + doBlink(id, count-1);}); + $(this).addClass("has-warning").dequeue() + }); + } +} + $(function() { $("[title]").tooltip(); + +$("#ipv6-magic").click(function() { + $.ajax({url: window.location, + data: {ipv4: $("[name=ipv4]").val(), + vlan: $("[name=vlan]").val()}, + success: function(data) { + $("[name=ipv6]").val(data.ipv6); + }}); +}); +$("#ipv4-magic").click(function() { + $.ajax({url: window.location, + data: {vlan: $("[name=vlan]").val()}, + success: function(data) { + $("[name=ipv4]").val(data.ipv4); + if ($("[name=ipv6]").val() != data.ipv6) { + doBlink("[name=ipv6]", 3); + } + $("[name=ipv6]").val(data.ipv6); + }}); +}); +$("#ipv6-tpl-magic").click(function() { + $.ajax({url: window.location, + data: {network4: $("[name=network4]").val(), + network6: $("[name=network6]").val()}, + success: function(data) { + $("[name=ipv6_template]").val(data.ipv6_template); + if ($("[name=host_ipv6_prefixlen]").val() != data.host_ipv6_prefixlen) { + doBlink("[name=host_ipv6_prefixlen]", 3); + } + $("[name=host_ipv6_prefixlen]").val(data.host_ipv6_prefixlen); + }}); +}); }); diff --git a/circle/network/static/js/select2-3.4.0/LICENSE b/circle/network/static/js/select2-3.4.0/LICENSE deleted file mode 100644 index 3c98f3d..0000000 --- a/circle/network/static/js/select2-3.4.0/LICENSE +++ /dev/null @@ -1,18 +0,0 @@ -Copyright 2012 Igor Vaynberg - -Version: @@ver@@ Timestamp: @@timestamp@@ - -This software is licensed under the Apache License, Version 2.0 (the "Apache License") or the GNU -General Public License version 2 (the "GPL License"). You may choose either license to govern your -use of this software only upon the condition that you accept all of the terms of either the Apache -License or the GPL License. - -You may obtain a copy of the Apache License and the GPL License at: - -http://www.apache.org/licenses/LICENSE-2.0 -http://www.gnu.org/licenses/gpl-2.0.html - -Unless required by applicable law or agreed to in writing, software distributed under the Apache License -or the GPL Licesnse is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, -either express or implied. See the Apache License and the GPL License for the specific language governing -permissions and limitations under the Apache License and the GPL License. \ No newline at end of file diff --git a/circle/network/static/js/select2-3.4.0/README.md b/circle/network/static/js/select2-3.4.0/README.md deleted file mode 100644 index 12e2492..0000000 --- a/circle/network/static/js/select2-3.4.0/README.md +++ /dev/null @@ -1,83 +0,0 @@ -Select2 -================= - -Select2 is a jQuery based replacement for select boxes. It supports searching, remote data sets, and infinite scrolling of results. - -To get started checkout examples and documentation at http://ivaynberg.github.com/select2 - -What Usecases Does Select2 Support -------------------------------------------------- - -* Enhances native selects with search -* Enhances native selects with a better multi-select interface -* Loading data from javascript: easily load items via ajax and have them searchable -* Nested optgroups: native selects only support one level of nested, Select2 does not have this restriction -* Tagging: ability to add new items on the fly -* Working with large remote datesets: ability to partially load a dataset based on the search term -* Paging of large datasets: easy support for loading more pages when the results are scrolled to the end -* Templating: support for custom rendering of results and selections - -Browser Compatibility --------------------- -* IE 8+ (7 mostly works except for [issue with z-index](https://github.com/ivaynberg/select2/issues/37)) -* Chrome 8+ -* Firefox 3.5+ -* Safari 3+ -* Opera 10.6+ - -Integrations ------------- - -* [Wicket-Select2](https://github.com/ivaynberg/wicket-select2) (Java / [Apache Wicket](http://wicket.apache.org)) -* [select2-rails](https://github.com/argerim/select2-rails) (Ruby on Rails) -* [AngularUI](http://angular-ui.github.com/#directives-select2) ([AngularJS](angularjs.org)) -* [Django](https://github.com/applegrew/django-select2) -* [Symfony](https://github.com/19Gerhard85/sfSelect2WidgetsPlugin) -* [Bootstrap](https://github.com/t0m/select2-bootstrap-css) (CSS skin) -* [Yii](https://github.com/tonybolzan/yii-select2) - -Internationalization (i18n) ---------------------------- - -Select2 supports multiple languages by simply including the right -language JS file (`select2_locale_it.js`, `select2_locale_nl.js` etc.). - -Missing a language? Just copy `select2_locale_en.js.template`, translate -it and make a pull request back to Select2 here on Github. - -Bug tracker ------------ - -Have a bug? Please create an issue here on GitHub! - -https://github.com/ivaynberg/select2/issues - -Mailing list ------------- - -Have a question? Ask on our mailing list! - -select2@googlegroups.com - -https://groups.google.com/d/forum/select2 - - -Copyright and License ---------------------- - -Copyright 2012 Igor Vaynberg - -This software is licensed under the Apache License, Version 2.0 (the "Apache License") or the GNU -General Public License version 2 (the "GPL License"). You may choose either license to govern your -use of this software only upon the condition that you accept all of the terms of either the Apache -License or the GPL License. - -You may obtain a copy of the Apache License and the GPL License in the LICENSE file, or at: - -http://www.apache.org/licenses/LICENSE-2.0 -http://www.gnu.org/licenses/gpl-2.0.html - -Unless required by applicable law or agreed to in writing, software distributed under the Apache License -or the GPL Licesnse is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, -either express or implied. See the Apache License and the GPL License for the specific language governing -permissions and limitations under the Apache License and the GPL License. diff --git a/circle/network/static/js/select2-3.4.0/component.json b/circle/network/static/js/select2-3.4.0/component.json deleted file mode 100644 index 4c7337f..0000000 --- a/circle/network/static/js/select2-3.4.0/component.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "name": "select2", - "version": "3.4.0", - "main": ["select2.js", "select2.css", "select2.png", "select2x2.png", "select2-spinner.gif"], - "dependencies": { - "jquery": ">= 1.7.1" - } -} diff --git a/circle/network/static/js/select2-3.4.0/release.sh b/circle/network/static/js/select2-3.4.0/release.sh deleted file mode 100755 index 0a315ab..0000000 --- a/circle/network/static/js/select2-3.4.0/release.sh +++ /dev/null @@ -1,69 +0,0 @@ -#!/bin/bash -set -e - -echo -n "Enter the version for this release: " - -read ver - -if [ ! $ver ]; then - echo "Invalid version." - exit -fi - -name="select2" -js="$name.js" -mini="$name.min.js" -css="$name.css" -release="$name-$ver" -tag="$ver" -branch="build-$ver" -curbranch=`git branch | grep "*" | sed "s/* //"` -timestamp=$(date) -tokens="s/@@ver@@/$ver/g;s/\@@timestamp@@/$timestamp/g" -remote="github" - -echo "Updating Version Identifiers" - -sed -E -e "s/\"version\": \"([0-9\.]+)\",/\"version\": \"$ver\",/g" -i "" component.json select2.jquery.json -git add component.json -git add select2.jquery.json -git commit -m "modified version identifiers in descriptors for release $ver" -git push - -git branch "$branch" -git checkout "$branch" - -echo "Tokenizing..." - -find . -name "$js" | xargs -I{} sed -e "$tokens" -i "" {} -find . -name "$css" | xargs -I{} sed -e "$tokens" -i "" {} -sed -e "s/latest/$ver/g" -i "" component.json - -git add "$js" -git add "$css" - -echo "Minifying..." - -echo "/*" > "$mini" -cat LICENSE | sed "$tokens" >> "$mini" -echo "*/" >> "$mini" - -curl -s \ - --data-urlencode "js_code@$js" \ - http://marijnhaverbeke.nl/uglifyjs \ - >> "$mini" - -git add "$mini" - -git commit -m "release $ver" - -echo "Tagging..." -git tag -a "$tag" -m "tagged version $ver" -git push "$remote" --tags - -echo "Cleaning Up..." - -git checkout "$curbranch" -git branch -D "$branch" - -echo "Done" diff --git a/circle/network/static/js/select2-3.4.0/select2-spinner.gif b/circle/network/static/js/select2-3.4.0/select2-spinner.gif deleted file mode 100644 index 5b33f7e..0000000 Binary files a/circle/network/static/js/select2-3.4.0/select2-spinner.gif and /dev/null differ diff --git a/circle/network/static/js/select2-3.4.0/select2.jquery.json b/circle/network/static/js/select2-3.4.0/select2.jquery.json deleted file mode 100644 index b9b114d..0000000 --- a/circle/network/static/js/select2-3.4.0/select2.jquery.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "name": "select2", - "title": "Select2", - "description": "Select2 is a jQuery based replacement for select boxes. It supports searching, remote data sets, and infinite scrolling of results.", - "keywords": [ - "select", - "autocomplete", - "typeahead", - "dropdown", - "multiselect", - "tag", - "tagging" - ], - "version": "3.4.0", - "author": { - "name": "Igor Vaynberg", - "url": "https://github.com/ivaynberg" - }, - "licenses": [ - { - "type": "Apache", - "url": "http://www.apache.org/licenses/LICENSE-2.0" - }, - { - "type": "GPL v2", - "url": "http://www.gnu.org/licenses/gpl-2.0.html" - } - ], - "bugs": "https://github.com/ivaynberg/select2/issues", - "homepage": "http://ivaynberg.github.com/select2", - "docs": "http://ivaynberg.github.com/select2/", - "download": "https://github.com/ivaynberg/select2/tags", - "dependencies": { - "jquery": ">=1.7.1" - } -} diff --git a/circle/network/static/js/select2-3.4.0/select2.js b/circle/network/static/js/select2-3.4.0/select2.js deleted file mode 100644 index 992ba8b..0000000 --- a/circle/network/static/js/select2-3.4.0/select2.js +++ /dev/null @@ -1,3054 +0,0 @@ -/* -Copyright 2012 Igor Vaynberg - -Version: 3.4.0 Timestamp: Tue May 14 08:27:33 PDT 2013 - -This software is licensed under the Apache License, Version 2.0 (the "Apache License") or the GNU -General Public License version 2 (the "GPL License"). You may choose either license to govern your -use of this software only upon the condition that you accept all of the terms of either the Apache -License or the GPL License. - -You may obtain a copy of the Apache License and the GPL License at: - - http://www.apache.org/licenses/LICENSE-2.0 - http://www.gnu.org/licenses/gpl-2.0.html - -Unless required by applicable law or agreed to in writing, software distributed under the -Apache License or the GPL Licesnse is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -CONDITIONS OF ANY KIND, either express or implied. See the Apache License and the GPL License for -the specific language governing permissions and limitations under the Apache License and the GPL License. -*/ - (function ($) { - if(typeof $.fn.each2 == "undefined"){ - $.fn.extend({ - /* - * 4-10 times faster .each replacement - * use it carefully, as it overrides jQuery context of element on each iteration - */ - each2 : function (c) { - var j = $([0]), i = -1, l = this.length; - while ( - ++i < l - && (j.context = j[0] = this[i]) - && c.call(j[0], i, j) !== false //"this"=DOM, i=index, j=jQuery object - ); - return this; - } - }); - } -})(jQuery); - -(function ($, undefined) { - "use strict"; - /*global document, window, jQuery, console */ - - if (window.Select2 !== undefined) { - return; - } - - var KEY, AbstractSelect2, SingleSelect2, MultiSelect2, nextUid, sizer, - lastMousePosition, $document, scrollBarDimensions, - - KEY = { - TAB: 9, - ENTER: 13, - ESC: 27, - SPACE: 32, - LEFT: 37, - UP: 38, - RIGHT: 39, - DOWN: 40, - SHIFT: 16, - CTRL: 17, - ALT: 18, - PAGE_UP: 33, - PAGE_DOWN: 34, - HOME: 36, - END: 35, - BACKSPACE: 8, - DELETE: 46, - isArrow: function (k) { - k = k.which ? k.which : k; - switch (k) { - case KEY.LEFT: - case KEY.RIGHT: - case KEY.UP: - case KEY.DOWN: - return true; - } - return false; - }, - isControl: function (e) { - var k = e.which; - switch (k) { - case KEY.SHIFT: - case KEY.CTRL: - case KEY.ALT: - return true; - } - - if (e.metaKey) return true; - - return false; - }, - isFunctionKey: function (k) { - k = k.which ? k.which : k; - return k >= 112 && k <= 123; - } - }, - MEASURE_SCROLLBAR_TEMPLATE = "
"; - - $document = $(document); - - nextUid=(function() { var counter=1; return function() { return counter++; }; }()); - - function indexOf(value, array) { - var i = 0, l = array.length; - for (; i < l; i = i + 1) { - if (equal(value, array[i])) return i; - } - return -1; - } - - function measureScrollbar () { - var $template = $( MEASURE_SCROLLBAR_TEMPLATE ); - $template.appendTo('body'); - - var dim = { - width: $template.width() - $template[0].clientWidth, - height: $template.height() - $template[0].clientHeight - }; - $template.remove(); - - return dim; - } - - /** - * Compares equality of a and b - * @param a - * @param b - */ - function equal(a, b) { - if (a === b) return true; - if (a === undefined || b === undefined) return false; - if (a === null || b === null) return false; - if (a.constructor === String) return a+'' === b+''; // IE requires a+'' instead of just a - if (b.constructor === String) return b+'' === a+''; // IE requires b+'' instead of just b - return false; - } - - /** - * Splits the string into an array of values, trimming each value. An empty array is returned for nulls or empty - * strings - * @param string - * @param separator - */ - function splitVal(string, separator) { - var val, i, l; - if (string === null || string.length < 1) return []; - val = string.split(separator); - for (i = 0, l = val.length; i < l; i = i + 1) val[i] = $.trim(val[i]); - return val; - } - - function getSideBorderPadding(element) { - return element.outerWidth(false) - element.width(); - } - - function installKeyUpChangeEvent(element) { - var key="keyup-change-value"; - element.on("keydown", function () { - if ($.data(element, key) === undefined) { - $.data(element, key, element.val()); - } - }); - element.on("keyup", function () { - var val= $.data(element, key); - if (val !== undefined && element.val() !== val) { - $.removeData(element, key); - element.trigger("keyup-change"); - } - }); - } - - $document.on("mousemove", function (e) { - lastMousePosition = {x: e.pageX, y: e.pageY}; - }); - - /** - * filters mouse events so an event is fired only if the mouse moved. - * - * filters out mouse events that occur when mouse is stationary but - * the elements under the pointer are scrolled. - */ - function installFilteredMouseMove(element) { - element.on("mousemove", function (e) { - var lastpos = lastMousePosition; - if (lastpos === undefined || lastpos.x !== e.pageX || lastpos.y !== e.pageY) { - $(e.target).trigger("mousemove-filtered", e); - } - }); - } - - /** - * Debounces a function. Returns a function that calls the original fn function only if no invocations have been made - * within the last quietMillis milliseconds. - * - * @param quietMillis number of milliseconds to wait before invoking fn - * @param fn function to be debounced - * @param ctx object to be used as this reference within fn - * @return debounced version of fn - */ - function debounce(quietMillis, fn, ctx) { - ctx = ctx || undefined; - var timeout; - return function () { - var args = arguments; - window.clearTimeout(timeout); - timeout = window.setTimeout(function() { - fn.apply(ctx, args); - }, quietMillis); - }; - } - - /** - * A simple implementation of a thunk - * @param formula function used to lazily initialize the thunk - * @return {Function} - */ - function thunk(formula) { - var evaluated = false, - value; - return function() { - if (evaluated === false) { value = formula(); evaluated = true; } - return value; - }; - }; - - function installDebouncedScroll(threshold, element) { - var notify = debounce(threshold, function (e) { element.trigger("scroll-debounced", e);}); - element.on("scroll", function (e) { - if (indexOf(e.target, element.get()) >= 0) notify(e); - }); - } - - function focus($el) { - if ($el[0] === document.activeElement) return; - - /* set the focus in a 0 timeout - that way the focus is set after the processing - of the current event has finished - which seems like the only reliable way - to set focus */ - window.setTimeout(function() { - var el=$el[0], pos=$el.val().length, range; - - $el.focus(); - - /* make sure el received focus so we do not error out when trying to manipulate the caret. - sometimes modals or others listeners may steal it after its set */ - if ($el.is(":visible") && el === document.activeElement) { - - /* after the focus is set move the caret to the end, necessary when we val() - just before setting focus */ - if(el.setSelectionRange) - { - el.setSelectionRange(pos, pos); - } - else if (el.createTextRange) { - range = el.createTextRange(); - range.collapse(false); - range.select(); - } - } - }, 0); - } - - function getCursorInfo(el) { - el = $(el)[0]; - var offset = 0; - var length = 0; - if ('selectionStart' in el) { - offset = el.selectionStart; - length = el.selectionEnd - offset; - } else if ('selection' in document) { - el.focus(); - var sel = document.selection.createRange(); - length = document.selection.createRange().text.length; - sel.moveStart('character', -el.value.length); - offset = sel.text.length - length; - } - return { offset: offset, length: length }; - } - - function killEvent(event) { - event.preventDefault(); - event.stopPropagation(); - } - function killEventImmediately(event) { - event.preventDefault(); - event.stopImmediatePropagation(); - } - - function measureTextWidth(e) { - if (!sizer){ - var style = e[0].currentStyle || window.getComputedStyle(e[0], null); - sizer = $(document.createElement("div")).css({ - position: "absolute", - left: "-10000px", - top: "-10000px", - display: "none", - fontSize: style.fontSize, - fontFamily: style.fontFamily, - fontStyle: style.fontStyle, - fontWeight: style.fontWeight, - letterSpacing: style.letterSpacing, - textTransform: style.textTransform, - whiteSpace: "nowrap" - }); - sizer.attr("class","select2-sizer"); - $("body").append(sizer); - } - sizer.text(e.val()); - return sizer.width(); - } - - function syncCssClasses(dest, src, adapter) { - var classes, replacements = [], adapted; - - classes = dest.attr("class"); - if (classes) { - classes = '' + classes; // for IE which returns object - $(classes.split(" ")).each2(function() { - if (this.indexOf("select2-") === 0) { - replacements.push(this); - } - }); - } - classes = src.attr("class"); - if (classes) { - classes = '' + classes; // for IE which returns object - $(classes.split(" ")).each2(function() { - if (this.indexOf("select2-") !== 0) { - adapted = adapter(this); - if (adapted) { - replacements.push(this); - } - } - }); - } - dest.attr("class", replacements.join(" ")); - } - - - function markMatch(text, term, markup, escapeMarkup) { - var match=text.toUpperCase().indexOf(term.toUpperCase()), - tl=term.length; - - if (match<0) { - markup.push(escapeMarkup(text)); - return; - } - - markup.push(escapeMarkup(text.substring(0, match))); - markup.push(""); - markup.push(escapeMarkup(text.substring(match, match + tl))); - markup.push(""); - markup.push(escapeMarkup(text.substring(match + tl, text.length))); - } - - /** - * Produces an ajax-based query function - * - * @param options object containing configuration paramters - * @param options.params parameter map for the transport ajax call, can contain such options as cache, jsonpCallback, etc. see $.ajax - * @param options.transport function that will be used to execute the ajax request. must be compatible with parameters supported by $.ajax - * @param options.url url for the data - * @param options.data a function(searchTerm, pageNumber, context) that should return an object containing query string parameters for the above url. - * @param options.dataType request data type: ajax, jsonp, other datatatypes supported by jQuery's $.ajax function or the transport function if specified - * @param options.quietMillis (optional) milliseconds to wait before making the ajaxRequest, helps debounce the ajax function if invoked too often - * @param options.results a function(remoteData, pageNumber) that converts data returned form the remote request to the format expected by Select2. - * The expected format is an object containing the following keys: - * results array of objects that will be used as choices - * more (optional) boolean indicating whether there are more results available - * Example: {results:[{id:1, text:'Red'},{id:2, text:'Blue'}], more:true} - */ - function ajax(options) { - var timeout, // current scheduled but not yet executed request - requestSequence = 0, // sequence used to drop out-of-order responses - handler = null, - quietMillis = options.quietMillis || 100, - ajaxUrl = options.url, - self = this; - - return function (query) { - window.clearTimeout(timeout); - timeout = window.setTimeout(function () { - requestSequence += 1; // increment the sequence - var requestNumber = requestSequence, // this request's sequence number - data = options.data, // ajax data function - url = ajaxUrl, // ajax url string or function - transport = options.transport || $.fn.select2.ajaxDefaults.transport, - // deprecated - to be removed in 4.0 - use params instead - deprecated = { - type: options.type || 'GET', // set type of request (GET or POST) - cache: options.cache || false, - jsonpCallback: options.jsonpCallback||undefined, - dataType: options.dataType||"json" - }, - params = $.extend({}, $.fn.select2.ajaxDefaults.params, deprecated); - - data = data ? data.call(self, query.term, query.page, query.context) : null; - url = (typeof url === 'function') ? url.call(self, query.term, query.page, query.context) : url; - - if( null !== handler) { handler.abort(); } - - if (options.params) { - if ($.isFunction(options.params)) { - $.extend(params, options.params.call(self)); - } else { - $.extend(params, options.params); - } - } - - $.extend(params, { - url: url, - dataType: options.dataType, - data: data, - success: function (data) { - if (requestNumber < requestSequence) { - return; - } - // TODO - replace query.page with query so users have access to term, page, etc. - var results = options.results(data, query.page); - query.callback(results); - } - }); - handler = transport.call(self, params); - }, quietMillis); - }; - } - - /** - * Produces a query function that works with a local array - * - * @param options object containing configuration parameters. The options parameter can either be an array or an - * object. - * - * If the array form is used it is assumed that it contains objects with 'id' and 'text' keys. - * - * If the object form is used ti is assumed that it contains 'data' and 'text' keys. The 'data' key should contain - * an array of objects that will be used as choices. These objects must contain at least an 'id' key. The 'text' - * key can either be a String in which case it is expected that each element in the 'data' array has a key with the - * value of 'text' which will be used to match choices. Alternatively, text can be a function(item) that can extract - * the text. - */ - function local(options) { - var data = options, // data elements - dataText, - tmp, - text = function (item) { return ""+item.text; }; // function used to retrieve the text portion of a data item that is matched against the search - - if ($.isArray(data)) { - tmp = data; - data = { results: tmp }; - } - - if ($.isFunction(data) === false) { - tmp = data; - data = function() { return tmp; }; - } - - var dataItem = data(); - if (dataItem.text) { - text = dataItem.text; - // if text is not a function we assume it to be a key name - if (!$.isFunction(text)) { - dataText = dataItem.text; // we need to store this in a separate variable because in the next step data gets reset and data.text is no longer available - text = function (item) { return item[dataText]; }; - } - } - - return function (query) { - var t = query.term, filtered = { results: [] }, process; - if (t === "") { - query.callback(data()); - return; - } - - process = function(datum, collection) { - var group, attr; - datum = datum[0]; - if (datum.children) { - group = {}; - for (attr in datum) { - if (datum.hasOwnProperty(attr)) group[attr]=datum[attr]; - } - group.children=[]; - $(datum.children).each2(function(i, childDatum) { process(childDatum, group.children); }); - if (group.children.length || query.matcher(t, text(group), datum)) { - collection.push(group); - } - } else { - if (query.matcher(t, text(datum), datum)) { - collection.push(datum); - } - } - }; - - $(data().results).each2(function(i, datum) { process(datum, filtered.results); }); - query.callback(filtered); - }; - } - - // TODO javadoc - function tags(data) { - var isFunc = $.isFunction(data); - return function (query) { - var t = query.term, filtered = {results: []}; - $(isFunc ? data() : data).each(function () { - var isObject = this.text !== undefined, - text = isObject ? this.text : this; - if (t === "" || query.matcher(t, text)) { - filtered.results.push(isObject ? this : {id: this, text: this}); - } - }); - query.callback(filtered); - }; - } - - /** - * Checks if the formatter function should be used. - * - * Throws an error if it is not a function. Returns true if it should be used, - * false if no formatting should be performed. - * - * @param formatter - */ - function checkFormatter(formatter, formatterName) { - if ($.isFunction(formatter)) return true; - if (!formatter) return false; - throw new Error("formatterName must be a function or a falsy value"); - } - - function evaluate(val) { - return $.isFunction(val) ? val() : val; - } - - function countResults(results) { - var count = 0; - $.each(results, function(i, item) { - if (item.children) { - count += countResults(item.children); - } else { - count++; - } - }); - return count; - } - - /** - * Default tokenizer. This function uses breaks the input on substring match of any string from the - * opts.tokenSeparators array and uses opts.createSearchChoice to create the choice object. Both of those - * two options have to be defined in order for the tokenizer to work. - * - * @param input text user has typed so far or pasted into the search field - * @param selection currently selected choices - * @param selectCallback function(choice) callback tho add the choice to selection - * @param opts select2's opts - * @return undefined/null to leave the current input unchanged, or a string to change the input to the returned value - */ - function defaultTokenizer(input, selection, selectCallback, opts) { - var original = input, // store the original so we can compare and know if we need to tell the search to update its text - dupe = false, // check for whether a token we extracted represents a duplicate selected choice - token, // token - index, // position at which the separator was found - i, l, // looping variables - separator; // the matched separator - - if (!opts.createSearchChoice || !opts.tokenSeparators || opts.tokenSeparators.length < 1) return undefined; - - while (true) { - index = -1; - - for (i = 0, l = opts.tokenSeparators.length; i < l; i++) { - separator = opts.tokenSeparators[i]; - index = input.indexOf(separator); - if (index >= 0) break; - } - - if (index < 0) break; // did not find any token separator in the input string, bail - - token = input.substring(0, index); - input = input.substring(index + separator.length); - - if (token.length > 0) { - token = opts.createSearchChoice(token, selection); - if (token !== undefined && token !== null && opts.id(token) !== undefined && opts.id(token) !== null) { - dupe = false; - for (i = 0, l = selection.length; i < l; i++) { - if (equal(opts.id(token), opts.id(selection[i]))) { - dupe = true; break; - } - } - - if (!dupe) selectCallback(token); - } - } - } - - if (original!==input) return input; - } - - /** - * Creates a new class - * - * @param superClass - * @param methods - */ - function clazz(SuperClass, methods) { - var constructor = function () {}; - constructor.prototype = new SuperClass; - constructor.prototype.constructor = constructor; - constructor.prototype.parent = SuperClass.prototype; - constructor.prototype = $.extend(constructor.prototype, methods); - return constructor; - } - - AbstractSelect2 = clazz(Object, { - - // abstract - bind: function (func) { - var self = this; - return function () { - func.apply(self, arguments); - }; - }, - - // abstract - init: function (opts) { - var results, search, resultsSelector = ".select2-results", disabled, readonly; - - // prepare options - this.opts = opts = this.prepareOpts(opts); - - this.id=opts.id; - - // destroy if called on an existing component - if (opts.element.data("select2") !== undefined && - opts.element.data("select2") !== null) { - this.destroy(); - } - - this.container = this.createContainer(); - - this.containerId="s2id_"+(opts.element.attr("id") || "autogen"+nextUid()); - this.containerSelector="#"+this.containerId.replace(/([;&,\.\+\*\~':"\!\^#$%@\[\]\(\)=>\|])/g, '\\$1'); - this.container.attr("id", this.containerId); - - // cache the body so future lookups are cheap - this.body = thunk(function() { return opts.element.closest("body"); }); - - syncCssClasses(this.container, this.opts.element, this.opts.adaptContainerCssClass); - - this.container.css(evaluate(opts.containerCss)); - this.container.addClass(evaluate(opts.containerCssClass)); - - this.elementTabIndex = this.opts.element.attr("tabindex"); - - // swap container for the element - this.opts.element - .data("select2", this) - .attr("tabindex", "-1") - .before(this.container); - this.container.data("select2", this); - - this.dropdown = this.container.find(".select2-drop"); - this.dropdown.addClass(evaluate(opts.dropdownCssClass)); - this.dropdown.data("select2", this); - - this.results = results = this.container.find(resultsSelector); - this.search = search = this.container.find("input.select2-input"); - - this.resultsPage = 0; - this.context = null; - - // initialize the container - this.initContainer(); - - installFilteredMouseMove(this.results); - this.dropdown.on("mousemove-filtered touchstart touchmove touchend", resultsSelector, this.bind(this.highlightUnderEvent)); - - installDebouncedScroll(80, this.results); - this.dropdown.on("scroll-debounced", resultsSelector, this.bind(this.loadMoreIfNeeded)); - - // do not propagate change event from the search field out of the component - $(this.container).on("change", ".select2-input", function(e) {e.stopPropagation();}); - $(this.dropdown).on("change", ".select2-input", function(e) {e.stopPropagation();}); - - // if jquery.mousewheel plugin is installed we can prevent out-of-bounds scrolling of results via mousewheel - if ($.fn.mousewheel) { - results.mousewheel(function (e, delta, deltaX, deltaY) { - var top = results.scrollTop(), height; - if (deltaY > 0 && top - deltaY <= 0) { - results.scrollTop(0); - killEvent(e); - } else if (deltaY < 0 && results.get(0).scrollHeight - results.scrollTop() + deltaY <= results.height()) { - results.scrollTop(results.get(0).scrollHeight - results.height()); - killEvent(e); - } - }); - } - - installKeyUpChangeEvent(search); - search.on("keyup-change input paste", this.bind(this.updateResults)); - search.on("focus", function () { search.addClass("select2-focused"); }); - search.on("blur", function () { search.removeClass("select2-focused");}); - - this.dropdown.on("mouseup", resultsSelector, this.bind(function (e) { - if ($(e.target).closest(".select2-result-selectable").length > 0) { - this.highlightUnderEvent(e); - this.selectHighlighted(e); - } - })); - - // trap all mouse events from leaving the dropdown. sometimes there may be a modal that is listening - // for mouse events outside of itself so it can close itself. since the dropdown is now outside the select2's - // dom it will trigger the popup close, which is not what we want - this.dropdown.on("click mouseup mousedown", function (e) { e.stopPropagation(); }); - - if ($.isFunction(this.opts.initSelection)) { - // initialize selection based on the current value of the source element - this.initSelection(); - - // if the user has provided a function that can set selection based on the value of the source element - // we monitor the change event on the element and trigger it, allowing for two way synchronization - this.monitorSource(); - } - - if (opts.maximumInputLength !== null) { - this.search.attr("maxlength", opts.maximumInputLength); - } - - var disabled = opts.element.prop("disabled"); - if (disabled === undefined) disabled = false; - this.enable(!disabled); - - var readonly = opts.element.prop("readonly"); - if (readonly === undefined) readonly = false; - this.readonly(readonly); - - // Calculate size of scrollbar - scrollBarDimensions = scrollBarDimensions || measureScrollbar(); - - this.autofocus = opts.element.prop("autofocus") - opts.element.prop("autofocus", false); - if (this.autofocus) this.focus(); - }, - - // abstract - destroy: function () { - var select2 = this.opts.element.data("select2"); - - if (this.propertyObserver) { delete this.propertyObserver; this.propertyObserver = null; } - - if (select2 !== undefined) { - - select2.container.remove(); - select2.dropdown.remove(); - select2.opts.element - .removeClass("select2-offscreen") - .removeData("select2") - .off(".select2") - .attr({"tabindex": this.elementTabIndex}) - .prop("autofocus", this.autofocus||false) - .show(); - } - }, - - // abstract - optionToData: function(element) { - if (element.is("option")) { - return { - id:element.prop("value"), - text:element.text(), - element: element.get(), - css: element.attr("class"), - disabled: element.prop("disabled"), - locked: equal(element.attr("locked"), "locked") - }; - } else if (element.is("optgroup")) { - return { - text:element.attr("label"), - children:[], - element: element.get(), - css: element.attr("class") - }; - } - }, - - // abstract - prepareOpts: function (opts) { - var element, select, idKey, ajaxUrl, self = this; - - element = opts.element; - - if (element.get(0).tagName.toLowerCase() === "select") { - this.select = select = opts.element; - } - - if (select) { - // these options are not allowed when attached to a select because they are picked up off the element itself - $.each(["id", "multiple", "ajax", "query", "createSearchChoice", "initSelection", "data", "tags"], function () { - if (this in opts) { - throw new Error("Option '" + this + "' is not allowed for Select2 when attached to a ", - "
" , - " " , - "
    " , - "
" , - "
"].join("")); - return container; - }, - - // single - enableInterface: function() { - if (this.parent.enableInterface.apply(this, arguments)) { - this.focusser.prop("disabled", !this.isInterfaceEnabled()); - } - }, - - // single - opening: function () { - var el, range; - this.parent.opening.apply(this, arguments); - if (this.showSearchInput !== false) { - // IE appends focusser.val() at the end of field :/ so we manually insert it at the beginning using a range - // all other browsers handle this just fine - - this.search.val(this.focusser.val()); - } - this.search.focus(); - // in IE we have to move the cursor to the end after focussing, otherwise it will be at the beginning and - // new text will appear *before* focusser.val() - el = this.search.get(0); - if (el.createTextRange) { - range = el.createTextRange(); - range.collapse(false); - range.select(); - } - - this.focusser.prop("disabled", true).val(""); - this.updateResults(true); - this.opts.element.trigger($.Event("select2-open")); - }, - - // single - close: function () { - if (!this.opened()) return; - this.parent.close.apply(this, arguments); - this.focusser.removeAttr("disabled"); - this.focusser.focus(); - }, - - // single - focus: function () { - if (this.opened()) { - this.close(); - } else { - this.focusser.removeAttr("disabled"); - this.focusser.focus(); - } - }, - - // single - isFocused: function () { - return this.container.hasClass("select2-container-active"); - }, - - // single - cancel: function () { - this.parent.cancel.apply(this, arguments); - this.focusser.removeAttr("disabled"); - this.focusser.focus(); - }, - - // single - initContainer: function () { - - var selection, - container = this.container, - dropdown = this.dropdown; - - this.showSearch(false); - - this.selection = selection = container.find(".select2-choice"); - - this.focusser = container.find(".select2-focusser"); - - // rewrite labels from original element to focusser - this.focusser.attr("id", "s2id_autogen"+nextUid()); - - $("label[for='" + this.opts.element.attr("id") + "']") - .attr('for', this.focusser.attr('id')); - - this.focusser.attr("tabindex", this.elementTabIndex); - - this.search.on("keydown", this.bind(function (e) { - if (!this.isInterfaceEnabled()) return; - - if (e.which === KEY.PAGE_UP || e.which === KEY.PAGE_DOWN) { - // prevent the page from scrolling - killEvent(e); - return; - } - - switch (e.which) { - case KEY.UP: - case KEY.DOWN: - this.moveHighlight((e.which === KEY.UP) ? -1 : 1); - killEvent(e); - return; - case KEY.ENTER: - this.selectHighlighted(); - killEvent(e); - return; - case KEY.TAB: - this.selectHighlighted({noFocus: true}); - return; - case KEY.ESC: - this.cancel(e); - killEvent(e); - return; - } - })); - - this.search.on("blur", this.bind(function(e) { - // a workaround for chrome to keep the search field focussed when the scroll bar is used to scroll the dropdown. - // without this the search field loses focus which is annoying - if (document.activeElement === this.body().get(0)) { - window.setTimeout(this.bind(function() { - this.search.focus(); - }), 0); - } - })); - - this.focusser.on("keydown", this.bind(function (e) { - if (!this.isInterfaceEnabled()) return; - - if (e.which === KEY.TAB || KEY.isControl(e) || KEY.isFunctionKey(e) || e.which === KEY.ESC) { - return; - } - - if (this.opts.openOnEnter === false && e.which === KEY.ENTER) { - killEvent(e); - return; - } - - if (e.which == KEY.DOWN || e.which == KEY.UP - || (e.which == KEY.ENTER && this.opts.openOnEnter)) { - this.open(); - killEvent(e); - return; - } - - if (e.which == KEY.DELETE || e.which == KEY.BACKSPACE) { - if (this.opts.allowClear) { - this.clear(); - } - killEvent(e); - return; - } - })); - - - installKeyUpChangeEvent(this.focusser); - this.focusser.on("keyup-change input", this.bind(function(e) { - e.stopPropagation(); - if (this.opened()) return; - this.open(); - })); - - selection.on("mousedown", "abbr", this.bind(function (e) { - if (!this.isInterfaceEnabled()) return; - this.clear(); - killEventImmediately(e); - this.close(); - this.selection.focus(); - })); - - selection.on("mousedown", this.bind(function (e) { - - if (!this.container.hasClass("select2-container-active")) { - this.opts.element.trigger($.Event("select2-focus")); - } - - if (this.opened()) { - this.close(); - } else if (this.isInterfaceEnabled()) { - this.open(); - } - - killEvent(e); - })); - - dropdown.on("mousedown", this.bind(function() { this.search.focus(); })); - - selection.on("focus", this.bind(function(e) { - killEvent(e); - })); - - this.focusser.on("focus", this.bind(function(){ - if (!this.container.hasClass("select2-container-active")) { - this.opts.element.trigger($.Event("select2-focus")); - } - this.container.addClass("select2-container-active"); - })).on("blur", this.bind(function() { - if (!this.opened()) { - this.container.removeClass("select2-container-active"); - this.opts.element.trigger($.Event("select2-blur")); - } - })); - this.search.on("focus", this.bind(function(){ - if (!this.container.hasClass("select2-container-active")) { - this.opts.element.trigger($.Event("select2-focus")); - } - this.container.addClass("select2-container-active"); - })); - - this.initContainerWidth(); - this.opts.element.addClass("select2-offscreen"); - this.setPlaceholder(); - - }, - - // single - clear: function(triggerChange) { - var data=this.selection.data("select2-data"); - if (data) { // guard against queued quick consecutive clicks - this.opts.element.val(""); - this.selection.find("span").empty(); - this.selection.removeData("select2-data"); - this.setPlaceholder(); - - if (triggerChange !== false){ - this.opts.element.trigger({ type: "select2-removed", val: this.id(data), choice: data }); - this.triggerChange({removed:data}); - } - } - }, - - /** - * Sets selection based on source element's value - */ - // single - initSelection: function () { - var selected; - if (this.opts.element.val() === "" && this.opts.element.text() === "") { - this.updateSelection([]); - this.close(); - this.setPlaceholder(); - } else { - var self = this; - this.opts.initSelection.call(null, this.opts.element, function(selected){ - if (selected !== undefined && selected !== null) { - self.updateSelection(selected); - self.close(); - self.setPlaceholder(); - } - }); - } - }, - - // single - prepareOpts: function () { - var opts = this.parent.prepareOpts.apply(this, arguments), - self=this; - - if (opts.element.get(0).tagName.toLowerCase() === "select") { - // install the selection initializer - opts.initSelection = function (element, callback) { - var selected = element.find(":selected"); - // a single select box always has a value, no need to null check 'selected' - callback(self.optionToData(selected)); - }; - } else if ("data" in opts) { - // install default initSelection when applied to hidden input and data is local - opts.initSelection = opts.initSelection || function (element, callback) { - var id = element.val(); - //search in data by id, storing the actual matching item - var match = null; - opts.query({ - matcher: function(term, text, el){ - var is_match = equal(id, opts.id(el)); - if (is_match) { - match = el; - } - return is_match; - }, - callback: !$.isFunction(callback) ? $.noop : function() { - callback(match); - } - }); - }; - } - - return opts; - }, - - // single - getPlaceholder: function() { - // if a placeholder is specified on a single select without the first empty option ignore it - if (this.select) { - if (this.select.find("option").first().text() !== "") { - return undefined; - } - } - - return this.parent.getPlaceholder.apply(this, arguments); - }, - - // single - setPlaceholder: function () { - var placeholder = this.getPlaceholder(); - - if (this.opts.element.val() === "" && placeholder !== undefined) { - - // check for a first blank option if attached to a select - if (this.select && this.select.find("option:first").text() !== "") return; - - this.selection.find("span").html(this.opts.escapeMarkup(placeholder)); - - this.selection.addClass("select2-default"); - - this.container.removeClass("select2-allowclear"); - } - }, - - // single - postprocessResults: function (data, initial, noHighlightUpdate) { - var selected = 0, self = this, showSearchInput = true; - - // find the selected element in the result list - - this.findHighlightableChoices().each2(function (i, elm) { - if (equal(self.id(elm.data("select2-data")), self.opts.element.val())) { - selected = i; - return false; - } - }); - - // and highlight it - if (noHighlightUpdate !== false) { - this.highlight(selected); - } - - // show the search box if this is the first we got the results and there are enough of them for search - - if (initial === true && this.showSearchInput === false) { - var min=this.opts.minimumResultsForSearch; - if (min>=0) { - this.showSearch(countResults(data.results)>=min); - } - } - - }, - - // single - showSearch: function(showSearchInput) { - this.showSearchInput = showSearchInput; - - this.dropdown.find(".select2-search").toggleClass("select2-search-hidden", !showSearchInput); - this.dropdown.find(".select2-search").toggleClass("select2-offscreen", !showSearchInput); - //add "select2-with-searchbox" to the container if search box is shown - $(this.dropdown, this.container).toggleClass("select2-with-searchbox", showSearchInput); - }, - - // single - onSelect: function (data, options) { - - if (!this.triggerSelect(data)) { return; } - - var old = this.opts.element.val(), - oldData = this.data(); - - this.opts.element.val(this.id(data)); - this.updateSelection(data); - - this.opts.element.trigger({ type: "select2-selected", val: this.id(data), choice: data }); - - this.close(); - - if (!options || !options.noFocus) - this.selection.focus(); - - if (!equal(old, this.id(data))) { this.triggerChange({added:data,removed:oldData}); } - }, - - // single - updateSelection: function (data) { - - var container=this.selection.find("span"), formatted; - - this.selection.data("select2-data", data); - - container.empty(); - formatted=this.opts.formatSelection(data, container); - if (formatted !== undefined) { - container.append(this.opts.escapeMarkup(formatted)); - } - - this.selection.removeClass("select2-default"); - - if (this.opts.allowClear && this.getPlaceholder() !== undefined) { - this.container.addClass("select2-allowclear"); - } - }, - - // single - val: function () { - var val, - triggerChange = false, - data = null, - self = this, - oldData = this.data(); - - if (arguments.length === 0) { - return this.opts.element.val(); - } - - val = arguments[0]; - - if (arguments.length > 1) { - triggerChange = arguments[1]; - } - - if (this.select) { - this.select - .val(val) - .find(":selected").each2(function (i, elm) { - data = self.optionToData(elm); - return false; - }); - this.updateSelection(data); - this.setPlaceholder(); - if (triggerChange) { - this.triggerChange({added: data, removed:oldData}); - } - } else { - if (this.opts.initSelection === undefined) { - throw new Error("cannot call val() if initSelection() is not defined"); - } - // val is an id. !val is true for [undefined,null,'',0] - 0 is legal - if (!val && val !== 0) { - this.clear(triggerChange); - return; - } - this.opts.element.val(val); - this.opts.initSelection(this.opts.element, function(data){ - self.opts.element.val(!data ? "" : self.id(data)); - self.updateSelection(data); - self.setPlaceholder(); - if (triggerChange) { - self.triggerChange({added: data, removed:oldData}); - } - }); - } - }, - - // single - clearSearch: function () { - this.search.val(""); - this.focusser.val(""); - }, - - // single - data: function(value, triggerChange) { - var data; - - if (arguments.length === 0) { - data = this.selection.data("select2-data"); - if (data == undefined) data = null; - return data; - } else { - if (!value || value === "") { - this.clear(triggerChange); - } else { - data = this.data(); - this.opts.element.val(!value ? "" : this.id(value)); - this.updateSelection(value); - if (triggerChange) { - this.triggerChange({added: value, removed:data}); - } - } - } - } - }); - - MultiSelect2 = clazz(AbstractSelect2, { - - // multi - createContainer: function () { - var container = $(document.createElement("div")).attr({ - "class": "select2-container select2-container-multi" - }).html([ - "
    ", - //"
  • California
  • " , - "
  • " , - " " , - "
  • " , - "
" , - "
" , - "
    " , - "
" , - "
"].join("")); - return container; - }, - - // multi - prepareOpts: function () { - var opts = this.parent.prepareOpts.apply(this, arguments), - self=this; - - // TODO validate placeholder is a string if specified - - if (opts.element.get(0).tagName.toLowerCase() === "select") { - // install sthe selection initializer - opts.initSelection = function (element, callback) { - - var data = []; - - element.find(":selected").each2(function (i, elm) { - data.push(self.optionToData(elm)); - }); - callback(data); - }; - } else if ("data" in opts) { - // install default initSelection when applied to hidden input and data is local - opts.initSelection = opts.initSelection || function (element, callback) { - var ids = splitVal(element.val(), opts.separator); - //search in data by array of ids, storing matching items in a list - var matches = []; - opts.query({ - matcher: function(term, text, el){ - var is_match = $.grep(ids, function(id) { - return equal(id, opts.id(el)); - }).length; - if (is_match) { - matches.push(el); - } - return is_match; - }, - callback: !$.isFunction(callback) ? $.noop : function() { - // reorder matches based on the order they appear in the ids array because right now - // they are in the order in which they appear in data array - var ordered = []; - for (var i = 0; i < ids.length; i++) { - var id = ids[i]; - for (var j = 0; j < matches.length; j++) { - var match = matches[j]; - if (equal(id, opts.id(match))) { - ordered.push(match); - matches.splice(j, 1); - break; - } - } - } - callback(ordered); - } - }); - }; - } - - return opts; - }, - - selectChoice: function (choice) { - - var selected = this.container.find(".select2-search-choice-focus"); - if (selected.length && choice && choice[0] == selected[0]) { - - } else { - if (selected.length) { - this.opts.element.trigger("choice-deselected", selected); - } - selected.removeClass("select2-search-choice-focus"); - if (choice && choice.length) { - this.close(); - choice.addClass("select2-search-choice-focus"); - this.opts.element.trigger("choice-selected", choice); - } - } - }, - - // multi - initContainer: function () { - - var selector = ".select2-choices", selection; - - this.searchContainer = this.container.find(".select2-search-field"); - this.selection = selection = this.container.find(selector); - - var _this = this; - this.selection.on("mousedown", ".select2-search-choice", function (e) { - //killEvent(e); - _this.search[0].focus(); - _this.selectChoice($(this)); - }) - //.sortable({ - // items: " > li", - // tolerance: "pointer", - // revert: 100 - //}); - - // rewrite labels from original element to focusser - this.search.attr("id", "s2id_autogen"+nextUid()); - $("label[for='" + this.opts.element.attr("id") + "']") - .attr('for', this.search.attr('id')); - - this.search.on("input paste", this.bind(function() { - if (!this.isInterfaceEnabled()) return; - if (!this.opened()) { - this.open(); - } - })); - - this.search.attr("tabindex", this.elementTabIndex); - - this.keydowns = 0; - this.search.on("keydown", this.bind(function (e) { - if (!this.isInterfaceEnabled()) return; - - ++this.keydowns; - var selected = selection.find(".select2-search-choice-focus"); - var prev = selected.prev(".select2-search-choice:not(.select2-locked)"); - var next = selected.next(".select2-search-choice:not(.select2-locked)"); - var pos = getCursorInfo(this.search); - - if (selected.length && - (e.which == KEY.LEFT || e.which == KEY.RIGHT || e.which == KEY.BACKSPACE || e.which == KEY.DELETE || e.which == KEY.ENTER)) { - var selectedChoice = selected; - if (e.which == KEY.LEFT && prev.length) { - selectedChoice = prev; - } - else if (e.which == KEY.RIGHT) { - selectedChoice = next.length ? next : null; - } - else if (e.which === KEY.BACKSPACE) { - this.unselect(selected.first()); - this.search.width(10); - selectedChoice = prev.length ? prev : next; - } else if (e.which == KEY.DELETE) { - this.unselect(selected.first()); - this.search.width(10); - selectedChoice = next.length ? next : null; - } else if (e.which == KEY.ENTER) { - selectedChoice = null; - } - - this.selectChoice(selectedChoice); - killEvent(e); - if (!selectedChoice || !selectedChoice.length) { - this.open(); - } - return; - } else if (((e.which === KEY.BACKSPACE && this.keydowns == 1) - || e.which == KEY.LEFT) && (pos.offset == 0 && !pos.length)) { - - this.selectChoice(selection.find(".select2-search-choice:not(.select2-locked)").last()); - killEvent(e); - return; - } else { - this.selectChoice(null); - } - - if (this.opened()) { - switch (e.which) { - case KEY.UP: - case KEY.DOWN: - this.moveHighlight((e.which === KEY.UP) ? -1 : 1); - killEvent(e); - return; - case KEY.ENTER: - this.selectHighlighted(); - killEvent(e); - return; - case KEY.TAB: - this.selectHighlighted({noFocus:true}); - return; - case KEY.ESC: - this.cancel(e); - killEvent(e); - return; - } - } - - if (e.which === KEY.TAB || KEY.isControl(e) || KEY.isFunctionKey(e) - || e.which === KEY.BACKSPACE || e.which === KEY.ESC) { - return; - } - - if (e.which === KEY.ENTER) { - if (this.opts.openOnEnter === false) { - return; - } else if (e.altKey || e.ctrlKey || e.shiftKey || e.metaKey) { - return; - } - } - - this.open(); - - if (e.which === KEY.PAGE_UP || e.which === KEY.PAGE_DOWN) { - // prevent the page from scrolling - killEvent(e); - } - - if (e.which === KEY.ENTER) { - // prevent form from being submitted - killEvent(e); - } - - })); - - this.search.on("keyup", this.bind(function (e) { - this.keydowns = 0; - this.resizeSearch(); - }) - ); - - this.search.on("blur", this.bind(function(e) { - this.container.removeClass("select2-container-active"); - this.search.removeClass("select2-focused"); - this.selectChoice(null); - if (!this.opened()) this.clearSearch(); - e.stopImmediatePropagation(); - this.opts.element.trigger($.Event("select2-blur")); - })); - - this.container.on("mousedown", selector, this.bind(function (e) { - if (!this.isInterfaceEnabled()) return; - if ($(e.target).closest(".select2-search-choice").length > 0) { - // clicked inside a select2 search choice, do not open - return; - } - this.selectChoice(null); - this.clearPlaceholder(); - if (!this.container.hasClass("select2-container-active")) { - this.opts.element.trigger($.Event("select2-focus")); - } - this.open(); - this.focusSearch(); - e.preventDefault(); - })); - - this.container.on("focus", selector, this.bind(function () { - if (!this.isInterfaceEnabled()) return; - if (!this.container.hasClass("select2-container-active")) { - this.opts.element.trigger($.Event("select2-focus")); - } - this.container.addClass("select2-container-active"); - this.dropdown.addClass("select2-drop-active"); - this.clearPlaceholder(); - })); - - this.initContainerWidth(); - this.opts.element.addClass("select2-offscreen"); - - // set the placeholder if necessary - this.clearSearch(); - }, - - // multi - enableInterface: function() { - if (this.parent.enableInterface.apply(this, arguments)) { - this.search.prop("disabled", !this.isInterfaceEnabled()); - } - }, - - // multi - initSelection: function () { - var data; - if (this.opts.element.val() === "" && this.opts.element.text() === "") { - this.updateSelection([]); - this.close(); - // set the placeholder if necessary - this.clearSearch(); - } - if (this.select || this.opts.element.val() !== "") { - var self = this; - this.opts.initSelection.call(null, this.opts.element, function(data){ - if (data !== undefined && data !== null) { - self.updateSelection(data); - self.close(); - // set the placeholder if necessary - self.clearSearch(); - } - }); - } - }, - - // multi - clearSearch: function () { - var placeholder = this.getPlaceholder(), - maxWidth = this.getMaxSearchWidth(); - - if (placeholder !== undefined && this.getVal().length === 0 && this.search.hasClass("select2-focused") === false) { - this.search.val(placeholder).addClass("select2-default"); - // stretch the search box to full width of the container so as much of the placeholder is visible as possible - // we could call this.resizeSearch(), but we do not because that requires a sizer and we do not want to create one so early because of a firefox bug, see #944 - this.search.width(maxWidth > 0 ? maxWidth : this.container.css("width")); - } else { - this.search.val("").width(10); - } - }, - - // multi - clearPlaceholder: function () { - if (this.search.hasClass("select2-default")) { - this.search.val("").removeClass("select2-default"); - } - }, - - // multi - opening: function () { - this.clearPlaceholder(); // should be done before super so placeholder is not used to search - this.resizeSearch(); - - this.parent.opening.apply(this, arguments); - - this.focusSearch(); - - this.updateResults(true); - this.search.focus(); - this.opts.element.trigger($.Event("select2-open")); - }, - - // multi - close: function () { - if (!this.opened()) return; - this.parent.close.apply(this, arguments); - }, - - // multi - focus: function () { - this.close(); - this.search.focus(); - //this.opts.element.triggerHandler("focus"); - }, - - // multi - isFocused: function () { - return this.search.hasClass("select2-focused"); - }, - - // multi - updateSelection: function (data) { - var ids = [], filtered = [], self = this; - - // filter out duplicates - $(data).each(function () { - if (indexOf(self.id(this), ids) < 0) { - ids.push(self.id(this)); - filtered.push(this); - } - }); - data = filtered; - - this.selection.find(".select2-search-choice").remove(); - $(data).each(function () { - self.addSelectedChoice(this); - }); - self.postprocessResults(); - }, - - // multi - tokenize: function() { - var input = this.search.val(); - input = this.opts.tokenizer(input, this.data(), this.bind(this.onSelect), this.opts); - if (input != null && input != undefined) { - this.search.val(input); - if (input.length > 0) { - this.open(); - } - } - - }, - - // multi - onSelect: function (data, options) { - - if (!this.triggerSelect(data)) { return; } - - this.addSelectedChoice(data); - - this.opts.element.trigger({ type: "selected", val: this.id(data), choice: data }); - - if (this.select || !this.opts.closeOnSelect) this.postprocessResults(); - - if (this.opts.closeOnSelect) { - this.close(); - this.search.width(10); - } else { - if (this.countSelectableResults()>0) { - this.search.width(10); - this.resizeSearch(); - if (this.getMaximumSelectionSize() > 0 && this.val().length >= this.getMaximumSelectionSize()) { - // if we reached max selection size repaint the results so choices - // are replaced with the max selection reached message - this.updateResults(true); - } - this.positionDropdown(); - } else { - // if nothing left to select close - this.close(); - this.search.width(10); - } - } - - // since its not possible to select an element that has already been - // added we do not need to check if this is a new element before firing change - this.triggerChange({ added: data }); - - if (!options || !options.noFocus) - this.focusSearch(); - }, - - // multi - cancel: function () { - this.close(); - this.focusSearch(); - }, - - addSelectedChoice: function (data) { - var enableChoice = !data.locked, - enabledItem = $( - "
  • " + - "
    " + - " " + - "
  • "), - disabledItem = $( - "
  • " + - "
    " + - "
  • "); - var choice = enableChoice ? enabledItem : disabledItem, - id = this.id(data), - val = this.getVal(), - formatted; - - formatted=this.opts.formatSelection(data, choice.find("div")); - if (formatted != undefined) { - choice.find("div").replaceWith("
    "+this.opts.escapeMarkup(formatted)+"
    "); - } - - if(enableChoice){ - choice.find(".select2-search-choice-close") - .on("mousedown", killEvent) - .on("click dblclick", this.bind(function (e) { - if (!this.isInterfaceEnabled()) return; - - $(e.target).closest(".select2-search-choice").fadeOut('fast', this.bind(function(){ - this.unselect($(e.target)); - this.selection.find(".select2-search-choice-focus").removeClass("select2-search-choice-focus"); - this.close(); - this.focusSearch(); - })).dequeue(); - killEvent(e); - })).on("focus", this.bind(function () { - if (!this.isInterfaceEnabled()) return; - this.container.addClass("select2-container-active"); - this.dropdown.addClass("select2-drop-active"); - })); - } - - choice.data("select2-data", data); - choice.insertBefore(this.searchContainer); - - val.push(id); - this.setVal(val); - }, - - // multi - unselect: function (selected) { - var val = this.getVal(), - data, - index; - - selected = selected.closest(".select2-search-choice"); - - if (selected.length === 0) { - throw "Invalid argument: " + selected + ". Must be .select2-search-choice"; - } - - data = selected.data("select2-data"); - - if (!data) { - // prevent a race condition when the 'x' is clicked really fast repeatedly the event can be queued - // and invoked on an element already removed - return; - } - - index = indexOf(this.id(data), val); - - if (index >= 0) { - val.splice(index, 1); - this.setVal(val); - if (this.select) this.postprocessResults(); - } - selected.remove(); - - this.opts.element.trigger({ type: "removed", val: this.id(data), choice: data }); - this.triggerChange({ removed: data }); - }, - - // multi - postprocessResults: function (data, initial, noHighlightUpdate) { - var val = this.getVal(), - choices = this.results.find(".select2-result"), - compound = this.results.find(".select2-result-with-children"), - self = this; - - choices.each2(function (i, choice) { - var id = self.id(choice.data("select2-data")); - if (indexOf(id, val) >= 0) { - choice.addClass("select2-selected"); - // mark all children of the selected parent as selected - choice.find(".select2-result-selectable").addClass("select2-selected"); - } - }); - - compound.each2(function(i, choice) { - // hide an optgroup if it doesnt have any selectable children - if (!choice.is('.select2-result-selectable') - && choice.find(".select2-result-selectable:not(.select2-selected)").length === 0) { - choice.addClass("select2-selected"); - } - }); - - if (this.highlight() == -1 && noHighlightUpdate !== false){ - self.highlight(0); - } - - //If all results are chosen render formatNoMAtches - if(!this.opts.createSearchChoice && !choices.filter('.select2-result:not(.select2-selected)').length > 0){ - this.results.append("
  • " + self.opts.formatNoMatches(self.search.val()) + "
  • "); - } - - }, - - // multi - getMaxSearchWidth: function() { - return this.selection.width() - getSideBorderPadding(this.search); - }, - - // multi - resizeSearch: function () { - var minimumWidth, left, maxWidth, containerLeft, searchWidth, - sideBorderPadding = getSideBorderPadding(this.search); - - minimumWidth = measureTextWidth(this.search) + 10; - - left = this.search.offset().left; - - maxWidth = this.selection.width(); - containerLeft = this.selection.offset().left; - - searchWidth = maxWidth - (left - containerLeft) - sideBorderPadding; - - if (searchWidth < minimumWidth) { - searchWidth = maxWidth - sideBorderPadding; - } - - if (searchWidth < 40) { - searchWidth = maxWidth - sideBorderPadding; - } - - if (searchWidth <= 0) { - searchWidth = minimumWidth; - } - - this.search.width(searchWidth); - }, - - // multi - getVal: function () { - var val; - if (this.select) { - val = this.select.val(); - return val === null ? [] : val; - } else { - val = this.opts.element.val(); - return splitVal(val, this.opts.separator); - } - }, - - // multi - setVal: function (val) { - var unique; - if (this.select) { - this.select.val(val); - } else { - unique = []; - // filter out duplicates - $(val).each(function () { - if (indexOf(this, unique) < 0) unique.push(this); - }); - this.opts.element.val(unique.length === 0 ? "" : unique.join(this.opts.separator)); - } - }, - - // multi - buildChangeDetails: function (old, current) { - var current = current.slice(0), - old = old.slice(0); - - // remove intersection from each array - for (var i = 0; i < current.length; i++) { - for (var j = 0; j < old.length; j++) { - if (equal(this.opts.id(current[i]), this.opts.id(old[j]))) { - current.splice(i, 1); - i--; - old.splice(j, 1); - j--; - } - } - } - - return {added: current, removed: old}; - }, - - - // multi - val: function (val, triggerChange) { - var oldData, self=this, changeDetails; - - if (arguments.length === 0) { - return this.getVal(); - } - - oldData=this.data(); - if (!oldData.length) oldData=[]; - - // val is an id. !val is true for [undefined,null,'',0] - 0 is legal - if (!val && val !== 0) { - this.opts.element.val(""); - this.updateSelection([]); - this.clearSearch(); - if (triggerChange) { - this.triggerChange({added: this.data(), removed: oldData}); - } - return; - } - - // val is a list of ids - this.setVal(val); - - if (this.select) { - this.opts.initSelection(this.select, this.bind(this.updateSelection)); - if (triggerChange) { - this.triggerChange(this.buildChangeDetails(oldData, this.data())); - } - } else { - if (this.opts.initSelection === undefined) { - throw new Error("val() cannot be called if initSelection() is not defined"); - } - - this.opts.initSelection(this.opts.element, function(data){ - var ids=$(data).map(self.id); - self.setVal(ids); - self.updateSelection(data); - self.clearSearch(); - if (triggerChange) { - self.triggerChange(this.buildChangeDetails(oldData, this.data())); - } - }); - } - this.clearSearch(); - }, - - // multi - onSortStart: function() { - if (this.select) { - throw new Error("Sorting of elements is not supported when attached to instead."); - } - - // collapse search field into 0 width so its container can be collapsed as well - this.search.width(0); - // hide the container - this.searchContainer.hide(); - }, - - // multi - onSortEnd:function() { - - var val=[], self=this; - - // show search and move it to the end of the list - this.searchContainer.show(); - // make sure the search container is the last item in the list - this.searchContainer.appendTo(this.searchContainer.parent()); - // since we collapsed the width in dragStarted, we resize it here - this.resizeSearch(); - - // update selection - - this.selection.find(".select2-search-choice").each(function() { - val.push(self.opts.id($(this).data("select2-data"))); - }); - this.setVal(val); - this.triggerChange(); - }, - - // multi - data: function(values, triggerChange) { - var self=this, ids, old; - if (arguments.length === 0) { - return this.selection - .find(".select2-search-choice") - .map(function() { return $(this).data("select2-data"); }) - .get(); - } else { - old = this.data(); - if (!values) { values = []; } - ids = $.map(values, function(e) { return self.opts.id(e); }); - this.setVal(ids); - this.updateSelection(values); - this.clearSearch(); - if (triggerChange) { - this.triggerChange(this.buildChangeDetails(old, this.data())); - } - } - } - }); - - $.fn.select2 = function () { - - var args = Array.prototype.slice.call(arguments, 0), - opts, - select2, - value, multiple, - allowedMethods = ["val", "destroy", "opened", "open", "close", "focus", "isFocused", "container", "onSortStart", "onSortEnd", "enable", "readonly", "positionDropdown", "data"], - valueMethods = ["val", "opened", "isFocused", "container", "data"]; - - this.each(function () { - if (args.length === 0 || typeof(args[0]) === "object") { - opts = args.length === 0 ? {} : $.extend({}, args[0]); - opts.element = $(this); - - if (opts.element.get(0).tagName.toLowerCase() === "select") { - multiple = opts.element.prop("multiple"); - } else { - multiple = opts.multiple || false; - if ("tags" in opts) {opts.multiple = multiple = true;} - } - - select2 = multiple ? new MultiSelect2() : new SingleSelect2(); - select2.init(opts); - } else if (typeof(args[0]) === "string") { - - if (indexOf(args[0], allowedMethods) < 0) { - throw "Unknown method: " + args[0]; - } - - value = undefined; - select2 = $(this).data("select2"); - if (select2 === undefined) return; - if (args[0] === "container") { - value=select2.container; - } else { - value = select2[args[0]].apply(select2, args.slice(1)); - } - if (indexOf(args[0], valueMethods) >= 0) { - return false; - } - } else { - throw "Invalid arguments to select2 plugin: " + args; - } - }); - return (value === undefined) ? this : value; - }; - - // plugin defaults, accessible to users - $.fn.select2.defaults = { - width: "copy", - loadMorePadding: 0, - closeOnSelect: true, - openOnEnter: true, - containerCss: {}, - dropdownCss: {}, - containerCssClass: "", - dropdownCssClass: "", - formatResult: function(result, container, query, escapeMarkup) { - var markup=[]; - markMatch(result.text, query.term, markup, escapeMarkup); - return markup.join(""); - }, - formatSelection: function (data, container) { - return data ? data.text : undefined; - }, - sortResults: function (results, container, query) { - return results; - }, - formatResultCssClass: function(data) {return undefined;}, - formatNoMatches: function () { return "No matches found"; }, - formatInputTooShort: function (input, min) { var n = min - input.length; return "Please enter " + n + " more character" + (n == 1? "" : "s"); }, - formatInputTooLong: function (input, max) { var n = input.length - max; return "Please delete " + n + " character" + (n == 1? "" : "s"); }, - formatSelectionTooBig: function (limit) { return "You can only select " + limit + " item" + (limit == 1 ? "" : "s"); }, - formatLoadMore: function (pageNumber) { return "Loading more results..."; }, - formatSearching: function () { return "Searching..."; }, - minimumResultsForSearch: 0, - minimumInputLength: 0, - maximumInputLength: null, - maximumSelectionSize: 0, - id: function (e) { return e.id; }, - matcher: function(term, text) { - return (''+text).toUpperCase().indexOf((''+term).toUpperCase()) >= 0; - }, - separator: ",", - tokenSeparators: [], - tokenizer: defaultTokenizer, - escapeMarkup: function (markup) { - var replace_map = { - '\\': '\', - '&': '&', - '<': '<', - '>': '>', - '"': '"', - "'": ''', - "/": '/' - }; - - return String(markup).replace(/[&<>"'\/\\]/g, function (match) { - return replace_map[match]; - }); - }, - blurOnChange: false, - selectOnBlur: false, - adaptContainerCssClass: function(c) { return c; }, - adaptDropdownCssClass: function(c) { return null; } - }; - - $.fn.select2.ajaxDefaults = { - transport: $.ajax, - params: { - type: "GET", - cache: false, - dataType: "json" - } - }; - - // exports - window.Select2 = { - query: { - ajax: ajax, - local: local, - tags: tags - }, util: { - debounce: debounce, - markMatch: markMatch - }, "class": { - "abstract": AbstractSelect2, - "single": SingleSelect2, - "multi": MultiSelect2 - } - }; - -}(jQuery)); diff --git a/circle/network/static/js/select2-3.4.0/select2.png b/circle/network/static/js/select2-3.4.0/select2.png deleted file mode 100644 index 1d804ff..0000000 Binary files a/circle/network/static/js/select2-3.4.0/select2.png and /dev/null differ diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_ca.js b/circle/network/static/js/select2-3.4.0/select2_locale_ca.js deleted file mode 100644 index bdcdaa7..0000000 --- a/circle/network/static/js/select2-3.4.0/select2_locale_ca.js +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Select2 Catalan translation. - * - * Author: David Planella - */ -(function ($) { - "use strict"; - - $.extend($.fn.select2.defaults, { - formatNoMatches: function () { return "No s'ha trobat cap coincidència"; }, - formatInputTooShort: function (input, min) { var n = min - input.length; return "Introduïu " + n + " caràcter" + (n == 1 ? "" : "s") + " més"; }, - formatInputTooLong: function (input, max) { var n = input.length - max; return "Introduïu " + n + " caràcter" + (n == 1? "" : "s") + "menys"; }, - formatSelectionTooBig: function (limit) { return "Només podeu seleccionar " + limit + " element" + (limit == 1 ? "" : "s"); }, - formatLoadMore: function (pageNumber) { return "S'estan carregant més resultats..."; }, - formatSearching: function () { return "S'està cercant..."; } - }); -})(jQuery); diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_cs.js b/circle/network/static/js/select2-3.4.0/select2_locale_cs.js deleted file mode 100644 index 2055f08..0000000 --- a/circle/network/static/js/select2-3.4.0/select2_locale_cs.js +++ /dev/null @@ -1,49 +0,0 @@ -/** - * Select2 Czech translation. - * - * Author: Michal Marek - * Author - sklonovani: David Vallner - */ -(function ($) { - "use strict"; - // use text for the numbers 2 through 4 - var smallNumbers = { - 2: function(masc) { return (masc ? "dva" : "dvě"); }, - 3: function() { return "tři"; }, - 4: function() { return "čtyři"; } - } - $.extend($.fn.select2.defaults, { - formatNoMatches: function () { return "Nenalezeny žádné položky"; }, - formatInputTooShort: function (input, min) { - var n = min - input.length; - if (n == 1) { - return "Prosím zadejte ještě jeden znak"; - } else if (n <= 4) { - return "Prosím zadejte ještě další "+smallNumbers[n](true)+" znaky"; - } else { - return "Prosím zadejte ještě dalších "+n+" znaků"; - } - }, - formatInputTooLong: function (input, max) { - var n = input.length - max; - if (n == 1) { - return "Prosím zadejte o jeden znak méně"; - } else if (n <= 4) { - return "Prosím zadejte o "+smallNumbers[n](true)+" znaky méně"; - } else { - return "Prosím zadejte o "+n+" znaků méně"; - } - }, - formatSelectionTooBig: function (limit) { - if (limit == 1) { - return "Můžete zvolit jen jednu položku"; - } else if (limit <= 4) { - return "Můžete zvolit maximálně "+smallNumbers[limit](false)+" položky"; - } else { - return "Můžete zvolit maximálně "+limit+" položek"; - } - }, - formatLoadMore: function (pageNumber) { return "Načítavají se další výsledky..."; }, - formatSearching: function () { return "Vyhledávání..."; } - }); -})(jQuery); diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_da.js b/circle/network/static/js/select2-3.4.0/select2_locale_da.js deleted file mode 100644 index dbce3e1..0000000 --- a/circle/network/static/js/select2-3.4.0/select2_locale_da.js +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Select2 Danish translation. - * - * Author: Anders Jenbo - */ -(function ($) { - "use strict"; - - $.extend($.fn.select2.defaults, { - formatNoMatches: function () { return "Ingen resultater fundet"; }, - formatInputTooShort: function (input, min) { var n = min - input.length; return "Angiv venligst " + n + " tegn mere"; }, - formatInputTooLong: function (input, max) { var n = input.length - max; return "Angiv venligst " + n + " tegn mindre"; }, - formatSelectionTooBig: function (limit) { return "Du kan kun vælge " + limit + " emne" + (limit === 1 ? "" : "r"); }, - formatLoadMore: function (pageNumber) { return "Indlæser flere resultater…"; }, - formatSearching: function () { return "Søger…"; } - }); -})(jQuery); diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_de.js b/circle/network/static/js/select2-3.4.0/select2_locale_de.js deleted file mode 100644 index 01f94ed..0000000 --- a/circle/network/static/js/select2-3.4.0/select2_locale_de.js +++ /dev/null @@ -1,15 +0,0 @@ -/** - * Select2 German translation - */ -(function ($) { - "use strict"; - - $.extend($.fn.select2.defaults, { - formatNoMatches: function () { return "Keine Übereinstimmungen gefunden"; }, - formatInputTooShort: function (input, min) { var n = min - input.length; return "Bitte " + n + " Zeichen mehr eingeben"; }, - formatInputTooLong: function (input, max) { var n = input.length - max; return "Bitte " + n + " Zeichen weniger eingeben"; }, - formatSelectionTooBig: function (limit) { return "Sie können nur " + limit + " Eintr" + (limit === 1 ? "ag" : "äge") + " auswählen"; }, - formatLoadMore: function (pageNumber) { return "Lade mehr Ergebnisse..."; }, - formatSearching: function () { return "Suche..."; } - }); -})(jQuery); \ No newline at end of file diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_en.js.template b/circle/network/static/js/select2-3.4.0/select2_locale_en.js.template deleted file mode 100644 index 260c6c4..0000000 --- a/circle/network/static/js/select2-3.4.0/select2_locale_en.js.template +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Select2 translation. - * - * Author: Your Name - */ -(function ($) { - "use strict"; - - $.extend($.fn.select2.defaults, { - formatNoMatches: function () { return "No matches found"; }, - formatInputTooShort: function (input, min) { var n = min - input.length; return "Please enter " + n + " more character" + (n == 1 ? "" : "s"); }, - formatInputTooLong: function (input, max) { var n = input.length - max; return "Please enter " + n + " less character" + (n == 1? "" : "s"); }, - formatSelectionTooBig: function (limit) { return "You can only select " + limit + " item" + (limit == 1 ? "" : "s"); }, - formatLoadMore: function (pageNumber) { return "Loading more results..."; }, - formatSearching: function () { return "Searching..."; } - }); -})(jQuery); diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_es.js b/circle/network/static/js/select2-3.4.0/select2_locale_es.js deleted file mode 100644 index 1b0a021..0000000 --- a/circle/network/static/js/select2-3.4.0/select2_locale_es.js +++ /dev/null @@ -1,15 +0,0 @@ -/** - * Select2 Spanish translation - */ -(function ($) { - "use strict"; - - $.extend($.fn.select2.defaults, { - formatNoMatches: function () { return "No se encontraron resultados"; }, - formatInputTooShort: function (input, min) { var n = min - input.length; return "Por favor adicione " + n + " caracter" + (n == 1? "" : "es"); }, - formatInputTooLong: function (input, max) { var n = input.length - max; return "Por favor elimine " + n + " caracter" + (n == 1? "" : "es"); }, - formatSelectionTooBig: function (limit) { return "Solo puede seleccionar " + limit + " elemento" + (limit == 1 ? "" : "s"); }, - formatLoadMore: function (pageNumber) { return "Cargando más resultados..."; }, - formatSearching: function () { return "Buscando..."; } - }); -})(jQuery); \ No newline at end of file diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_et.js b/circle/network/static/js/select2-3.4.0/select2_locale_et.js deleted file mode 100644 index a4045d2..0000000 --- a/circle/network/static/js/select2-3.4.0/select2_locale_et.js +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Select2 Estonian translation. - * - * Author: Kuldar Kalvik - */ -(function ($) { - "use strict"; - - $.extend($.fn.select2.defaults, { - formatNoMatches: function () { return "Tulemused puuduvad"; }, - formatInputTooShort: function (input, min) { var n = min - input.length; return "Sisesta " + n + " täht" + (n == 1 ? "" : "e") + " rohkem"; }, - formatInputTooLong: function (input, max) { var n = input.length - max; return "Sisesta " + n + " täht" + (n == 1? "" : "e") + " vähem"; }, - formatSelectionTooBig: function (limit) { return "Saad vaid " + limit + " tulemus" + (limit == 1 ? "e" : "t") + " valida"; }, - formatLoadMore: function (pageNumber) { return "Laen tulemusi.."; }, - formatSearching: function () { return "Otsin.."; } - }); -})(jQuery); diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_eu.js b/circle/network/static/js/select2-3.4.0/select2_locale_eu.js deleted file mode 100644 index 05665f5..0000000 --- a/circle/network/static/js/select2-3.4.0/select2_locale_eu.js +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Select2 Basque translation. - * - * Author: Julen Ruiz Aizpuru - */ -(function ($) { - "use strict"; - - $.extend($.fn.select2.defaults, { - formatNoMatches: function () { - return "Ez da bat datorrenik aurkitu"; - }, - formatInputTooShort: function (input, min) { - var n = min - input.length; - if (n === 1) { - return "Idatzi karaktere bat gehiago"; - } else { - return "Idatzi " + n + " karaktere gehiago"; - } - }, - formatInputTooLong: function (input, max) { - var n = input.length - max; - if (n === 1) { - return "Idatzi karaktere bat gutxiago"; - } else { - return "Idatzi " + n + " karaktere gutxiago"; - } - }, - formatSelectionTooBig: function (limit) { - if (limit === 1 ) { - return "Elementu bakarra hauta dezakezu"; - } else { - return limit + " elementu hauta ditzakezu soilik"; - } - }, - formatLoadMore: function (pageNumber) { - return "Emaitza gehiago kargatzen..."; - }, - formatSearching: function () { - return "Bilatzen..."; - } - }); -})(jQuery); diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_fr.js b/circle/network/static/js/select2-3.4.0/select2_locale_fr.js deleted file mode 100644 index 53c60a6..0000000 --- a/circle/network/static/js/select2-3.4.0/select2_locale_fr.js +++ /dev/null @@ -1,15 +0,0 @@ -/** - * Select2 French translation - */ -(function ($) { - "use strict"; - - $.extend($.fn.select2.defaults, { - formatNoMatches: function () { return "Aucun résultat trouvé"; }, - formatInputTooShort: function (input, min) { var n = min - input.length; return "Merci de saisir " + n + " caractère" + (n == 1? "" : "s") + " de plus"; }, - formatInputTooLong: function (input, max) { var n = input.length - max; return "Merci de saisir " + n + " caractère" + (n == 1? "" : "s") + " de moins"; }, - formatSelectionTooBig: function (limit) { return "Vous pouvez seulement sélectionner " + limit + " élément" + (limit == 1 ? "" : "s"); }, - formatLoadMore: function (pageNumber) { return "Chargement de résultats supplémentaires..."; }, - formatSearching: function () { return "Recherche en cours..."; } - }); -})(jQuery); diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_gl.js b/circle/network/static/js/select2-3.4.0/select2_locale_gl.js deleted file mode 100644 index 1017c20..0000000 --- a/circle/network/static/js/select2-3.4.0/select2_locale_gl.js +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Select2 Galician translation - * - * Author: Leandro Regueiro - */ -(function ($) { - "use strict"; - - $.extend($.fn.select2.defaults, { - formatNoMatches: function () { - return "Non se atoparon resultados"; - }, - formatInputTooShort: function (input, min) { - var n = min - input.length; - if (n === 1) { - return "Engada un carácter"; - } else { - return "Engada " + n + " caracteres"; - } - }, - formatInputTooLong: function (input, max) { - var n = input.length - max; - if (n === 1) { - return "Elimine un carácter"; - } else { - return "Elimine " + n + " caracteres"; - } - }, - formatSelectionTooBig: function (limit) { - if (limit === 1 ) { - return "Só pode seleccionar un elemento"; - } else { - return "Só pode seleccionar " + limit + " elementos"; - } - }, - formatLoadMore: function (pageNumber) { - return "Cargando máis resultados..."; - }, - formatSearching: function () { - return "Buscando..."; - } - }); -})(jQuery); diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_he.js b/circle/network/static/js/select2-3.4.0/select2_locale_he.js deleted file mode 100644 index dd72eaa..0000000 --- a/circle/network/static/js/select2-3.4.0/select2_locale_he.js +++ /dev/null @@ -1,17 +0,0 @@ -/** -* Select2 Hebrew translation. -* -* Author: Yakir Sitbon -*/ -(function ($) { - "use strict"; - - $.extend($.fn.select2.defaults, { - formatNoMatches: function () { return "לא נמצאו התאמות"; }, - formatInputTooShort: function (input, min) { var n = min - input.length; return "נא להזין עוד " + n + " תווים נוספים"; }, - formatInputTooLong: function (input, max) { var n = input.length - max; return "נא להזין פחות " + n + " תווים"; }, - formatSelectionTooBig: function (limit) { return "ניתן לבחור " + limit + " פריטים"; }, - formatLoadMore: function (pageNumber) { return "טוען תוצאות נוספות..."; }, - formatSearching: function () { return "מחפש..."; } - }); -})(jQuery); diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_hr.js b/circle/network/static/js/select2-3.4.0/select2_locale_hr.js deleted file mode 100644 index b061540..0000000 --- a/circle/network/static/js/select2-3.4.0/select2_locale_hr.js +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Select2 Croatian translation. - * - * Author: Edi Modrić - */ -(function ($) { - "use strict"; - - var specialNumbers = { - 1: function(n) { return (n % 100 != 11 ? "znak" : "znakova"); }, - 2: function(n) { return (n % 100 != 12 ? "znaka" : "znakova"); }, - 3: function(n) { return (n % 100 != 13 ? "znaka" : "znakova"); }, - 4: function(n) { return (n % 100 != 14 ? "znaka" : "znakova"); } - }; - - $.extend($.fn.select2.defaults, { - formatNoMatches: function () { return "Nema rezultata"; }, - formatInputTooShort: function (input, min) { - var n = min - input.length; - var nMod10 = n % 10; - - if (nMod10 > 0 && nMod10 < 5) { - return "Unesite još " + n + " " + specialNumbers[nMod10](n); - } - - return "Unesite još " + n + " znakova"; - }, - formatInputTooLong: function (input, max) { - var n = input.length - max; - var nMod10 = n % 10; - - if (nMod10 > 0 && nMod10 < 5) { - return "Unesite " + n + " " + specialNumbers[nMod10](n) + " manje"; - } - - return "Unesite " + n + " znakova manje"; - }, - formatSelectionTooBig: function (limit) { return "Maksimalan broj odabranih stavki je " + limit; }, - formatLoadMore: function (pageNumber) { return "Učitavanje rezultata..."; }, - formatSearching: function () { return "Pretraga..."; } - }); -})(jQuery); diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_hu.js b/circle/network/static/js/select2-3.4.0/select2_locale_hu.js deleted file mode 100644 index 572dea9..0000000 --- a/circle/network/static/js/select2-3.4.0/select2_locale_hu.js +++ /dev/null @@ -1,15 +0,0 @@ -/** - * Select2 Hungarian translation - */ -(function ($) { - "use strict"; - - $.extend($.fn.select2.defaults, { - formatNoMatches: function () { return "Nincs találat."; }, - formatInputTooShort: function (input, min) { var n = min - input.length; return "Túl rövid. Még " + n + " karakter hiányzik."; }, - formatInputTooLong: function (input, max) { var n = input.length - max; return "Túl hosszú. " + n + " kerekterrel több mint kellene."; }, - formatSelectionTooBig: function (limit) { return "Csak " + limit + " elemet lehet kiválasztani."; }, - formatLoadMore: function (pageNumber) { return "Töltés..."; }, - formatSearching: function () { return "Keresés..."; } - }); -})(jQuery); diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_is.js b/circle/network/static/js/select2-3.4.0/select2_locale_is.js deleted file mode 100644 index b10073b..0000000 --- a/circle/network/static/js/select2-3.4.0/select2_locale_is.js +++ /dev/null @@ -1,16 +0,0 @@ -/** - * Select2 Icelandic translation. - * - */ -(function ($) { - "use strict"; - - $.extend($.fn.select2.defaults, { - formatNoMatches: function () { return "Ekkert fannst"; }, - formatInputTooShort: function (input, min) { var n = min - input.length; return "Vinsamlegast skrifið " + n + " staf" + (n == 1 ? "" : "i") + " í viðbót"; }, - formatInputTooLong: function (input, max) { var n = input.length - max; return "Vinsamlegast styttið texta um " + n + " staf" + (n == 1 ? "" : "i"); }, - formatSelectionTooBig: function (limit) { return "Þú getur aðeins valið " + limit + " atriði"; }, - formatLoadMore: function (pageNumber) { return "Sæki fleiri niðurstöður..."; }, - formatSearching: function () { return "Leita..."; } - }); -})(jQuery); diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_it.js b/circle/network/static/js/select2-3.4.0/select2_locale_it.js deleted file mode 100644 index 98369dd..0000000 --- a/circle/network/static/js/select2-3.4.0/select2_locale_it.js +++ /dev/null @@ -1,15 +0,0 @@ -/** - * Select2 Italian translation - */ -(function ($) { - "use strict"; - - $.extend($.fn.select2.defaults, { - formatNoMatches: function () { return "Nessuna corrispondenza trovata"; }, - formatInputTooShort: function (input, min) { var n = min - input.length; return "Inserisci ancora " + n + " caratter" + (n == 1? "e" : "i"); }, - formatInputTooLong: function (input, max) { var n = input.length - max; return "Inserisci " + n + " caratter" + (n == 1? "e" : "i") + " in meno"; }, - formatSelectionTooBig: function (limit) { return "Puoi selezionare solo " + limit + " element" + (limit == 1 ? "o" : "i"); }, - formatLoadMore: function (pageNumber) { return "Caricamento in corso..."; }, - formatSearching: function () { return "Ricerca..."; } - }); -})(jQuery); \ No newline at end of file diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_ja.js b/circle/network/static/js/select2-3.4.0/select2_locale_ja.js deleted file mode 100644 index 3fc8074..0000000 --- a/circle/network/static/js/select2-3.4.0/select2_locale_ja.js +++ /dev/null @@ -1,15 +0,0 @@ -/** - * Select2 Japanese translation. - */ -(function ($) { - "use strict"; - - $.extend($.fn.select2.defaults, { - formatNoMatches: function () { return "該当項目なし"; }, - formatInputTooShort: function (input, min) { var n = min - input.length; return "後" + n + "文字入れてください"; }, - formatInputTooLong: function (input, max) { var n = input.length - max; return "検索文字列が" + n + "文字長すぎます"; }, - formatSelectionTooBig: function (limit) { return "最多で" + limit + "項目までしか選択できません"; }, - formatLoadMore: function (pageNumber) { return "読込中・・・"; }, - formatSearching: function () { return "検索中・・・"; } - }); -})(jQuery); diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_lt.js b/circle/network/static/js/select2-3.4.0/select2_locale_lt.js deleted file mode 100644 index dbb1f09..0000000 --- a/circle/network/static/js/select2-3.4.0/select2_locale_lt.js +++ /dev/null @@ -1,29 +0,0 @@ -/** - * Select2 lithuanian translation. - * - * Author: CRONUS Karmalakas - */ -(function ($) { - "use strict"; - - $.extend($.fn.select2.defaults, { - formatNoMatches: function () { return "Atitikmenų nerasta"; }, - formatInputTooShort: function (input, min) { - var n = min - input.length, - suffix = (n % 10 == 1) && (n % 100 != 11) ? 'į' : (((n % 10 >= 2) && ((n % 100 < 10) || (n % 100 >= 20))) ? 'ius' : 'ių'); - return "Įrašykite dar " + n + " simbol" + suffix; - }, - formatInputTooLong: function (input, max) { - var n = input.length - max, - suffix = (n % 10 == 1) && (n % 100 != 11) ? 'į' : (((n % 10 >= 2) && ((n % 100 < 10) || (n % 100 >= 20))) ? 'ius' : 'ių'); - return "Pašalinkite " + n + " simbol" + suffix; - }, - formatSelectionTooBig: function (limit) { - var n = limit, - suffix = (n % 10 == 1) && (n % 100 != 11) ? 'ą' : (((n % 10 >= 2) && ((n % 100 < 10) || (n % 100 >= 20))) ? 'us' : 'ų'); - return "Jūs galite pasirinkti tik " + limit + " element" + suffix; - }, - formatLoadMore: function (pageNumber) { return "Kraunama daugiau rezultatų..."; }, - formatSearching: function () { return "Ieškoma..."; } - }); -})(jQuery); diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_lv.js b/circle/network/static/js/select2-3.4.0/select2_locale_lv.js deleted file mode 100644 index 2c05cfd..0000000 --- a/circle/network/static/js/select2-3.4.0/select2_locale_lv.js +++ /dev/null @@ -1,16 +0,0 @@ -/** - * Select2 Latvian translation - */ -(function ($) { - "use strict"; - - $.extend($.fn.select2.defaults, { - formatNoMatches: function () { return "Sakritību nav"; }, - formatInputTooShort: function (input, min) { var n = min - input.length; return "Lūdzu ievadiet vēl " + n + " simbol" + (n == 11 ? "us" : (/^\d*[1]$/im.test(n)? "u" : "us")); }, - formatInputTooLong: function (input, max) { var n = input.length - max; return "Lūdzu ievadiet par " + n + " simbol" + (n == 11 ? "iem" : (/^\d*[1]$/im.test(n)? "u" : "iem")) + " mazāk"; }, - formatSelectionTooBig: function (limit) { return "Jūs varat izvēlēties ne vairāk kā " + limit + " element" + (limit == 11 ? "us" : (/^\d*[1]$/im.test(limit)? "u" : "us")); }, - formatLoadMore: function (pageNumber) { return "Datu ielāde..."; }, - formatSearching: function () { return "Meklēšana..."; } - }); - -})(jQuery); diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_mk.js b/circle/network/static/js/select2-3.4.0/select2_locale_mk.js deleted file mode 100644 index 69e3981..0000000 --- a/circle/network/static/js/select2-3.4.0/select2_locale_mk.js +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Select2 Macedonian translation. - * - * Author: Marko Aleksic - */ -(function ($) { - "use strict"; - - $.extend($.fn.select2.defaults, { - formatNoMatches: function () { return "Нема пронајдено совпаѓања"; }, - formatInputTooShort: function (input, min) { var n = min - input.length; return "Ве молиме внесете уште " + n + " карактер" + (n == 1 ? "" : "и"); }, - formatInputTooLong: function (input, max) { var n = input.length - max; return "Ве молиме внесете " + n + " помалку карактер" + (n == 1? "" : "и"); }, - formatSelectionTooBig: function (limit) { return "Можете да изберете само " + limit + " ставк" + (limit == 1 ? "а" : "и"); }, - formatLoadMore: function (pageNumber) { return "Вчитување резултати..."; }, - formatSearching: function () { return "Пребарување..."; } - }); -})(jQuery); \ No newline at end of file diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_nl.js b/circle/network/static/js/select2-3.4.0/select2_locale_nl.js deleted file mode 100644 index 2ee2662..0000000 --- a/circle/network/static/js/select2-3.4.0/select2_locale_nl.js +++ /dev/null @@ -1,15 +0,0 @@ -/** - * Select2 Dutch translation - */ -(function ($) { - "use strict"; - - $.extend($.fn.select2.defaults, { - formatNoMatches: function () { return "Geen resultaten gevonden"; }, - formatInputTooShort: function (input, min) { var n = min - input.length; return "Vul " + n + " karakter" + (n == 1? "" : "s") + " meer in"; }, - formatInputTooLong: function (input, max) { var n = input.length - max; return "Vul " + n + " karakter" + (n == 1? "" : "s") + " minder in"; }, - formatSelectionTooBig: function (limit) { return "Maximaal " + limit + " item" + (limit == 1 ? "" : "s") + " toegestaan"; }, - formatLoadMore: function (pageNumber) { return "Meer resultaten laden..."; }, - formatSearching: function () { return "Zoeken..."; }, - }); -})(jQuery); \ No newline at end of file diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_no.js b/circle/network/static/js/select2-3.4.0/select2_locale_no.js deleted file mode 100644 index 0831360..0000000 --- a/circle/network/static/js/select2-3.4.0/select2_locale_no.js +++ /dev/null @@ -1,18 +0,0 @@ -/** - * Select2 Norwegian translation. - * - * Author: Torgeir Veimo - */ -(function ($) { - "use strict"; - - $.extend($.fn.select2.defaults, { - formatNoMatches: function () { return "Ingen treff"; }, - formatInputTooShort: function (input, min) { var n = min - input.length; return "Vennligst skriv inn " + n + (n>1 ? " flere tegn" : " tegn til"); }, - formatInputTooLong: function (input, max) { var n = input.length - max; return "Vennligst fjern " + n + " tegn"; }, - formatSelectionTooBig: function (limit) { return "Du kan velge maks " + limit + " elementer"; }, - formatLoadMore: function (pageNumber) { return "Laster flere resultater..."; }, - formatSearching: function () { return "Søker..."; } - }); -})(jQuery); - diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_pl.js b/circle/network/static/js/select2-3.4.0/select2_locale_pl.js deleted file mode 100644 index 1d5b327..0000000 --- a/circle/network/static/js/select2-3.4.0/select2_locale_pl.js +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Select2 Polish translation. - * - * Author: Jan Kondratowicz - */ -(function ($) { - "use strict"; - - var pl_suffix = function(n) { - if(n == 1) return ""; - if((n%100 > 1 && n%100 < 5) || (n%100 > 20 && n%10 > 1 && n%10 < 5)) return "i"; - return "ów"; - }; - - $.extend($.fn.select2.defaults, { - formatNoMatches: function () { - return "Brak wyników."; - }, - formatInputTooShort: function (input, min) { - var n = min - input.length; - return "Wpisz jeszcze " + n + " znak" + pl_suffix(n) + "."; - }, - formatInputTooLong: function (input, max) { - var n = input.length - max; - return "Wpisana fraza jest za długa o " + n + " znak" + pl_suffix(n) + "."; - }, - formatSelectionTooBig: function (limit) { - return "Możesz zaznaczyć najwyżej " + limit + " element" + pl_suffix(limit) + "."; - }, - formatLoadMore: function (pageNumber) { - return "Ładowanie wyników..."; - }, - formatSearching: function () { - return "Szukanie..."; - } - }); -})(jQuery); \ No newline at end of file diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_pt-BR.js b/circle/network/static/js/select2-3.4.0/select2_locale_pt-BR.js deleted file mode 100644 index 701fb7f..0000000 --- a/circle/network/static/js/select2-3.4.0/select2_locale_pt-BR.js +++ /dev/null @@ -1,15 +0,0 @@ -/** - * Select2 Brazilian Portuguese translation - */ -(function ($) { - "use strict"; - - $.extend($.fn.select2.defaults, { - formatNoMatches: function () { return "Nenhum resultado encontrado"; }, - formatInputTooShort: function (input, min) { var n = min - input.length; return "Informe " + n + " caracter" + (n == 1? "" : "es"); }, - formatInputTooLong: function (input, max) { var n = input.length - max; return "Apague " + n + " caracter" + (n == 1? "" : "es"); }, - formatSelectionTooBig: function (limit) { return "Só é possível selecionar " + limit + " elemento" + (limit == 1 ? "" : "s"); }, - formatLoadMore: function (pageNumber) { return "Carregando mais resultados..."; }, - formatSearching: function () { return "Buscando..."; } - }); -})(jQuery); diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_pt-PT.js b/circle/network/static/js/select2-3.4.0/select2_locale_pt-PT.js deleted file mode 100644 index 008653e..0000000 --- a/circle/network/static/js/select2-3.4.0/select2_locale_pt-PT.js +++ /dev/null @@ -1,15 +0,0 @@ -/** - * Select2 Portuguese (Portugal) translation - */ -(function ($) { - "use strict"; - - $.extend($.fn.select2.defaults, { - formatNoMatches: function () { return "Nenhum resultado encontrado"; }, - formatInputTooShort: function (input, min) { var n = min - input.length; return "Introduza " + n + " caracter" + (n == 1 ? "" : "es"); }, - formatInputTooLong: function (input, max) { var n = input.length - max; return "Apague " + n + " caracter" + (n == 1 ? "" : "es"); }, - formatSelectionTooBig: function (limit) { return "Só é possível selecionar " + limit + " elemento" + (limit == 1 ? "" : "s"); }, - formatLoadMore: function (pageNumber) { return "A carregar mais resultados..."; }, - formatSearching: function () { return "A pesquisar..."; } - }); -})(jQuery); diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_ro.js b/circle/network/static/js/select2-3.4.0/select2_locale_ro.js deleted file mode 100644 index 88b3ac4..0000000 --- a/circle/network/static/js/select2-3.4.0/select2_locale_ro.js +++ /dev/null @@ -1,15 +0,0 @@ -/** - * Select2 Romanian translation. - */ -(function ($) { - "use strict"; - - $.extend($.fn.select2.defaults, { - formatNoMatches: function () { return "Nu a fost găsit nimic"; }, - formatInputTooShort: function (input, min) { var n = min - input.length; return "Vă rugăm să introduceți incă " + n + " caracter" + (n == 1 ? "" : "e"); }, - formatInputTooLong: function (input, max) { var n = input.length - max; return "Vă rugăm să introduceți mai puțin de " + n + " caracter" + (n == 1? "" : "e"); }, - formatSelectionTooBig: function (limit) { return "Aveți voie să selectați cel mult " + limit + " element" + (limit == 1 ? "" : "e"); }, - formatLoadMore: function (pageNumber) { return "Se încarcă..."; }, - formatSearching: function () { return "Căutare..."; } - }); -})(jQuery); diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_ru.js b/circle/network/static/js/select2-3.4.0/select2_locale_ru.js deleted file mode 100644 index 3da956a..0000000 --- a/circle/network/static/js/select2-3.4.0/select2_locale_ru.js +++ /dev/null @@ -1,15 +0,0 @@ -/** - * Select2 Russian translation - */ -(function ($) { - "use strict"; - - $.extend($.fn.select2.defaults, { - formatNoMatches: function () { return "Совпадений не найдено"; }, - formatInputTooShort: function (input, min) { var n = min - input.length; return "Пожалуйста, введите еще " + n + " символ" + (n == 1 ? "" : ((n > 1)&&(n < 5) ? "а" : "ов")); }, - formatInputTooLong: function (input, max) { var n = input.length - max; return "Пожалуйста, введите на " + n + " символ" + (n == 1 ? "" : ((n > 1)&&(n < 5)? "а" : "ов")) + " меньше"; }, - formatSelectionTooBig: function (limit) { return "Вы можете выбрать не более " + limit + " элемент" + (limit == 1 ? "а" : "ов"); }, - formatLoadMore: function (pageNumber) { return "Загрузка данных..."; }, - formatSearching: function () { return "Поиск..."; } - }); -})(jQuery); diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_sk.js b/circle/network/static/js/select2-3.4.0/select2_locale_sk.js deleted file mode 100644 index 8d4e46a..0000000 --- a/circle/network/static/js/select2-3.4.0/select2_locale_sk.js +++ /dev/null @@ -1,48 +0,0 @@ -/** - * Select2 Slovak translation. - * - * Author: David Vallner - */ -(function ($) { - "use strict"; - // use text for the numbers 2 through 4 - var smallNumbers = { - 2: function(masc) { return (masc ? "dva" : "dve"); }, - 3: function() { return "tri"; }, - 4: function() { return "štyri"; } - } - $.extend($.fn.select2.defaults, { - formatNoMatches: function () { return "Nenašli sa žiadne položky"; }, - formatInputTooShort: function (input, min) { - var n = min - input.length; - if (n == 1) { - return "Prosím zadajte ešte jeden znak"; - } else if (n <= 4) { - return "Prosím zadajte ešte ďalšie "+smallNumbers[n](true)+" znaky"; - } else { - return "Prosím zadajte ešte ďalších "+n+" znakov"; - } - }, - formatInputTooLong: function (input, max) { - var n = input.length - max; - if (n == 1) { - return "Prosím zadajte o jeden znak menej"; - } else if (n <= 4) { - return "Prosím zadajte o "+smallNumbers[n](true)+" znaky menej"; - } else { - return "Prosím zadajte o "+n+" znakov menej"; - } - }, - formatSelectionTooBig: function (limit) { - if (limit == 1) { - return "Môžete zvoliť len jednu položku"; - } else if (limit <= 4) { - return "Môžete zvoliť najviac "+smallNumbers[limit](false)+" položky"; - } else { - return "Môžete zvoliť najviac "+limit+" položiek"; - } - }, - formatLoadMore: function (pageNumber) { return "Načítavajú sa ďalšie výsledky..."; }, - formatSearching: function () { return "Vyhľadávanie..."; } - }); -})(jQuery); diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_sv.js b/circle/network/static/js/select2-3.4.0/select2_locale_sv.js deleted file mode 100644 index 9f09de3..0000000 --- a/circle/network/static/js/select2-3.4.0/select2_locale_sv.js +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Select2 Swedish translation. - * - * Author: Jens Rantil - */ -(function ($) { - "use strict"; - - $.extend($.fn.select2.defaults, { - formatNoMatches: function () { return "Inga träffar"; }, - formatInputTooShort: function (input, min) { var n = min - input.length; return "Var god skriv in " + n + (n>1 ? " till tecken" : " tecken till"); }, - formatInputTooLong: function (input, max) { var n = input.length - max; return "Var god sudda ut " + n + " tecken"; }, - formatSelectionTooBig: function (limit) { return "Du kan max välja " + limit + " element"; }, - formatLoadMore: function (pageNumber) { return "Laddar fler resultat..."; }, - formatSearching: function () { return "Söker..."; } - }); -})(jQuery); diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_tr.js b/circle/network/static/js/select2-3.4.0/select2_locale_tr.js deleted file mode 100644 index b47a2fa..0000000 --- a/circle/network/static/js/select2-3.4.0/select2_locale_tr.js +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Select2 Turkish translation. - * - * Author: Salim KAYABAŞI - */ -(function ($) { - "use strict"; - - $.extend($.fn.select2.defaults, { - formatNoMatches: function () { return "Sonuç bulunamadı"; }, - formatInputTooShort: function (input, min) { var n = min - input.length; return "En az " + n + " karakter daha girmelisiniz"; }, - formatInputTooLong: function (input, max) { var n = input.length - max; return n + " karakter azaltmalısınız"; }, - formatSelectionTooBig: function (limit) { return "Sadece " + limit + " seçim yapabilirsiniz"; }, - formatLoadMore: function (pageNumber) { return "Daha fazla..."; }, - formatSearching: function () { return "Aranıyor..."; } - }); -})(jQuery); diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_ua.js b/circle/network/static/js/select2-3.4.0/select2_locale_ua.js deleted file mode 100644 index 58d31e7..0000000 --- a/circle/network/static/js/select2-3.4.0/select2_locale_ua.js +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Select2 translation. - * - * Author: bigmihail - */ -(function ($) { - "use strict"; - - $.extend($.fn.select2.defaults, { - formatNoMatches: function () { return "Нічого не знайдено"; }, - formatInputTooShort: function (input, min) { var n = min - input.length, s = ["", "и", "ів"], p = [2,0,1,1,1,2]; return "Введіть буль ласка ще " + n + " символ" + s[ (n%100>4 && n%100<=20)? 2 : p[Math.min(n%10, 5)] ]; }, - formatInputTooLong: function (input, max) { var n = input.length - max, s = ["", "и", "ів"], p = [2,0,1,1,1,2]; return "Введіть буль ласка на " + n + " символ" + s[ (n%100>4 && n%100<=20)? 2 : p[Math.min(n%10, 5)] ] + " менше"; }, - formatSelectionTooBig: function (limit) {var s = ["", "и", "ів"], p = [2,0,1,1,1,2]; return "Ви можете вибрати лише " + limit + " елемент" + s[ (limit%100>4 && limit%100<=20)? 2 : p[Math.min(limit%10, 5)] ]; }, - formatLoadMore: function (pageNumber) { return "Завантаження даних..."; }, - formatSearching: function () { return "Пошук..."; } - }); -})(jQuery); diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_vi.js b/circle/network/static/js/select2-3.4.0/select2_locale_vi.js deleted file mode 100644 index 0a45dfc..0000000 --- a/circle/network/static/js/select2-3.4.0/select2_locale_vi.js +++ /dev/null @@ -1,18 +0,0 @@ -/** - * Select2 Vietnamese translation. - * - * Author: Long Nguyen - */ -(function ($) { - "use strict"; - - $.extend($.fn.select2.defaults, { - formatNoMatches: function () { return "Không tìm thấy kết quả"; }, - formatInputTooShort: function (input, min) { var n = min - input.length; return "Vui lòng nhập nhiều hơn " + n + " ký tự" + (n == 1 ? "" : "s"); }, - formatInputTooLong: function (input, max) { var n = input.length - max; return "Vui lòng nhập ít hơn " + n + " ký tự" + (n == 1? "" : "s"); }, - formatSelectionTooBig: function (limit) { return "Chỉ có thể chọn được " + limit + " tùy chọn" + (limit == 1 ? "" : "s"); }, - formatLoadMore: function (pageNumber) { return "Đang lấy thêm kết quả..."; }, - formatSearching: function () { return "Đang tìm..."; } - }); -})(jQuery); - diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_zh-CN.js b/circle/network/static/js/select2-3.4.0/select2_locale_zh-CN.js deleted file mode 100644 index 49d8e59..0000000 --- a/circle/network/static/js/select2-3.4.0/select2_locale_zh-CN.js +++ /dev/null @@ -1,14 +0,0 @@ -/** - * Select2 Chinese translation - */ -(function ($) { - "use strict"; - $.extend($.fn.select2.defaults, { - formatNoMatches: function () { return "没有找到匹配项"; }, - formatInputTooShort: function (input, min) { var n = min - input.length; return "请再输入" + n + "个字符";}, - formatInputTooLong: function (input, max) { var n = input.length - max; return "请删掉" + n + "个字符";}, - formatSelectionTooBig: function (limit) { return "你只能选择最多" + limit + "项"; }, - formatLoadMore: function (pageNumber) { return "加载结果中..."; }, - formatSearching: function () { return "搜索中..."; } - }); -})(jQuery); diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_zh-TW.js b/circle/network/static/js/select2-3.4.0/select2_locale_zh-TW.js deleted file mode 100755 index 3d447d6..0000000 --- a/circle/network/static/js/select2-3.4.0/select2_locale_zh-TW.js +++ /dev/null @@ -1,14 +0,0 @@ -/** - * Select2 Traditional Chinese translation - */ -(function ($) { - "use strict"; - $.extend($.fn.select2.defaults, { - formatNoMatches: function () { return "沒有找到相符的項目"; }, - formatInputTooShort: function (input, min) { var n = min - input.length; return "請再輸入" + n + "個字元";}, - formatInputTooLong: function (input, max) { var n = input.length - max; return "請刪掉" + n + "個字元";}, - formatSelectionTooBig: function (limit) { return "你只能選擇最多" + limit + "項"; }, - formatLoadMore: function (pageNumber) { return "載入中..."; }, - formatSearching: function () { return "搜尋中..."; } - }); -})(jQuery); diff --git a/circle/network/static/js/select2-3.4.0/select2x2.png b/circle/network/static/js/select2-3.4.0/select2x2.png deleted file mode 100644 index 4bdd5c9..0000000 Binary files a/circle/network/static/js/select2-3.4.0/select2x2.png and /dev/null differ diff --git a/circle/network/static/js/switch-port.js b/circle/network/static/js/switch-port.js index f6991f6..6962f57 100644 --- a/circle/network/static/js/switch-port.js +++ b/circle/network/static/js/switch-port.js @@ -1,4 +1,4 @@ -$('i[class="fa fa-times"]').click(function() { +$('.ethernet-devices-mini-table i[class="fa fa-times"]').click(function() { href = $(this).parent('a').attr('href'); csrf = getCookie('csrftoken'); var click_this = this; diff --git a/circle/network/static/network/network.css b/circle/network/static/network/network.less similarity index 100% rename from circle/network/static/network/network.css rename to circle/network/static/network/network.less diff --git a/circle/network/tables.py b/circle/network/tables.py index 3dcfa22..a1261d2 100644 --- a/circle/network/tables.py +++ b/circle/network/tables.py @@ -15,14 +15,30 @@ # You should have received a copy of the GNU General Public License along # with CIRCLE. If not, see . +from netaddr import EUI from django.utils.translation import ugettext_lazy as _ +from django.utils.html import format_html from django_tables2 import Table, A -from django_tables2.columns import LinkColumn, TemplateColumn +from django_tables2.columns import LinkColumn, TemplateColumn, Column from firewall.models import Host, Vlan, Domain, Group, Record, Rule, SwitchPort +class MACColumn(Column): + def render(self, value): + if isinstance(value, basestring): + try: + value = EUI(value) + except: + return value + try: + return format_html('{1}', + value.oui.registration().org, value) + except: + return value + + class BlacklistItemTable(Table): ipv4 = LinkColumn('network.blacklist', args=[A('pk')]) @@ -55,9 +71,7 @@ class GroupTable(Table): class HostTable(Table): hostname = LinkColumn('network.host', args=[A('pk')]) - mac = TemplateColumn( - template_name="network/columns/mac.html" - ) + mac = MACColumn() class Meta: model = Host @@ -83,7 +97,8 @@ class SmallRuleTable(Table): class Meta: model = Rule - attrs = {'class': 'table table-striped table-bordered table-condensed'} + attrs = {'class': 'table table-striped table-bordered table-condensed', + 'id': "small_rule_table"} fields = ('rule', 'action', ) @@ -108,6 +123,20 @@ class SmallHostTable(Table): attrs = {'class': 'table table-striped table-condensed'} fields = ('hostname', 'ipv4') order_by = ('vlan', 'hostname', ) + empty_text = _("No hosts.") + + +class SmallDhcpTable(Table): + mac = MACColumn(verbose_name=_("MAC address")) + hostname = Column(verbose_name=_("hostname")) + ip = Column(verbose_name=_("requested IP")) + register = TemplateColumn( + template_name="network/columns/host-register.html", + attrs={"th": {"style": "display: none;"}}) + + class Meta: + attrs = {'class': 'table table-striped table-condensed'} + empty_text = _("No hosts.") class RecordTable(Table): diff --git a/circle/network/templates/network/base.html b/circle/network/templates/network/base.html index 077e9d5..3cdba7d 100644 --- a/circle/network/templates/network/base.html +++ b/circle/network/templates/network/base.html @@ -46,8 +46,3 @@ {% trans "dashboard" %} {% endblock %} - -{% block extra_script %} - - -{% endblock %} diff --git a/circle/network/templates/network/columns/host-register.html b/circle/network/templates/network/columns/host-register.html new file mode 100644 index 0000000..c488894 --- /dev/null +++ b/circle/network/templates/network/columns/host-register.html @@ -0,0 +1,3 @@ +{% load i18n %} + diff --git a/circle/network/templates/network/columns/mac.html b/circle/network/templates/network/columns/mac.html deleted file mode 100644 index 2c22d37..0000000 --- a/circle/network/templates/network/columns/mac.html +++ /dev/null @@ -1,3 +0,0 @@ -{% load i18n %} - -{{ record.mac }} diff --git a/circle/network/templates/network/host-edit.html b/circle/network/templates/network/host-edit.html index 8f8f879..e426288 100644 --- a/circle/network/templates/network/host-edit.html +++ b/circle/network/templates/network/host-edit.html @@ -79,7 +79,3 @@
    {% endblock %} - -{% block extra_etc %} - -{% endblock %} diff --git a/circle/network/templates/network/switch-port-edit.html b/circle/network/templates/network/switch-port-edit.html index 9ea4a37..1b19bb8 100644 --- a/circle/network/templates/network/switch-port-edit.html +++ b/circle/network/templates/network/switch-port-edit.html @@ -51,7 +51,3 @@ {% endblock %} - -{% block extra_etc %} - -{% endblock %} diff --git a/circle/network/templates/network/vlan-edit.html b/circle/network/templates/network/vlan-edit.html index c0e9441..930a76f 100644 --- a/circle/network/templates/network/vlan-edit.html +++ b/circle/network/templates/network/vlan-edit.html @@ -19,9 +19,16 @@
    {% render_table host_list %} + + + {% render_table dhcp_list %} + diff --git a/circle/network/views.py b/circle/network/views.py index 26f6d76..22c4191 100644 --- a/circle/network/views.py +++ b/circle/network/views.py @@ -15,11 +15,13 @@ # You should have received a copy of the GNU General Public License along # with CIRCLE. If not, see . +from netaddr import IPNetwork from django.views.generic import (TemplateView, UpdateView, DeleteView, CreateView) +from django.core.exceptions import ValidationError from django.core.urlresolvers import reverse_lazy -from django.shortcuts import render, redirect -from django.http import HttpResponse +from django.shortcuts import render, redirect, get_object_or_404 +from django.http import HttpResponse, Http404 from django_tables2 import SingleTableView @@ -29,7 +31,7 @@ from vm.models import Interface from .tables import (HostTable, VlanTable, SmallHostTable, DomainTable, GroupTable, RecordTable, BlacklistItemTable, RuleTable, VlanGroupTable, SmallRuleTable, SmallGroupRuleTable, - SmallRecordTable, SwitchPortTable) + SmallRecordTable, SwitchPortTable, SmallDhcpTable, ) from .forms import (HostForm, VlanForm, DomainForm, GroupForm, RecordForm, BlacklistItemForm, RuleForm, VlanGroupForm, SwitchPortForm) @@ -41,10 +43,36 @@ from braces.views import LoginRequiredMixin, SuperuserRequiredMixin # from django.db.models import Q from operator import itemgetter from itertools import chain -import json from dashboard.views import AclUpdateView from dashboard.forms import AclUserOrGroupAddForm +from django.utils import simplejson + +try: + from django.http import JsonResponse +except ImportError: + class JsonResponse(HttpResponse): + """JSON response for Django < 1.7 + https://gist.github.com/philippeowagner/3179eb475fe1795d6515 + """ + def __init__(self, content, mimetype='application/json', + status=None, content_type=None): + super(JsonResponse, self).__init__( + content=simplejson.dumps(content), + mimetype=mimetype, + status=status, + content_type=content_type) + + +class MagicMixin(object): + + def get(self, *args, **kwargs): + if self.request.is_ajax(): + result = self._get_ajax(*args, **kwargs) + return JsonResponse({k: unicode(result[k] or "") for k in result}) + else: + return super(MagicMixin, self).get(*args, **kwargs) + class InitialOwnerMixin(FormMixin): def get_initial(self): @@ -310,6 +338,25 @@ class GroupDelete(LoginRequiredMixin, SuperuserRequiredMixin, DeleteView): return context +class HostMagicMixin(MagicMixin): + def _get_ajax(self, *args, **kwargs): + GET = self.request.GET + result = {} + vlan = get_object_or_404(Vlan.objects, pk=GET.get("vlan", "")) + if "ipv4" in GET: + try: + result["ipv6"] = vlan.convert_ipv4_to_ipv6(GET["ipv4"]) or "" + except: + result["ipv6"] = "" + else: + try: + result.update(vlan.get_new_address()) + except ValidationError: + result["ipv4"] = "" + result["ipv6"] = "" + return result + + class HostList(LoginRequiredMixin, SuperuserRequiredMixin, SingleTableView): model = Host table_class = HostTable @@ -331,15 +378,15 @@ class HostList(LoginRequiredMixin, SuperuserRequiredMixin, SingleTableView): return data -class HostDetail(LoginRequiredMixin, SuperuserRequiredMixin, +class HostDetail(HostMagicMixin, LoginRequiredMixin, SuperuserRequiredMixin, SuccessMessageMixin, UpdateView): model = Host template_name = "network/host-edit.html" form_class = HostForm success_message = _(u'Successfully modified host %(hostname)s!') - def get(self, request, *args, **kwargs): - if request.is_ajax(): + def _get_ajax(self, *args, **kwargs): + if "vlan" not in self.request.GET: host = Host.objects.get(pk=kwargs['pk']) host = { 'hostname': host.hostname, @@ -347,11 +394,13 @@ class HostDetail(LoginRequiredMixin, SuperuserRequiredMixin, 'ipv6': str(host.ipv6), 'fqdn': host.get_fqdn() } - return HttpResponse(json.dumps(host), - content_type="application/json") + return host else: - self.object = self.get_object() - return super(HostDetail, self).get(request, *args, **kwargs) + return super(HostDetail, self)._get_ajax(*args, **kwargs) + + def get(self, request, *args, **kwargs): + self.object = self.get_object() + return super(HostDetail, self).get(request, *args, **kwargs) def post(self, request, *args, **kwargs): pk = self.kwargs.get('pk') @@ -402,13 +451,29 @@ class HostDetail(LoginRequiredMixin, SuperuserRequiredMixin, return reverse_lazy('network.host', kwargs=self.kwargs) -class HostCreate(LoginRequiredMixin, SuperuserRequiredMixin, +class HostCreate(HostMagicMixin, LoginRequiredMixin, SuperuserRequiredMixin, SuccessMessageMixin, InitialOwnerMixin, CreateView): model = Host template_name = "network/host-create.html" form_class = HostForm success_message = _(u'Successfully created host %(hostname)s!') + def get_initial(self): + initial = super(HostCreate, self).get_initial() + + for i in ("vlan", "mac", "hostname"): + if i in self.request.GET and i not in self.request.POST: + initial[i] = self.request.GET[i] + if "vlan" in initial: + if not initial['vlan'].isnumeric(): + raise Http404() + vlan = get_object_or_404(Vlan.objects, pk=initial['vlan']) + try: + initial.update(vlan.get_new_address()) + except ValidationError as e: + messages.error(self.request, e.message) + return initial + class HostDelete(LoginRequiredMixin, SuperuserRequiredMixin, DeleteView): model = Host @@ -644,7 +709,21 @@ class VlanAclUpdateView(AclUpdateView): model = Vlan -class VlanDetail(LoginRequiredMixin, SuperuserRequiredMixin, +class VlanMagicMixin(MagicMixin): + def _get_ajax(self, *args, **kwargs): + GET = self.request.GET + result = {} + if "network4" in GET and "network6" in GET: + try: + result["ipv6_template"], result["host_ipv6_prefixlen"] = ( + Vlan._magic_ipv6_template(IPNetwork(GET['network4']), + IPNetwork(GET['network6']))) + except: + result["ipv6_template"] = result["host_ipv6_prefixlen"] = "" + return result + + +class VlanDetail(VlanMagicMixin, LoginRequiredMixin, SuperuserRequiredMixin, SuccessMessageMixin, UpdateView): model = Vlan template_name = "network/vlan-edit.html" @@ -655,12 +734,8 @@ class VlanDetail(LoginRequiredMixin, SuperuserRequiredMixin, def get_context_data(self, **kwargs): context = super(VlanDetail, self).get_context_data(**kwargs) - - q = Host.objects.filter(interface__in=Interface.objects.filter( - vlan=self.object - )) - - context['host_list'] = SmallHostTable(q) + context['host_list'] = SmallHostTable(self.object.host_set.all()) + context['dhcp_list'] = SmallDhcpTable(self.object.get_dhcp_clients()) context['vlan_vid'] = self.kwargs.get('vid') context['acl'] = AclUpdateView.get_acl_data( self.object, self.request.user, 'network.vlan-acl') @@ -670,7 +745,7 @@ class VlanDetail(LoginRequiredMixin, SuperuserRequiredMixin, success_url = reverse_lazy('network.vlan_list') -class VlanCreate(LoginRequiredMixin, SuperuserRequiredMixin, +class VlanCreate(VlanMagicMixin, LoginRequiredMixin, SuperuserRequiredMixin, SuccessMessageMixin, InitialOwnerMixin, CreateView): model = Vlan template_name = "network/vlan-create.html" diff --git a/circle/templates/registration/base.html b/circle/templates/registration/base.html index a98c4cd..a626320 100644 --- a/circle/templates/registration/base.html +++ b/circle/templates/registration/base.html @@ -76,7 +76,7 @@ {% block navbar-brand %} - + {% endblock %} diff --git a/circle/templates/registration/login.html b/circle/templates/registration/login.html index f2e27d1..f6a09da 100644 --- a/circle/templates/registration/login.html +++ b/circle/templates/registration/login.html @@ -1,4 +1,5 @@ {% extends "registration/base.html" %} +{% load staticfiles %} {% load i18n %} {% load crispy_forms_tags %} {% get_current_language as LANGUAGE_CODE %} @@ -7,7 +8,7 @@ {% block navbar-brand %} - + {% endblock %} diff --git a/circle/vm/tests/test_models.py b/circle/vm/tests/test_models.py index 8f9ff41..d0c5790 100644 --- a/circle/vm/tests/test_models.py +++ b/circle/vm/tests/test_models.py @@ -177,6 +177,7 @@ class InterfaceTestCase(TestCase): d.save() v = Vlan(vid=55, network4='127.0.0.1/8', network6='2001::1/32', domain=d) + v.clean() v.save() Interface.create(i, v, managed=True, owner=owner) diff --git a/docs/install.rst b/docs/install.rst index 5d94228..cdb2c06 100644 --- a/docs/install.rst +++ b/docs/install.rst @@ -61,7 +61,8 @@ Update the package lists, and install the required system software:: sudo apt-get update sudo apt-get install --yes virtualenvwrapper postgresql git \ python-pip rabbitmq-server libpq-dev python-dev ntp memcached \ - libmemcached-dev + libmemcached-dev npm + sudo npm -g install bower less Set up *PostgreSQL* to listen on localhost and restart it:: diff --git a/requirements/base.txt b/requirements/base.txt index 7a91456..4f9f98c 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -35,3 +35,6 @@ sqlparse==0.1.11 pika==0.9.13 Fabric==1.9.0 lxml==3.3.5 +pyinotify==0.9.4 +git+https://github.com/BME-IK/django-pipeline.git +slimit==0.8.1