Giter VIP home page Giter VIP logo

moon's Introduction

Moon

The minimal & fast library for functional user interfaces

Build Status Code Coverage Slack License

Summary

  • πŸŽ‰ Small file size (2kb minified + gzip)
  • ⚑ Blazing fast view rendering
  • πŸ”¨ Purely functional driver-based design
  • πŸš€ Intuitive & consistent API

About

See the about page for more information on why Moon was created.

Usage

See the documentation.

Contributing

Check the CONTRIBUTING file for more information about this project and how to help.

Support

Support Moon on Patreon to help sustain the development of the project. The maker of the project works on open source for free. If you or your company depend on this project, then it makes sense to donate to ensure that the project is maintained.

License

Licensed under the MIT License by Kabir Shah

moon's People

Contributors

arandaschimpf avatar fengzilong avatar hackerxian avatar kbrsh avatar piperchester avatar shellvip avatar shinriyo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

moon's Issues

Calling a Method via `m-on` and Custom Parameters is Slow

Making a new function call just to evaluate parameters is a very expensive operation, along with getting them inside the opening/closing parenthesis.

A better solution would be to just put the function call in the render method.

Curious about checkboxes and radiobuttons

I was curious if moon works with multiple checkboxes with the same name. It seems to bind it all together if I use the same model. Also I can't seem to get radiobuttons to work. I was expecting similar to
https://vuejs.org/v2/guide/forms.html#Checkbox -- the 'Multiple checkboxes, bound to the same Array' bit and https://vuejs.org/v2/guide/forms.html#Radio.

My stab at seeing if it would work. Am I just doing something silly? https://jsfiddle.net/fw8spum7/
I see that the checkboxes with different names work fine. Just hoping you might want to cater to this use-case.

Thanks for a great slim front-end, just what I was looking for!

Conditional Object Classes and Array of Classes

First, add two forms of adding the class attribute.

Single class:

<h1 class="className"></h1>

Array of Classes:

<h1 class="['className', 'otherClass']"></h1>

Next, add support for a class being a conditional statement in an object:

<h1 class="{className: {{condition}}, otherClass: {{condition}} === false}"></h1>

These objects can also be used in the array of classes.

Add Component System

Implement a component system that can take props, and each has their own scope, etc.

Filters

I tried to use pipe filters and there was an error. Are there any pipe filters functionalities? Thanks

Passing a Template to an Event Handler doesn't Render Correctly

Passing a template parameter to an event using m-on doesn't render correctly.

For example:

<button m-on="click:someMethod({{val}})">Button</button>

Moon will throw an error or pass a random string instead of the expected value.

To fix this, maybe Moon should compile the template of the parameters.

Can not seem to get computed properties to work

Overview of the problem

This is about the Moon JS framework
I'm using Moon 0.8.0
My browser is: Chrome 57.0.2987.133 (64-bit)
I am sure this issue is not (well sort of not) a duplicate

Description

