A Pen by findoff

Thumbnail
This awesome code was written by findoff, you can see more from this user in the personal repository.
You can find the original code on Codepen.io
Copyright findoff ©

Technologies

  • HTML
  • CSS
  • JavaScript
<!DOCTYPE html>
<html lang="en" >

<head>
  <meta charset="UTF-8">
  <title>A Pen by  findoff</title>
  
  
  
      <link rel="stylesheet" href="css/style.css">

  
</head>

<body>

  
<script type="text/x-template" id="opt-view">
  <div>
    {{ opt.caption }}({{ opt.name }})
    <input style="width: 4em;" v-if="opt.type === 'number'" type="number" v-model="value" :min="opt.min" :max="opt.max" @change="$emit('input', $event.target.value)"/>
    <select v-if="opt.type === 'list'" v-model="value" @change="$emit('input', $event.target.value)">
      <option v-for="caption,value in opt.values" :value="value">{{ caption }}</option>
    </select>
  </div>
</script>
<!-- ------------------------------------------>
<script type="text/x-template" id="opt">
  <table border="1">
    <tr>
      <td>name</td>
      <td>
        <input type="text" :value="value.name" @change="value.name = $event.target.value.toLowerCase(); $emit('input', value)"/>
      </td>
    </tr>
    <tr>
      <td>caption</td>
      <td>
        <input type="text" v-model="value.caption" @change="$emit('input', value)"/>
      </td>
    </tr>
    <tr>
      <td>value</td>
      <td>{{ values[value.name] }}</td>
    </tr>
    <tr>
      <td>type</td>
      <td>
        <select v-model="value.type" @change="$emit('input')">
          <option v-for="v,k in {list: 'список', number: 'число', checkbox: 'да/нет', text: 'текст'}" :value="k">{{ v }}</option>
        </select>
      </td>
    </tr>
    <template v-if="value.type === 'list'">
      <tr v-for="v,k in value.values">
        <td style="white-space: nowrap;">
          <button @click="$delete(value.values, k)" @change="$emit('input')">X</button>
          <input type="text" :value="k" size="6" @change="$delete(value.values, k); $set(value.values, $event.target.value, v); $emit('input')"/>
          <td>
            <input type="text" v-model="value.values[k]" size="6" @change="$emit('input')"/>
          </td>
        </td>
      </tr>
      <tr>
        <td>
          <button @click="$set(value.values, 'value'+Object.keys(value.values).length, 'none')" @change="$emit('input')">add</button>
        </td>
      </tr>
    </template>
    <template v-if="value.type === 'checkbox'"></template>
    <template v-if="value.type === 'number'">
      <tr>
        <td>min</td>
        <td>
          <input type="number" v-model="value.min" @change="$emit('input')"/>
        </td>
      </tr>
      <tr>
        <td>max</td>
        <td>
          <input type="number" v-model="value.max" @change="$emit('input')"/>
        </td>
      </tr>
    </template>
    <tr>
      <th colspan="2">restrictions</th>
    </tr>
    <tr v-for="r,index in value.restrictions">
      <td><a @click="" href="#">X</a>
        <select v-model="r.k" v-show="r.cmp !== 'any'">
          <option v-for="o in options" :value="o.name">{{ o.caption }}({{o.name}})</option>
        </select>
        <select v-model="r.cmp">
          <option v-for="cmp in ['any','=','!=','in','out','&lt;','&gt;','&lt;=','&gt;=',]" :value="cmp">{{ cmp }}</option>
        </select>
      </td>
      <td>
        <input type="text" v-model="r.v" style="width: 4em;" v-show="r.cmp !== 'any'"/>
        <template v-for="v,k in {include: 'I', exclude: 'E'}">
          <label :for="value.name+'res'+index+'_'+k">{{ v }}</label>
          <input type="radio" v-model="r.op" :value="k" :id="value.name+'res'+index+'_'+k"/>
        </template>
      </td>
    </tr>
    <tr>
      <th colspan="2">
        <button @click="value.restrictions.push({op: 'exclude', k: '_', cmp: '=', v: ''})">add</button>
      </th>
    </tr>
  </table>
