Skip to content

Commit

Permalink
feat(#69) add Vue.js support
Browse files Browse the repository at this point in the history
  • Loading branch information
kucherenko committed Jan 8, 2017
1 parent f7afac3 commit 33f2d02
Show file tree
Hide file tree
Showing 6 changed files with 525 additions and 26 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
| Ruby | C | SCSS |
| Less | CSS | erlang |
| Swift | xml/xslt | Objective-C |
| Puppet | Twig | |
| Puppet | Twig | Vue.js |

If you need support language not from list feel free to create [request](https://github.com/kucherenko/jscpd/issues/new).

Expand Down
32 changes: 18 additions & 14 deletions src/tokenizer/TokenizerCodeMirror.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -7,38 +7,42 @@ CodeMirror = require("codemirror/addon/runmode/runmode.node.js")

CodeMirror.loadMode = (name) ->
filename = require.resolve("codemirror/mode/" + name + "/" + name + ".js")
modeDef = null
try
modeDef = fs.readFileSync(filename, "utf8")
catch err
throw new Error(name + " mode isn't shipped with CodeMirror")
vm.runInNewContext modeDef,
CodeMirror: CodeMirror

CodeMirror.loadMode 'xml'
CodeMirror.loadMode 'clike'

require filename

class TokenizerCodeMirror extends TokenizerBase
@type = null

setType: (type) ->
@type = type
setTypeAndMode: (language) ->
switch language
when "csharp", "java"
@type = 'clike'
@mode = "text/#{language}"
when 'typescript'
@type = 'javascript'
@mode = "text/#{language}"
when 'jsx'
@type = 'javascript'
@mode = "text/javascript"
else
@type = language
@mode = language


loadType: (type) ->
try
CodeMirror.loadMode type
catch e
if e.code is 'MODULE_NOT_FOUND'
logger.debug "#{e}"
console.error "JSCPD Error 01: #{type} in not supported"
@

tokenize: (code) =>
@tokens = []

@loadType @type

CodeMirror.runMode code, @type, (value, tokenType, lineNumber) =>
CodeMirror.runMode code, @mode, (value, tokenType, lineNumber) =>
return if not lineNumber
tokenType = if @isEmptyToken value then 'empty' else tokenType
tokenType = tokenType ? 'default'
Expand Down
13 changes: 3 additions & 10 deletions src/tokenizer/TokenizerFactory.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ class TokenizerFactory
xml: ['xml', 'xsl', 'xslt']
puppet: ['pp', 'puppet']
twig: ['twig']
vue: ['vue']

getLanguageByExtension: (extension) ->
for language of TokenizerFactory::LANGUAGES
Expand All @@ -50,16 +51,8 @@ class TokenizerFactory
return off if language not in supportedLanguages

if language not of TokenizerFactory::tokenizers
switch language
when "csharp", "java", "csrc"
TokenizerFactory::tokenizers[language] = new TokenizerCodeMirror()
TokenizerFactory::tokenizers[language].setType "text/x-#{language}"
when "typescript", 'jsx'
TokenizerFactory::tokenizers[language] = new TokenizerCodeMirror()
TokenizerFactory::tokenizers[language].setType "javascript"
else
TokenizerFactory::tokenizers[language] = new TokenizerCodeMirror()
TokenizerFactory::tokenizers[language].setType language
TokenizerFactory::tokenizers[language] = new TokenizerCodeMirror()
TokenizerFactory::tokenizers[language].setTypeAndMode language

TokenizerFactory::tokenizers[language]

Expand Down
262 changes: 262 additions & 0 deletions test/fixtures/vue/file_1.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,262 @@
<template>
<div von-nav class="navbar" :class="{'hide': hideNavbar}">
<div v-if="showBackButton" class="back-button" @click="backButtonClicked($event)" transition="fade">
{{{ backButtonText }}}
</div>

<div v-if="showMenuButton" class="menu-button" @click="menuButtonClicked($event)" transition="fade">
{{{ menuButtonText }}}
</div>
</div>
</template>
<style lang='scss'>
@import "../scss/variables";
@import '../scss/mixins';
$themeColor: '#007aff';
$navbar-z-index: 10;
$navbar-title-z-index: 12;
$navbar-button-z-index: 13;
.navbar {
box-sizing: border-box;
-webkit-tap-highlight-color: rgba(0,0,0,0);
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 44px;
z-index: $navbar-z-index;
background-color: #fff;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.15);
/* 用阴影替代 */
/*
&:after {
@include hairline(bottom);
}
*/
&[theme="dark"] {
background-color: #000;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.6);
.button {
color: #fff;
}
.center {
color: #fff;
}
}
.back-button, .menu-button {
position: absolute;
top: 0;
width: 80px;
height: 44px;
line-height: 44px;
z-index: $navbar-button-z-index;
.button-icon {
padding: 0;
min-height: 44px;
height: 44px;
margin-top: -1px;
&.ion-android-arrow-back {
&:before {
font-size: 28px;
}
}
}
}
.back-button {
left: 0;
padding: 0 0 0 10px;
text-align: left;
}
.menu-button {
right: 0;
padding: 0 10px 0 0;
text-align: right;
}
.center {
position: absolute;
top: 0px;
left: 0;
width: 100%;
height: 44px;
padding: 0;
text-align: center;
z-index: $navbar-title-z-index;
.title {
display: inline-block;
font-size: 18px;
line-height: 44px;
&.title-transition {
@include transition-duration($ios-transition-duration);
@include transition-timing-function($ios-transition-timing-function);
-webkit-transition-property: opacity, -webkit-transform, box-shadow;
transition-property: opacity, transform, box-shadow;
}
}
}
.fade-transition {
@include transition-duration($android-transition-duration);
@include transition-timing-function($android-transition-timing-function);
opacity: 1;
}
.fade-enter, .fade-leave {
opacity: 0;
}
}
/* android or other */
.grade-b .navbar {
.center .title,
.fade-transition
{
@include transition-property(all);
@include transition-duration($android-transition-duration);
@include transition-timing-function($android-transition-timing-function);
}
}
.navbar .hide {
visibility: hidden;
}
</style>
<script>
import channel from './channel'
import utils from './utils'
function getTitleTransitionDistance(t) {
return (document.body.offsetWidth - t.offsetWidth) / 2 - 10
}
function centerElement(navbar, title, direction) {
let centerId = Math.random().toString(36).substring(3, 8)
let c = document.createElement('div')
c.id = centerId
c.className = 'center'
let t = document.createElement('span')
if (!window.__disable_nav_title_transition__) {
t.className = 'title title-transition'
} else {
t.className = 'title'
}
t.innerHTML = title
let reverse = direction == 'back'
t.style.opacity = 0
if (!window.__disable_nav_title_transition__ && utils.is_ios_device()) {
t.style.transform = 'translate3d(' + (reverse ? '-' : '') + getTitleTransitionDistance(t) + 'px,0,0)'
t.style.webkitTransform = 'translate3d(' + (reverse ? '-' : '') + getTitleTransitionDistance(t) + 'px,0,0)'
}
if (!navbar.querySelector('.center')) {
t.style.opacity = 1
t.style.transform = 'translate3d(0,0,0)'
t.style.webkitTransform = 'translate3d(0,0,0)'
}
c.appendChild(t)
navbar.appendChild(c)
return document.getElementById(centerId)
}
function titleIn(t) {
t.style.opacity = 1
t.style.transform = 'translate3d(0,0,0)'
t.style.webkitTransform = 'translate3d(0,0,0)'
}
function titleOut(t, direction) {
let reverse = direction == 'back'
t.style.opacity = 0
if (!window.__disable_nav_title_transition__ && utils.is_ios_device()) {
t.style.transform = 'translate3d(' + (reverse ? '' : '-') + getTitleTransitionDistance(t) + 'px,0,0)'
t.style.webkitTransform = 'translate3d(' + (reverse ? '' : '-') + getTitleTransitionDistance(t) + 'px,0,0)'
}
}
function defaultBackButtonText() {
return utils.is_ios_device() ?
'<a class="button button-icon icon ion-ios-arrow-back"></a>' :
'<a class="button button-icon icon ion-android-arrow-back"></a>'
}
function defaultMenuButtonText() {
return '<a class="button button-icon icon ion-navicon"></a>'
}
window.__block_touch__ = false
function navTransitionStart() {
var navbar = document.querySelector('.navbar')
navbar.style.position = 'absolute'
window.__block_touch__ = true
}
function navTransitionEnd() {
var navbar = document.querySelector('.navbar')
navbar.style.position = 'fixed'
window.__block_touch__ = false
}
export default {
data() {
return {
title: '',
showBackButton: false,
onBackButtonClick: undefined,
showMenuButton: false,
onMenuButtonClick: undefined,
backButtonText: defaultBackButtonText(),
menuButtonText: defaultMenuButtonText(),
hideNavbar: false
}
},
created() {
// center & center leave
let c, cl;
channel.$on('PageTransitionEvent', (data) => {
let direction = document.querySelector('[von-app]').getAttribute('transition-direction')
this.title = data.title ? data.title : ''
this.hideNavbar = !!data.hideNavbar
// 浏览器前进、后退按钮被连续点击
if (document.querySelectorAll('[von-nav] .center').length > 1) {
c.querySelector('.title').innerHTML = this.title
return
}
navTransitionStart()
c = centerElement(this.$el, this.title, direction)
setTimeout(() => {
titleIn(c.querySelector('.title'))
if (cl) {
titleOut(cl.querySelector('.title'), direction)
}
setTimeout(() => {
if (cl) this.$el.removeChild(cl)
cl = c
navTransitionEnd()
}, window.__disable_nav_title_transition__ ? 0 : 600)
})
// nav item & click event handler
this.showBackButton = data.showBackButton
this.onBackButtonClick = data.onBackButtonClick
if (data.backButtonText)
this.backButtonText = data.backButtonText
else
this.backButtonText = defaultBackButtonText()
this.showMenuButton = data.showMenuButton
this.onMenuButtonClick = data.onMenuButtonClick
if (data.menuButtonText)
this.menuButtonText = data.menuButtonText
else
this.menuButtonText = defaultMenuButtonText()
})
},
methods: {
backButtonClicked(e) {
if (window.__block_touch__) {
e.preventDefault()
return;
}
if (this.onBackButtonClick) {
this.onBackButtonClick()
return
}
document.querySelector('[von-app]').setAttribute('transition-direction', 'back')
history.go(-1)
},
menuButtonClicked() {
if (window.__block_touch__) {
e.preventDefault()
return;
}
if (this.onMenuButtonClick) {
this.onMenuButtonClick()
}
}
}
}
</script>
Loading

0 comments on commit 33f2d02

Please sign in to comment.