I am trying to use computed properties, which I saw had been added in early March 2017 (Issue #13). Since computed properties haven't been added to the docs, I decided to give it a kick at the can anyway, based on what I know about Vue. Sadly, I can't get it to work :-( .

My issue may also extend to method calls as well.

Steps to Reproduce

  1. Consider this rather silly, yet simple, example:
var app = new Moon({
  el: "#app",
  
  data: {
    message: 'Hello World!'
  },

  computed: {
    reversedMessage () {
      return this.get('message').split('').reverse().join('')
    }
  }
})
  1. ...and this HTML
<div id="app">
  <h4 m-text="reversedMessage"></h4>
</div>

Expected behavior

The reversedMessage computed property method should fire, producing the following HTML:

<div id="app">
  <h4>!dlroW olleH</h4>
</div>

Actual behavior

The way things are now, reversedMessage did not fire. Instead, it just rendered:

<div id="app">
  <h4>reversedMessage</h4>
</div>

Calling functions inside delimiters

Is it there a way to call functions inside of the delimited expressions for example:

...
  computed : {
         add : {
             get : function (a, b) {
                  return a + b;
             }
         }
...

and in the html

<p>{{add(1, 3)}}</p>

Feature suggestions and a question

Features:

  1. Make Moon#set chainable
  2. When data has member field1, make moonInstance.field1 a property, triggering Moon#set on assignment. This need not apply to arbitrarily complex data names. (I'm going to experiment with this a bit; I've already done a POC regarding the addition of arbitrary properties to a page framework.)

Item 2 brings me to a question: if my application has (for example) flight segments to be rendered

const trip = {
    segments : [
       { origin:"MIA",dest:"MCO",date:"09SEP17",departs:"0800",arrives:"0852"},
       { origin:"MCO",dest:"ATL",date:"09SEP17",departs:"1020",arrives:"1115"},
       // etc.
    ]
};

then what does the HTML look like to render that in Moon? (I couldn't make it work the way I wanted to in Vue, and mustaches don't seem to lend themselves to it.) Overall these frameworks seem oriented toward single-field renders or (at best) single-column data amenable to UL rendering. Can't quite get my head around complex data rendering for these things.

Components

Looking into your library and I like what I am seeing ... keep up the good work

There is no info in the docs on how to implement a component..

I tried implementing it but it takes in data as string and prints list with "," any reason why this happens?

<script src="https://unpkg.com/moonjs"></script>
<div id="app1">
		<list data={{listdata}}></list>
	</div>
<script>
var list = Moon.component("list", {
		props:['data'],
		template:"<ul><li m-for='item in {{data}}'>{{item}}</li></ul>"
	})
	var app = new Moon({
		el:"#app1",
		data: {
			listdata:[0,1,2,3,4,5,6,7,8,9]	
		}
		
	})
</script>

Is data should be function in a component?

	<script src="https://unpkg.com/moonjs"></script>
	<div id="app1">
		<simple-counter></simple-counter>
		<simple-counter></simple-counter>
		<simple-counter></simple-counter>
	</div>
	<script>
		Moon.component('simple-counter', {
			template: '<button m-on:click="add">{{ counter }}</button>',
			data: {
				counter: 0
			},
			methods: {
				add: function () {
					var v = this.get('counter');
					this.set('counter', v + 1);
				}
			}
		})
		var app = new Moon({
			el: "#app1"
		})
	</script>

the result is strange.

LICENSE file missing

Hello @kingpixil πŸ‘‹ !
Great UI library! I've been looking for the LICENSE file of the repo but it seems you only added it on the package.json. It would be great to have it on the repo.

how to fetch from REST API

I'm trying to fetch data from external json and can't figure out how, I'm using a kind of fechData fro VueJS (as both looks similar) and returning nothing. Any clues?

Multiple Directives with Same Type on Same Element

Having multiple directives on the same element that have the same type, for example:

<div m-on="click:action" m-on="click:otherAction"></div>

The only prop will be m-on:"click:otherAction", because the other property is overwritten.

A solution would be to store props as an array inside, only for directives, and execute for all of them.

Keyed Virtual DOM

Moon has trouble when there are different nodes of the same node name, such as two checkboxes. It assumes they are the same and goes on to diff the text nodes, but if the state has changed, no changes are shown.

EDIT:

It turns out this issue was with Moon updating the current node (patch in place). The issue should be fixed if it can rearrange, this can be implemented by having "key" system. The key will be a unique prop that lets Moon know which vnode belongs to what node, allowing it to rearrange the node accordingly.

Whitespace between moustache braces will not render data

Description

If there is any whitespace between the moustache braces, the information within the braces will not render. Some (like myself) like to incorporate a space between {{}} and the data to make the code more readable.

Steps to Reproduce

Create a new Moon instance and within the data object, add a message:

var app1 = new Moon({
  el: "#app1",
  data: {
    message: "Hello Moon!"
  }
});

and within your HTML:

<p>{{ message }}</p>

Expected behavior

{{ message }} should be replaced by "Hello Moon!"

Actual behavior

All you see in your HTML is "{{ message }}".

Just Wondering...

The browser support table reset, is that a problem, just wondering.

Dynamic rendering

Here are a few lines of code that describes what I am trying to achieve:

test.html

<body>
    <div id="app">
        <p>{{msg}}</p>
        <my-component></my-component>
        <div id="dynamic"></div>
    </div>

    <button id="daBtn">Add</button>

    <script src="js/vendor/jquery-1.12.0.min.js"></script>
    <script src="node_modules/moonjs/dist/moon.min.js"></script> 
    <script src="js/main.js"></script>
</body>

main.js

Moon.component('my-component', {
    template: "<h1>Custom Component</h1>"
});

var app = new Moon({
    el: "#app",
    data: {
        msg: "Hello Moon!"
    }
});

$('#daBtn').on('click', function(e) {
    e.preventDefault();
    $('#dynamic').append('<my-component></my-component>');
});

What would be the best way to notify the DOM to re-render and thus showing the newly injected component?

Thanks

Button's disabled attribute cannot be set conditionally

Description

I am trying to conditionally trying to set the disabled attribute on a button, but this doesn't seem to be working. I should be able to do this by using m-literal:disabled and set that equal to a Boolean data property.

Steps to Reproduce

  1. Consider this Moon instance:
    var app = new Moon({
      el: "#app",
      
      data: {
        isDisabled: false
      },
      
      methods: {
        setDisabled () {
          this.set('isDisabled', ! this.get('isDisabled'))
        }
      }
    })

  1. ...and this HTML:
  <div id="app">
    <button
       class="button"
       m-literal:disabled="{{isDisabled}}"
       m-on:click="setDisabled"
    >Click to disable</button>
  </div>

Expected behavior

Before I even click the button to trigger the event, the above HTML should render to:

<button class="button">Click to disable</button>

As isDisabled is initially set to false, the disabled attribute should not appear at all.

On click, we should get the following:

<button class="button" disabled>Click to disable</button>

Actual behavior

Before I even click the button to trigger the event, the above HTML actually renders to:

<button class="button" disabled="false">Click to disable</button>

and the button appears as disabled.

This is probably not a bug. The bug may actually be the human (i.e. me). Suggestions?

Compiler Problem

When compiling something like this:

<div id="app">
  <h1>App</h1>
  <ul>
    <li m-for='item in items'>
      <span>{{item}}</span>
      <input />
    </li>
  </ul>
  <button>Some Button</button>
</div>

It will create duplicate buttons, one inside the ul element.

Edit: It's a problem with how the compiler encounters unclosed elements. It pushes all nodes into the unclosed element, it should actually create an empty one.

Documentation mistake

Hi,

I was just reading though the docs, and noticed a small mistake:

"Type app1.set('signedIn', false) in the console, and watch the DOM being updated!"

but this should be app2.set('signedIn', false)

Lexical analyzer has some problems

if your html is like this:

<section class="todoapp">
      "<ccdacasd"
      <header class="header">
        <h1>todos</h1>
        <input class="new-todo" autofocus="autofocus" autocomplete="off" placeholder="What needs to be done?">
      </header>
    </section>

it will be wrong

msg and input example

The example on the website has one little bug that you might want to fix. When there is no text in the msg area, the input box moves upward. This is kind of annoying. Could you please fix this, thanks.

Object prop is passed to child component as string

First of all, congrats for sticking to your idea and launching it! I'm a Vue.js fan and really like the idea of a lightweight alternative, specially for embedded apps.

I tried out Moon this afternoon and had a problem with props. I want to send data from the main Moon instance to a child component via props. Later this data will be loaded from an API.

// app.js
const Moon = require('moonjs')
const ContactsIndex = require('./contacts/index.moon')(Moon)

new Moon({
    el: "#app",
    data: {
        contacts: [{name:"Pedro"},{name:"Augusto"},{name:"Borges"}]
    }
})
// contacts/index.moon
<template>
    <h1>Contacts</h1>
    <ul>
        <li m-for="person in {{contacts}}">{{person}}</li>
    </ul>
</template>

<script>
    exports = {
        props: ['contacts']
    }
</script>
<!-- /index.html -->
<div id="app" m-mask>
    <Index contacts="{{contacts}}"/>
</div>

Moon passes the object as a string and renders each character on a li element. Am I doing something wrong? I want to avoid converting and parsing JSON.


Another question… Is the component name tied to its file name? I want to organize components in folders and name them like so, ContactsIndex. Moon only accepts the Index name since the file is located at contacts/index.moon.

Event listeners don't update correctly

After removing an item from a list. An error occurs when I try to update other items on the list. For example:

<ul>
    <li m-for="dino in {{dinos}}">
      <button m-on:click="log({{dino}})">Log</button>
      {{dino.name}}
      <button m-on:click="removeDino({{dino}})">Make Extinct</button>
    </li>
  </ul>

Here is the JS:

       data : {
		dinos : [
			{name : "Velociraptor", quantity : 5},
			{name : "Triceratops", quantity : 15},
			{name : "Stegosaurus", quantity : 10}
		]
	},
	methods : {
		log : function (dino) {
			var dinos = this.get("dinos");
			console.log(dino, dinos.indexOf(dino));
		},
		removeDino : function (dino) {
			let dinos = this.get("dinos");
			dinos.splice(dinos.indexOf(dino), 1);
			console.log(dinos);
			this.set("dinos", dinos);
		}
	} 

When I click removeDino() on the Triceratops, the DOM is updated. However, after removing it, I can't access Stegosaurus from the Data anymore. The DOM will show Stegosaurus but when I click the log button, I get Object {name: "Triceratops", quantity: 15} -1. Please can you help me fix this? Thanks

Using array methods with instance.set()

Setting properties using instance.set() is easy enough for integers, strings and the like, but how might one use the set() method for arrays. From a Laracasts tutorial on Vuejs, suppose you had the following:

   var app = new Vue({
      el: "#app",
      data: {
        newName: '',
        names: [
          'Joe',
          'Mary',
          'Jane',
          'Jack'
        ], 
      },
      methods: {
        addName() {
          this.names.push(newName)

          this.newName = ''
        }
      }
    })

and the following in your HTML:

  <div id="app">
    <ul>
      <li v-for="name in names" v-text="name"></li>
    </ul>
          
    <input type="text" placeholder="Add a name" v-model="newName">
        
   <button @click="addName">Add Name</button>
  </div>

Every time you add a name via the <input> and click the <button>, a new name will be pushed to the names array. How would this be done via instance.set()?

What I have so far:

   var app = new Moon({
      el: "#app",
      data: {
        newName: '',
        names: [
          'Joe',
          'Mary',
          'Jane',
          'Jack'
        ], 
      },
      methods: {
        addName() {
          this.set('names', /*?????*/)

          this.set('newName', '')
        }
      }
    })

I haven't added the Moon version of the HTML, as that's pretty much the same.

Accessing data attributes?

Nice framework. How should one access data attributes for use in methods?
An example tag.

<article
  id="electriccars"
  data-columns="3"
  data-index-number="12314"
  data-parent="cars">
</article>

HTML comment spacing disrupts rendering

I wanted to write a small tutorial for the team here, and added some HTML comments.

<!DOCTYPE html>
<html>
<head>
    <title>T-Shirt</title>
    <meta charset="UTF-8">
    <meta name="description" content="">
    <meta name="keywords" content="">
    <link rel="stylesheet" href="./t-shirt.css">
</head>
<body>
    <div class="content">
        All the narrow columns have editable content; simply click on an item to edit it.
        <p>The T-shirt columns accept either upper- or lower-case input, limited to s, m, l, xl, and xxl.</p>
        <p>The story points column accepts any number, but rounds up to the next value that would be appropriate for planning poker.  Anything larger than 100 becomes 100.</p>
    </div>
    <div class="present" id="app"><!-- Moon will be told that this is the div that requires rendering -->
        <table>
            <tr>
                <th>Story</th><th>Effort</th><th>Value</th><th>Points</th>
            </tr>
            <tr m-for="item in {{stories}}"><!-- See tshirt.js -->
                <td class="story" m-html="{{item.story}}"></td>
                <td class="work"><input data-type="work" size="4" value="{{item.work}}"></td>
                <td class="value"><input data-type="value" size="4" value="{{item.value}}"></td>
                <td class="points"><input data-type="points" size="4" value="{{item.points}}"></td>
            </tr><!-- Moon will stop the rendering loop here -->
            <tr>
                <td class="story">Scores</td>
                <td class="work result" id="work"></td>
                <td class="value result" id="value"></td>
                <td class="points result" id="points"></td>
            </tr>
        </table>
    </div>
    <script src="./Loader.js"></script>
    <script src="./tshirt.js"></script>
</body>
</html>

This works as expected.
expected

Then I tried it with a space separating the angle brackets for the "see tshirt.js" comment:

<!DOCTYPE html>
<html>
<head>
    <title>T-Shirt</title>
    <meta charset="UTF-8">
    <meta name="description" content="">
    <meta name="keywords" content="">
    <link rel="stylesheet" href="./t-shirt.css">
</head>
<body>
    <div class="content">
        All the narrow columns have editable content; simply click on an item to edit it.
        <p>The T-shirt columns accept either upper- or lower-case input, limited to s, m, l, xl, and xxl.</p>
        <p>The story points column accepts any number, but rounds up to the next value that would be appropriate for planning poker.  Anything larger than 100 becomes 100.</p>
    </div>
    <div class="present" id="app"><!-- Moon will be told that this is the div that requires rendering -->
        <table>
            <tr>
                <th>Story</th><th>Effort</th><th>Value</th><th>Points</th>
            </tr>
            <tr m-for="item in {{stories}}"> <!-- See tshirt.js -->
                <td class="story" m-html="{{item.story}}"></td>
                <td class="work"><input data-type="work" size="4" value="{{item.work}}"></td>
                <td class="value"><input data-type="value" size="4" value="{{item.value}}"></td>
                <td class="points"><input data-type="points" size="4" value="{{item.points}}"></td>
            </tr><!-- Moon will stop the rendering loop here -->
            <tr>
                <td class="story">Scores</td>
                <td class="work result" id="work"></td>
                <td class="value result" id="value"></td>
                <td class="points result" id="points"></td>
            </tr>
        </table>
    </div>
    <script src="./Loader.js"></script>
    <script src="./tshirt.js"></script>
</body>
</html>

The results were unexpected:
unexpected
I don't recall any explicit advice in the docs about being careful with HTML comments, but I certainly could have missed something.

Documentation needs search

I'm very intrigued by Moon, given the size/functionality ratio. Unfortunately, the documentation right now is in serious need of some search, either Algolia or even Lunr.

I read in the docs that Moon supports computed properties as well, but to find how to use it, I resorted to Github search and found the example in tests.

Support Computed Properties

Supporting computed properties defined in the computed options in which you can add custom getters and setters to the property. It should also have access to this as a reference to the instance as well.

Example usage:

new Moon({
  data: {
    msg: "Hello Moon!"
  },
  computed: {
    reversed: {
      get: function() {
        return this.get('msg').split('').reverse().join('')
      }
    }
  }
})

This should be updated every time 'msg' is updated, and trigger view updates.

Example app5 Generates Console Error

In the Getting Started section for "Loops", the part where it tells you...

Go ahead, try entering app5.set('list', ['New Item', 'Another Item']) in the console!

...generates the following error but still makes the changes to the HTML page.

Uncaught TypeError: Cannot read property 'type' of null
    at E (unpkg.com/[email protected]:7)
    at D (unpkg.com/[email protected]:7)
    at D (unpkg.com/[email protected]:7)
    at D (unpkg.com/[email protected]:7)
    at t.patch (unpkg.com/[email protected]:7)
    at t.build (unpkg.com/[email protected]:7)
    at unpkg.com/[email protected]:7

Here's a JSBIN
http://jsbin.com/xavozefeti/2/edit?html,js,output

Dynamically mounting a component?

Is there some example code on how to dynamically mount a component to a certain element during run-time? For example, using a button?
Thanks

Normalizer Ignores/Misplaces Elements after Array

When the normalizer is given an array of vnodes, (by m-for, for example), it ignores or misplaces everything after the array.

Example:

<div id="app">
  <span m-for="item in {{items}}">{{item}}</span>
  <h1>This will be misplaced</h1>
</div>

It will show the h1 element 2 spans down, and render the rest of the spans under.

With no whitespace, such as:

<div id="app"><span m-for="item in {{items}}">{{item}}</span><h1>This will be ignored</h1></div>

It will ignore the h1

Feature request: moustache delimiter config

The moustache delimiters can conflict with other framework like for example Hugo. Although I can change the delimiters in template.js, I suggest that moon makes the delimiters configurable as a setting.

Functional Component DOM Mismatch

When diffing a functional component, the children that come after are mismatched with the DOM, and a duplicate element is created.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.