From 2cd47a578cddb4eb9161968afe2d7364c6dc4b16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Espino?= Date: Wed, 8 Nov 2017 09:38:01 +0100 Subject: [PATCH] kanban drag multiple --- app/coffee/modules/backlog/sortable.coffee | 2 +- app/coffee/modules/common.coffee | 2 - .../modules/kanban/kanban-usertories.coffee | 58 +++++++++++++----- app/coffee/modules/kanban/main.coffee | 60 ++++++++++++------- app/coffee/modules/kanban/sortable.coffee | 40 +++++++++---- app/js/dragula-drag-multiple.js | 25 ++++---- .../card/card-templates/card-owner.jade | 4 +- .../card/card-templates/card-unfold.jade | 2 +- app/modules/components/card/card.jade | 12 ++++ .../includes/modules/kanban-table.jade | 3 +- app/styles/layout/backlog.scss | 2 +- app/styles/modules/kanban/kanban-table.scss | 54 +++++++++++++++++ prism-languages.json | 2 +- 13 files changed, 198 insertions(+), 68 deletions(-) diff --git a/app/coffee/modules/backlog/sortable.coffee b/app/coffee/modules/backlog/sortable.coffee index 69272b2d..bcf67dcf 100644 --- a/app/coffee/modules/backlog/sortable.coffee +++ b/app/coffee/modules/backlog/sortable.coffee @@ -68,7 +68,7 @@ BacklogSortableDirective = () -> window.dragMultiple.start(item, container) drake.on 'cloned', (item) -> - $(item).addClass('backlog-us-mirror') + $(item).addClass('multiple-drag-mirror') drake.on 'dragend', (item) -> parent = $(item).parent() diff --git a/app/coffee/modules/common.coffee b/app/coffee/modules/common.coffee index 11455fa6..16979e26 100644 --- a/app/coffee/modules/common.coffee +++ b/app/coffee/modules/common.coffee @@ -251,8 +251,6 @@ Qqueue = ($q) -> bindAdd: (fn) => return (args...) => lastPromise = lastPromise.then () => fn.apply(@, args) - - return qqueue add: (fn) => if !lastPromise lastPromise = fn() diff --git a/app/coffee/modules/kanban/kanban-usertories.coffee b/app/coffee/modules/kanban/kanban-usertories.coffee index 9f92fc8f..0b0f13bf 100644 --- a/app/coffee/modules/kanban/kanban-usertories.coffee +++ b/app/coffee/modules/kanban/kanban-usertories.coffee @@ -93,15 +93,17 @@ class KanbanUserstoriesService extends taiga.Service @.refresh() - move: (id, statusId, index) -> - us = @.getUsModel(id) - + move: (usList, statusId, index) -> + initialLength = usList.length + usByStatus = _.filter @.userstoriesRaw, (it) => return it.status == statusId usByStatus = _.sortBy usByStatus, (it) => @.order[it.id] - usByStatusWithoutMoved = _.filter usByStatus, (it) => it.id != id + usByStatusWithoutMoved = _.filter usByStatus, (listIt) -> + return !_.find usList, (moveIt) -> return listIt.id == moveIt.id + beforeDestination = _.slice(usByStatusWithoutMoved, 0, index) afterDestination = _.slice(usByStatusWithoutMoved, index) @@ -112,26 +114,54 @@ class KanbanUserstoriesService extends taiga.Service previousWithTheSameOrder = _.filter beforeDestination, (it) => @.order[it.id] == @.order[previous.id] + if previousWithTheSameOrder.length > 1 for it in previousWithTheSameOrder setOrders[it.id] = @.order[it.id] - if !previous and (!afterDestination or afterDestination.length == 0) - @.order[us.id] = 0 - else if !previous and afterDestination and afterDestination.length > 0 - @.order[us.id] = @.order[afterDestination[0].id] - 1 + modifiedUs = [] + setPreviousOrders = [] + setNextOrders = [] + + if !previous + startIndex = 0 else if previous - @.order[us.id] = @.order[previous.id] + 1 + startIndex = @.order[previous.id] + 1 - for it, key in afterDestination - @.order[it.id] = @.order[us.id] + key + 1 + previousWithTheSameOrder = _.filter(beforeDestination, (it) => + it.kanban_order == @.order[previous.id] + ) + for it, key in afterDestination # increase position of the us after the dragged us's + @.order[it.id] = @.order[previous.id] + key + initialLength + 1 + it.kanban_order = @.order[it.id] - us.status = statusId - us.kanban_order = @.order[us.id] + setNextOrders = _.map(afterDestination, (it) => + {us_id: it.id, order: @.order[it.id]} + ) + + # we must send the USs previous to the dropped USs to tell the backend + # which USs are before the dropped USs, if they have the same value to + # order, the backend doens't know after which one do you want to drop + # the USs + if previousWithTheSameOrder.length > 1 + setPreviousOrders = _.map(previousWithTheSameOrder, (it) => + {us_id: it.id, order: @.order[it.id]} + ) + + for us, key in usList + us.status = statusId + us.kanban_order = startIndex + key + @.order[us.id] = us.kanban_order + + modifiedUs.push({us_id: us.id, order: us.kanban_order}) @.refresh() - return {"us_id": us.id, "order": @.order[us.id], "set_orders": setOrders} + return { + bulkOrders: modifiedUs.concat(setPreviousOrders, setNextOrders), + usList: modifiedUs, + set_orders: setOrders + } moveToEnd: (id, statusId) -> us = @.getUsModel(id) diff --git a/app/coffee/modules/kanban/main.coffee b/app/coffee/modules/kanban/main.coffee index 7e137c8a..ff8642e5 100644 --- a/app/coffee/modules/kanban/main.coffee +++ b/app/coffee/modules/kanban/main.coffee @@ -71,6 +71,7 @@ class KanbanController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fi bindMethods(@) @kanbanUserstoriesService.reset() @.openFilter = false + @.selectedUss = {} return if @.applyStoredFilters(@params.pslug, "kanban-filters") @@ -80,6 +81,13 @@ class KanbanController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fi taiga.defineImmutableProperty @.scope, "usByStatus", () => return @kanbanUserstoriesService.usByStatus + cleanSelectedUss: () -> + for key of @.selectedUss + @.selectedUss[key] = false + + toggleSelectedUs: (usId) -> + @.selectedUss[usId] = !@.selectedUss[usId] + firstLoad: () -> promise = @.loadInitialData() @@ -291,36 +299,42 @@ class KanbanController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fi prepareBulkUpdateData: (uses, field="kanban_order") -> return _.map(uses, (x) -> {"us_id": x.id, "order": x[field]}) - moveUs: (ctx, us, oldStatusId, newStatusId, index) -> - us = @kanbanUserstoriesService.getUsModel(us.get('id')) - newStatus = @scope.usStatusById[newStatusId] - if newStatus.is_archived and !@scope.usByStatus.get(newStatusId.toString()) - moveUpdateData = @kanbanUserstoriesService.moveToEnd(us.id, newStatusId) - else - moveUpdateData = @kanbanUserstoriesService.move(us.id, newStatusId, index) + moveUs: (ctx, usList, newStatusId, index) -> + @.cleanSelectedUss() + + usList = _.map usList, (us) => + return @kanbanUserstoriesService.getUsModel(us.id) - params = { - include_attachments: true, - include_tasks: true - } + data = @kanbanUserstoriesService.move(usList, newStatusId, index) - options = { - headers: { - "set-orders": JSON.stringify(moveUpdateData.set_orders) + promise = @rs.userstories.bulkUpdateKanbanOrder(@scope.projectId, data.bulkOrders) + + promise.then () => + # saving + # drag single or different status + options = { + headers: { + "set-orders": JSON.stringify(data.setOrders) + } } - } - promise = @repo.save(us, true, params, options, true) + params = { + include_attachments: true, + include_tasks: true + } - promise = promise.then (result) => - headers = result[1] + promises = _.map usList, (us) => + @repo.save(us, true, params, options, true) - if headers && headers['taiga-info-order-updated'] - order = JSON.parse(headers['taiga-info-order-updated']) - @kanbanUserstoriesService.assignOrders(order) - @scope.$broadcast("redraw:wip") + promise = @q.all(promises) - return promise + promise.then (result) => + headers = result[1] + + if headers && headers['taiga-info-order-updated'] + order = JSON.parse(headers['taiga-info-order-updated']) + @kanbanUserstoriesService.assignOrders(order) + @scope.$broadcast("redraw:wip") module.controller("KanbanController", KanbanController) diff --git a/app/coffee/modules/kanban/sortable.coffee b/app/coffee/modules/kanban/sortable.coffee index 8df444ed..b14d5eef 100644 --- a/app/coffee/modules/kanban/sortable.coffee +++ b/app/coffee/modules/kanban/sortable.coffee @@ -48,7 +48,6 @@ KanbanSortableDirective = ($repo, $rs, $rootscope) -> if not ($scope.project.my_permissions.indexOf("modify_us") > -1) return - oldParentScope = null newParentScope = null itemEl = null tdom = $el @@ -70,23 +69,44 @@ KanbanSortableDirective = ($repo, $rs, $rootscope) -> }) drake.on 'drag', (item) -> - oldParentScope = $(item).parent().scope() + window.dragMultiple.start(item, containers) + + drake.on 'cloned', (item, dropTarget) -> + $(item).addClass('multiple-drag-mirror') drake.on 'dragend', (item) -> parentEl = $(item).parent() - itemEl = $(item) - itemUs = itemEl.scope().us - itemIndex = itemEl.index() newParentScope = parentEl.scope() newStatusId = newParentScope.s.id - oldStatusId = oldParentScope.s.id + dragMultipleItems = window.dragMultiple.stop() - if newStatusId != oldStatusId - deleteElement(itemEl) + # if it is not drag multiple + if !dragMultipleItems.length + dragMultipleItems = [item] - $scope.$apply -> - $rootscope.$broadcast("kanban:us:move", itemUs, itemUs.getIn(['model', 'status']), newStatusId, itemIndex) + firstElement = dragMultipleItems[0] + index = $(firstElement).index() + newStatus = newParentScope.s.id + + usList = _.map dragMultipleItems, (item) -> $(item).scope().us + + finalUsList = _.map usList, (item) -> + return { + id: item.get('id'), + oldStatusId: item.getIn(['model', 'status']) + } + + $scope.$apply -> + _.each usList, (item, key) => + oldStatus = item.getIn(['model', 'status']) + sameContainer = newStatus == oldStatus + + if !sameContainer + itemEl = $(dragMultipleItems[key]) + deleteElement(itemEl) + + $rootscope.$broadcast("kanban:us:move", finalUsList, newStatus, index) scroll = autoScroll(containers, { margin: 100, diff --git a/app/js/dragula-drag-multiple.js b/app/js/dragula-drag-multiple.js index 9751afd0..5cdda7e7 100644 --- a/app/js/dragula-drag-multiple.js +++ b/app/js/dragula-drag-multiple.js @@ -7,8 +7,8 @@ var reset = function(elm) { $(elm) .removeAttr('style') - .removeClass('tg-backlog-us-mirror') - .removeClass('backlog-us-mirror') + .removeClass('tg-multiple-drag-mirror') + .removeClass('multiple-drag-mirror') .data('dragMultipleIndex', null) .data('dragMultipleActive', false); }; @@ -40,6 +40,8 @@ var currentTop = shadow.position().top; var height = shadow.outerHeight(); + $('.gu-transit').addClass('gu-transit-multi'); + _.forEach(dragMultiple.items.draggingItems, function(elm, index) { var elmIndex = parseInt(elm.data('dragMultipleIndex'), 10); var top = currentTop + (elmIndex * height); @@ -57,22 +59,21 @@ refreshOriginal(); - var current = dragMultiple.items.elm; - var container = dragMultiple.items.container; - document.documentElement.removeEventListener('mousemove', removeEventFn); // reset dragMultiple.items = {}; $('.' + mainClass).removeClass(mainClass); - $('.tg-backlog-us-mirror').remove(); - $('.backlog-us-mirror').removeClass('backlog-us-mirror'); + $('.tg-multiple-drag-mirror').remove(); + $('.multiple-drag-mirror').removeClass('multiple-drag-mirror'); - $('.tg-backlog-us-dragging') - .removeClass('tg-backlog-us-dragging') + $('.tg-multiple-drag-dragging') + .removeClass('tg-multiple-drag-dragging') .show(); + $('.gu-transit-multi').removeClass('gu-transit-multi'); + return $('.' + multipleSortableClass); }; @@ -180,8 +181,8 @@ clone = $(item).clone(true); clone - .addClass('backlog-us-mirror') - .addClass('tg-backlog-us-mirror') + .addClass('multiple-drag-mirror') + .addClass('tg-multiple-drag-mirror') .data('dragmultiple:originalPosition', $(item).position()) .data('dragMultipleActive', true) .css({ @@ -194,7 +195,7 @@ $(item) .hide() - .addClass('tg-backlog-us-dragging'); + .addClass('tg-multiple-drag-dragging'); return clone; }); diff --git a/app/modules/components/card/card-templates/card-owner.jade b/app/modules/components/card/card-templates/card-owner.jade index 3c3f180b..e1b96904 100644 --- a/app/modules/components/card/card-templates/card-owner.jade +++ b/app/modules/components/card/card-templates/card-owner.jade @@ -23,7 +23,7 @@ tg-check-permission="{{vm.getPermissionsKey()}}" ) a.e2e-assign.card-owner-assign( - ng-click="vm.onClickAssignedTo({id: vm.item.get('id')})" + ng-click="!$event.ctrlKey && vm.onClickAssignedTo({id: vm.item.get('id')})" href="" ) tg-svg(svg-icon="icon-add-user") @@ -31,7 +31,7 @@ a.e2e-edit.card-edit( href="" - ng-click="vm.onClickEdit({id: vm.item.get('id')})" + ng-click="!$event.ctrlKey && vm.onClickEdit({id: vm.item.get('id')})" tg-loading="vm.item.get('loading')" ) tg-svg(svg-icon="icon-edit") diff --git a/app/modules/components/card/card-templates/card-unfold.jade b/app/modules/components/card/card-templates/card-unfold.jade index 5ee7fcf1..9b78e7fa 100644 --- a/app/modules/components/card/card-templates/card-unfold.jade +++ b/app/modules/components/card/card-templates/card-unfold.jade @@ -1,5 +1,5 @@ .card-unfold.ng-animate-disabled( - ng-click="vm.toggleFold()" + ng-click="!$event.ctrlKey && vm.toggleFold()" ng-if="vm.visible('unfold') && (vm.hasTasks() || vm.hasVisibleAttachments())" role="button" ) diff --git a/app/modules/components/card/card.jade b/app/modules/components/card/card.jade index 556c3c82..faf99601 100644 --- a/app/modules/components/card/card.jade +++ b/app/modules/components/card/card.jade @@ -14,3 +14,15 @@ images="vm.item.get('images')" ) include card-templates/card-unfold + +.card-transit-multi + div.fake-us + div.fake-img + div.column + div.fake-text + div.fake-text + div.fake-us + div.fake-img + div.column + div.fake-text + div.fake-text \ No newline at end of file diff --git a/app/partials/includes/modules/kanban-table.jade b/app/partials/includes/modules/kanban-table.jade index 12c396c1..2581dfa7 100644 --- a/app/partials/includes/modules/kanban-table.jade +++ b/app/partials/includes/modules/kanban-table.jade @@ -67,7 +67,7 @@ div.kanban-table( tg-card.card.ng-animate-disabled( tg-repeat="us in usByStatus.get(s.id.toString()) track by us.getIn(['model', 'id'])", - ng-class="{'kanban-task-maximized': ctrl.isMaximized(s.id), 'kanban-task-minimized': ctrl.isMinimized(s.id)}" + ng-class="{'kanban-task-maximized': ctrl.isMaximized(s.id), 'kanban-task-minimized': ctrl.isMinimized(s.id), 'kanban-task-selected': ctrl.selectedUss[us.get('id')], 'ui-multisortable-multiple': ctrl.selectedUss[us.get('id')]}" tg-class-permission="{'readonly': '!modify_task'}" tg-bind-scope, on-toggle-fold="ctrl.toggleFold(id)" @@ -78,6 +78,7 @@ div.kanban-table( zoom="ctrl.zoom" zoom-level="ctrl.zoomLevel" archived="ctrl.isUsInArchivedHiddenStatus(us.get('id'))" + ng-click="$event.ctrlKey && ctrl.toggleSelectedUs(us.get('id'))" ) div.kanban-column-intro(ng-if="s.is_archived", tg-kanban-archived-status-intro="s") diff --git a/app/styles/layout/backlog.scss b/app/styles/layout/backlog.scss index e6feca25..4c3486d6 100644 --- a/app/styles/layout/backlog.scss +++ b/app/styles/layout/backlog.scss @@ -41,7 +41,7 @@ } } -.backlog-us-mirror { +.multiple-drag-mirror.us-item-row { background: $white; border-radius: 4px; box-shadow: 2px 2px 5px $gray; diff --git a/app/styles/modules/kanban/kanban-table.scss b/app/styles/modules/kanban/kanban-table.scss index 24d2496b..385b9072 100644 --- a/app/styles/modules/kanban/kanban-table.scss +++ b/app/styles/modules/kanban/kanban-table.scss @@ -148,9 +148,63 @@ $column-padding: .5rem 1rem; .kanban-uses-box { background: $mass-white; } + .kanban-task-selected { + &.card:not(.gu-transit-multi) { + // border: 1px solid $primary-light; + box-shadow: 0 0 0 1px $primary-light, 2px 2px 4px darken($whitish, 10%); + } + } } .kanban-table-inner { display: flex; flex-wrap: nowrap; } + +.card-transit-multi { + background: darken($whitish, 2%); + border: 1px dashed darken($whitish, 8%); + display: none; + opacity: 1; + padding: 1rem; + .fake-img, + .fake-text { + background: darken($whitish, 8%); + } + .fake-us { + display: flex; + margin-bottom: 1rem; + + &:last-child { + margin-bottom: 0; + } + } + .column { + padding-left: 0.5rem; + width: 100%; + } + .fake-img { + flex-basis: 48px; + flex-shrink: 0; + height: 48px; + width: 48px; + } + .fake-text { + height: 1rem; + margin-bottom: 1rem; + width: 80%; + &:last-child { + margin-bottom: 0; + width: 40%; + } + } +} + +.card.gu-transit-multi { + .card-transit-multi { + display: block; + } + .card-inner { + display: none; + } +} diff --git a/prism-languages.json b/prism-languages.json index 6d79b676..466c5dc2 100644 --- a/prism-languages.json +++ b/prism-languages.json @@ -1 +1 @@ -[{"file":"prism-abap.min.js","name":"abap"},{"file":"prism-actionscript.min.js","name":"actionscript"},{"file":"prism-ada.min.js","name":"ada"},{"file":"prism-apacheconf.min.js","name":"apacheconf"},{"file":"prism-apl.min.js","name":"apl"},{"file":"prism-applescript.min.js","name":"applescript"},{"file":"prism-asciidoc.min.js","name":"asciidoc"},{"file":"prism-aspnet.min.js","name":"aspnet"},{"file":"prism-autohotkey.min.js","name":"autohotkey"},{"file":"prism-autoit.min.js","name":"autoit"},{"file":"prism-bash.min.js","name":"bash"},{"file":"prism-basic.min.js","name":"basic"},{"file":"prism-batch.min.js","name":"batch"},{"file":"prism-bison.min.js","name":"bison"},{"file":"prism-brainfuck.min.js","name":"brainfuck"},{"file":"prism-bro.min.js","name":"bro"},{"file":"prism-c.min.js","name":"c"},{"file":"prism-clike.min.js","name":"clike"},{"file":"prism-coffeescript.min.js","name":"coffeescript"},{"file":"prism-core.min.js","name":"core"},{"file":"prism-cpp.min.js","name":"cpp"},{"file":"prism-crystal.min.js","name":"crystal"},{"file":"prism-csharp.min.js","name":"csharp"},{"file":"prism-css-extras.min.js","name":"css-extras"},{"file":"prism-css.min.js","name":"css"},{"file":"prism-d.min.js","name":"d"},{"file":"prism-dart.min.js","name":"dart"},{"file":"prism-diff.min.js","name":"diff"},{"file":"prism-docker.min.js","name":"docker"},{"file":"prism-eiffel.min.js","name":"eiffel"},{"file":"prism-elixir.min.js","name":"elixir"},{"file":"prism-erlang.min.js","name":"erlang"},{"file":"prism-fortran.min.js","name":"fortran"},{"file":"prism-fsharp.min.js","name":"fsharp"},{"file":"prism-gherkin.min.js","name":"gherkin"},{"file":"prism-git.min.js","name":"git"},{"file":"prism-glsl.min.js","name":"glsl"},{"file":"prism-go.min.js","name":"go"},{"file":"prism-graphql.min.js","name":"graphql"},{"file":"prism-groovy.min.js","name":"groovy"},{"file":"prism-haml.min.js","name":"haml"},{"file":"prism-handlebars.min.js","name":"handlebars"},{"file":"prism-haskell.min.js","name":"haskell"},{"file":"prism-haxe.min.js","name":"haxe"},{"file":"prism-http.min.js","name":"http"},{"file":"prism-icon.min.js","name":"icon"},{"file":"prism-inform7.min.js","name":"inform7"},{"file":"prism-ini.min.js","name":"ini"},{"file":"prism-j.min.js","name":"j"},{"file":"prism-jade.min.js","name":"jade"},{"file":"prism-java.min.js","name":"java"},{"file":"prism-javascript.min.js","name":"javascript"},{"file":"prism-jolie.min.js","name":"jolie"},{"file":"prism-json.min.js","name":"json"},{"file":"prism-jsx.min.js","name":"jsx"},{"file":"prism-julia.min.js","name":"julia"},{"file":"prism-keyman.min.js","name":"keyman"},{"file":"prism-kotlin.min.js","name":"kotlin"},{"file":"prism-latex.min.js","name":"latex"},{"file":"prism-less.min.js","name":"less"},{"file":"prism-livescript.min.js","name":"livescript"},{"file":"prism-lolcode.min.js","name":"lolcode"},{"file":"prism-lua.min.js","name":"lua"},{"file":"prism-makefile.min.js","name":"makefile"},{"file":"prism-markdown.min.js","name":"markdown"},{"file":"prism-markup.min.js","name":"markup"},{"file":"prism-matlab.min.js","name":"matlab"},{"file":"prism-mel.min.js","name":"mel"},{"file":"prism-mizar.min.js","name":"mizar"},{"file":"prism-monkey.min.js","name":"monkey"},{"file":"prism-nasm.min.js","name":"nasm"},{"file":"prism-nginx.min.js","name":"nginx"},{"file":"prism-nim.min.js","name":"nim"},{"file":"prism-nix.min.js","name":"nix"},{"file":"prism-nsis.min.js","name":"nsis"},{"file":"prism-objectivec.min.js","name":"objectivec"},{"file":"prism-ocaml.min.js","name":"ocaml"},{"file":"prism-oz.min.js","name":"oz"},{"file":"prism-parigp.min.js","name":"parigp"},{"file":"prism-parser.min.js","name":"parser"},{"file":"prism-pascal.min.js","name":"pascal"},{"file":"prism-perl.min.js","name":"perl"},{"file":"prism-php-extras.min.js","name":"php-extras"},{"file":"prism-php.min.js","name":"php"},{"file":"prism-powershell.min.js","name":"powershell"},{"file":"prism-processing.min.js","name":"processing"},{"file":"prism-prolog.min.js","name":"prolog"},{"file":"prism-properties.min.js","name":"properties"},{"file":"prism-protobuf.min.js","name":"protobuf"},{"file":"prism-puppet.min.js","name":"puppet"},{"file":"prism-pure.min.js","name":"pure"},{"file":"prism-python.min.js","name":"python"},{"file":"prism-q.min.js","name":"q"},{"file":"prism-qore.min.js","name":"qore"},{"file":"prism-r.min.js","name":"r"},{"file":"prism-reason.min.js","name":"reason"},{"file":"prism-rest.min.js","name":"rest"},{"file":"prism-rip.min.js","name":"rip"},{"file":"prism-roboconf.min.js","name":"roboconf"},{"file":"prism-ruby.min.js","name":"ruby"},{"file":"prism-rust.min.js","name":"rust"},{"file":"prism-sas.min.js","name":"sas"},{"file":"prism-sass.min.js","name":"sass"},{"file":"prism-scala.min.js","name":"scala"},{"file":"prism-scheme.min.js","name":"scheme"},{"file":"prism-scss.min.js","name":"scss"},{"file":"prism-smalltalk.min.js","name":"smalltalk"},{"file":"prism-smarty.min.js","name":"smarty"},{"file":"prism-sql.min.js","name":"sql"},{"file":"prism-stylus.min.js","name":"stylus"},{"file":"prism-swift.min.js","name":"swift"},{"file":"prism-tcl.min.js","name":"tcl"},{"file":"prism-textile.min.js","name":"textile"},{"file":"prism-twig.min.js","name":"twig"},{"file":"prism-typescript.min.js","name":"typescript"},{"file":"prism-verilog.min.js","name":"verilog"},{"file":"prism-vhdl.min.js","name":"vhdl"},{"file":"prism-vim.min.js","name":"vim"},{"file":"prism-wiki.min.js","name":"wiki"},{"file":"prism-xojo.min.js","name":"xojo"},{"file":"prism-yaml.min.js","name":"yaml"}] \ No newline at end of file +[{"file":"prism-abap.min.js","name":"abap"},{"file":"prism-actionscript.min.js","name":"actionscript"},{"file":"prism-ada.min.js","name":"ada"},{"file":"prism-apacheconf.min.js","name":"apacheconf"},{"file":"prism-apl.min.js","name":"apl"},{"file":"prism-applescript.min.js","name":"applescript"},{"file":"prism-arduino.min.js","name":"arduino"},{"file":"prism-asciidoc.min.js","name":"asciidoc"},{"file":"prism-aspnet.min.js","name":"aspnet"},{"file":"prism-autohotkey.min.js","name":"autohotkey"},{"file":"prism-autoit.min.js","name":"autoit"},{"file":"prism-bash.min.js","name":"bash"},{"file":"prism-basic.min.js","name":"basic"},{"file":"prism-batch.min.js","name":"batch"},{"file":"prism-bison.min.js","name":"bison"},{"file":"prism-brainfuck.min.js","name":"brainfuck"},{"file":"prism-bro.min.js","name":"bro"},{"file":"prism-c.min.js","name":"c"},{"file":"prism-clike.min.js","name":"clike"},{"file":"prism-coffeescript.min.js","name":"coffeescript"},{"file":"prism-core.min.js","name":"core"},{"file":"prism-cpp.min.js","name":"cpp"},{"file":"prism-crystal.min.js","name":"crystal"},{"file":"prism-csharp.min.js","name":"csharp"},{"file":"prism-css-extras.min.js","name":"css-extras"},{"file":"prism-css.min.js","name":"css"},{"file":"prism-d.min.js","name":"d"},{"file":"prism-dart.min.js","name":"dart"},{"file":"prism-diff.min.js","name":"diff"},{"file":"prism-django.min.js","name":"django"},{"file":"prism-docker.min.js","name":"docker"},{"file":"prism-eiffel.min.js","name":"eiffel"},{"file":"prism-elixir.min.js","name":"elixir"},{"file":"prism-erlang.min.js","name":"erlang"},{"file":"prism-flow.min.js","name":"flow"},{"file":"prism-fortran.min.js","name":"fortran"},{"file":"prism-fsharp.min.js","name":"fsharp"},{"file":"prism-gherkin.min.js","name":"gherkin"},{"file":"prism-git.min.js","name":"git"},{"file":"prism-glsl.min.js","name":"glsl"},{"file":"prism-go.min.js","name":"go"},{"file":"prism-graphql.min.js","name":"graphql"},{"file":"prism-groovy.min.js","name":"groovy"},{"file":"prism-haml.min.js","name":"haml"},{"file":"prism-handlebars.min.js","name":"handlebars"},{"file":"prism-haskell.min.js","name":"haskell"},{"file":"prism-haxe.min.js","name":"haxe"},{"file":"prism-http.min.js","name":"http"},{"file":"prism-icon.min.js","name":"icon"},{"file":"prism-inform7.min.js","name":"inform7"},{"file":"prism-ini.min.js","name":"ini"},{"file":"prism-j.min.js","name":"j"},{"file":"prism-java.min.js","name":"java"},{"file":"prism-javascript.min.js","name":"javascript"},{"file":"prism-jolie.min.js","name":"jolie"},{"file":"prism-json.min.js","name":"json"},{"file":"prism-jsx.min.js","name":"jsx"},{"file":"prism-julia.min.js","name":"julia"},{"file":"prism-keyman.min.js","name":"keyman"},{"file":"prism-kotlin.min.js","name":"kotlin"},{"file":"prism-latex.min.js","name":"latex"},{"file":"prism-less.min.js","name":"less"},{"file":"prism-livescript.min.js","name":"livescript"},{"file":"prism-lolcode.min.js","name":"lolcode"},{"file":"prism-lua.min.js","name":"lua"},{"file":"prism-makefile.min.js","name":"makefile"},{"file":"prism-markdown.min.js","name":"markdown"},{"file":"prism-markup.min.js","name":"markup"},{"file":"prism-matlab.min.js","name":"matlab"},{"file":"prism-mel.min.js","name":"mel"},{"file":"prism-mizar.min.js","name":"mizar"},{"file":"prism-monkey.min.js","name":"monkey"},{"file":"prism-n4js.min.js","name":"n4js"},{"file":"prism-nasm.min.js","name":"nasm"},{"file":"prism-nginx.min.js","name":"nginx"},{"file":"prism-nim.min.js","name":"nim"},{"file":"prism-nix.min.js","name":"nix"},{"file":"prism-nsis.min.js","name":"nsis"},{"file":"prism-objectivec.min.js","name":"objectivec"},{"file":"prism-ocaml.min.js","name":"ocaml"},{"file":"prism-opencl.min.js","name":"opencl"},{"file":"prism-oz.min.js","name":"oz"},{"file":"prism-parigp.min.js","name":"parigp"},{"file":"prism-parser.min.js","name":"parser"},{"file":"prism-pascal.min.js","name":"pascal"},{"file":"prism-perl.min.js","name":"perl"},{"file":"prism-php-extras.min.js","name":"php-extras"},{"file":"prism-php.min.js","name":"php"},{"file":"prism-powershell.min.js","name":"powershell"},{"file":"prism-processing.min.js","name":"processing"},{"file":"prism-prolog.min.js","name":"prolog"},{"file":"prism-properties.min.js","name":"properties"},{"file":"prism-protobuf.min.js","name":"protobuf"},{"file":"prism-pug.min.js","name":"pug"},{"file":"prism-puppet.min.js","name":"puppet"},{"file":"prism-pure.min.js","name":"pure"},{"file":"prism-python.min.js","name":"python"},{"file":"prism-q.min.js","name":"q"},{"file":"prism-qore.min.js","name":"qore"},{"file":"prism-r.min.js","name":"r"},{"file":"prism-reason.min.js","name":"reason"},{"file":"prism-renpy.min.js","name":"renpy"},{"file":"prism-rest.min.js","name":"rest"},{"file":"prism-rip.min.js","name":"rip"},{"file":"prism-roboconf.min.js","name":"roboconf"},{"file":"prism-ruby.min.js","name":"ruby"},{"file":"prism-rust.min.js","name":"rust"},{"file":"prism-sas.min.js","name":"sas"},{"file":"prism-sass.min.js","name":"sass"},{"file":"prism-scala.min.js","name":"scala"},{"file":"prism-scheme.min.js","name":"scheme"},{"file":"prism-scss.min.js","name":"scss"},{"file":"prism-smalltalk.min.js","name":"smalltalk"},{"file":"prism-smarty.min.js","name":"smarty"},{"file":"prism-sql.min.js","name":"sql"},{"file":"prism-stylus.min.js","name":"stylus"},{"file":"prism-swift.min.js","name":"swift"},{"file":"prism-tcl.min.js","name":"tcl"},{"file":"prism-textile.min.js","name":"textile"},{"file":"prism-twig.min.js","name":"twig"},{"file":"prism-typescript.min.js","name":"typescript"},{"file":"prism-vbnet.min.js","name":"vbnet"},{"file":"prism-verilog.min.js","name":"verilog"},{"file":"prism-vhdl.min.js","name":"vhdl"},{"file":"prism-vim.min.js","name":"vim"},{"file":"prism-wiki.min.js","name":"wiki"},{"file":"prism-xojo.min.js","name":"xojo"},{"file":"prism-yaml.min.js","name":"yaml"}] \ No newline at end of file