</script>
<!-- ================================-->
<div id="app">
  <div style="float: left; border: 1px dashed #f00;">
    <transition-group name="opts-list" tag="div" qwe="qwe">
      <div v-for="opt,index in options" :key="opt">
        <div style="float: right;">
          <button @click="options.splice(index, 1)">X</button><br/>
          <button @click="shiftUp(options, index)" v-if="index !== 0">up</button><br/>
          <button @click="shiftDown(options, index)" v-if="index !== options.length-1">dn</button>
        </div>
        <opt v-model="opt" :values="values" :options="options"></opt>
      </div>
    </transition-group>
    <button @click="options.push({name: 'opt'+Object.keys(options).length, type: 'number', values: {}, restrictions: [],})">add</button>
  </div>
  <div style="float: right; border: 1px dashed #0f0;">
    <transition-group name="opts-list" tag="div" qwe="qwe">
      <opt-view v-for="opt in getCheckedList()" :key="opt.name" v-model="values[opt.name]" :values="values" :opt="opt"></opt-view>
    </transition-group>
    <table border="1" style="clear: both;">
      <tr v-for="v,k in values">
        <td>{{ k }}</td>
        <td>{{ v }}</td>
      </tr>
    </table>
    <textarea :value="JSON.stringify(options)" @mouseup="$event.target.select();"></textarea>
    <textarea :value="JSON.stringify(getActualValues())" @mouseup="$event.target.select()"></textarea>
  </div>
</div>
  <script src='https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.min.js'></script>

  

    <script  src="js/index.js"></script>




</body>

</html>

/*Downloaded from https://www.codeseek.co/findoff/a-pen-by-findoff-VxBXzg */
.opts-list-move {
  transition: 0.5s;
}

.opts-list-enter, .opts-list-leave-to {
  transform: scale(0);
  opacity: 0;
  transition: 0.5s;
}

.opts-list-leave, .opts-list-enter-to {
  opacity: 1;
  transform: scale(1);
  transition: 0.5s;
}


/*Downloaded from https://www.codeseek.co/findoff/a-pen-by-findoff-VxBXzg */
console.clear();

Vue.component('opt-view', {
	template: '#opt-view',
	props: {
		values: {},
		opt: {},
		value: {},
	},
});

Vue.component('opt', {
	template: '#opt',
	props: {
		values: {required: true,},
		options: {required: true,},
		value: {required: true,},
	},
	data(){return {};},
	mounted(){
		//this.$set(this, 'name', this.value.name);
	},
	methods: {
	},
});

let app = new Vue({
	el: '#app',
	data: {
		options: [
			{name: 'list', caption: 'A LIST!', type: "list", values: {a: 'A', b: 'B'}, restrictions: [],},
			{name: 'a', caption: 'A caption', type: "number", values: {}, min: 0, max: 10, restrictions: [{op: 'include', k: 'list', cmp: '=', v: 'b'}],},
			{name: 'b', caption: 'B caption', type: "number", values: {}, min: 3, max: 20, restrictions: [],},
			{name: 'c', caption: 'C caption', type: "number", values: {}, min: 0, max: 10, restrictions: [{op: 'exclude', k: 'list', cmp: '=', v: 'b'}],},
		],
		values: {
			a: 6,
			list: 'b',
		},
	},
	methods: {
		getCheckedList(){
			let list = [];
			for(let opt of this.options){
				let op = 'include';
				for(let r of opt.restrictions){
					let kv = this.values[r.k];
					switch(r.cmp){
						case 'any':
							op = r.op;
							break;
						case '=':
							if(kv === r.v) op = r.op;
							break;
						case '!=':
							if(kv !== r.v) op = r.op;
							break;
						case '>':
							if(+kv > +r.v) op = r.op;
							break;
						case '<':
							if(+kv < +r.v) op = r.op;
							break;
						case '>=':
							if(+kv >= +r.v) op = r.op;
							break;
						case '<=':
							if(+kv <= +r.v) op = r.op;
							break;
						case 'in':
							if(r.v.split(/,\s*/).indexOf(kv) !== -1) op = r.op;
							break;
						case 'out':
							if(r.v.split(/,\s*/).indexOf(kv) === -1) op = r.op;
							break;
						default: throw new Error(`unknown cmp value ${r.cmp}`);
					}
				}
				if(op === 'include')
					list.push(opt);
			}
			return list;
		},
		shiftUp(arr, index){
			arr.splice(index, 0, arr.splice(index-1, 1)[0]);
		},
		shiftDown(arr, index){
			arr.splice(index+1, 0, arr.splice(index, 1)[0]);
		},
		getActualValues(){
			let values = {};
			let checked = this.getCheckedList().map(o=>o.name);
			for(let i of Object.keys(this.values)){
				if( checked.indexOf(i) !== -1 ) values[i] = this.values[i];
			}
			return values;
		},
	},
});

Comments