<commit_before>'use strict'

utils = require 'utils'
assert = require 'assert'
log = require 'log'

assert = assert.scope 'View.Use'
log = log.scope 'View', 'Use'

module.exports = (File) -> class Use
	@__name__ = 'Use'
	@__path__ = 'File.Use'

	JSON_CTOR_ID = @JSON_CTOR_ID = File.JSON_CTORS.push(Use) - 1

	i = 1
	JSON_NODE = i++
	JSON_ARGS_LENGTH = @JSON_ARGS_LENGTH = i

	@_fromJSON = (file, arr, obj) ->
		unless obj
			node = file.node.getChildByAccessPath arr[JSON_NODE]
			obj = new Use file, node
		obj

	visibilityChangeListener = ->
		if @file.isRendered and not @isRendered
			@render()

	attrsChangeListener = (name) ->
		if name is 'neft:fragment'
			@name = @node.attrs.get 'neft:fragment'

			if @isRendered
				@revert()
				@render()
		return

	queue = []
	queuePending = false

	runQueue = ->
		style = queue.shift()
		file = queue.shift()

		if style.isRendered
			style.renderFragment file

		if queue.length
			requestAnimationFrame runQueue
		else
			queuePending = false
		return

	constructor: (@file, @node) ->
		assert.instanceOf file, File
		assert.instanceOf node, File.Element

		@name = node.attrs.get 'neft:fragment'
		@usedFragment = null
		@isRendered = false

		node.onVisibleChange visibilityChangeListener, @
		node.onAttrsChange attrsChangeListener, @

		`//<development>`
		if @constructor is Use
			Object.preventExtensions @
		`//</development>`

	`//<development>`
	usesWithNotFoundFragments = []
	logUsesWithNoFragments = ->
		while useElem = usesWithNotFoundFragments.pop()
			unless useElem.usedFragment
				log.warn "neft:fragment '#{useElem.name}' can't be find in file '#{useElem.file.path}'"
		return
	`//</development>`

	render: (file) ->
		assert.instanceOf file, File if file?

		return unless @node.visible

		if @isRendered
			@revert()

		@isRendered = true

		useAsync = utils.isClient
		useAsync &&= @node.attrs.has 'neft:async'
		useAsync &&= @node.attrs.get('neft:async') isnt false
		if useAsync
			queue.push this, file
			unless queuePending
				requestAnimationFrame runQueue
				queuePending = true
		else
			@renderFragment file

		return

	renderFragment: (file) ->
		fragment = @file.fragments[@name]
		if not file and not fragment
			`//<development>`
			# if usesWithNotFoundFragments.push(@) is 1
			# 	setTimeout logUsesWithNoFragments
			`//</development>`
			return

		usedFragment = file or File.factory(fragment)
		unless file
			usedFragment.storage = @file.storage

		if file
			file.parentUse?.detachUsedFragment()

		unless usedFragment.isRendered
			usedFragment = usedFragment.render @

		usedFragment.node.parent = @node
		@usedFragment = usedFragment

		# signal
		usedFragment.parentUse = @
		usedFragment.onReplaceByUse.emit @

		return

	revert: ->
		return unless @isRendered

		# destroy used fragment
		if @usedFragment
			@usedFragment.revert().destroy()

		@isRendered = false
		return

	detachUsedFragment: ->
		assert.isDefined @usedFragment

		@usedFragment.node.parent = null
		@usedFragment.parentUse = null
		@usedFragment = null
		return

	clone: (original, file) ->
		node = original.node.getCopiedElement @node, file.node

		new Use file, node

	toJSON: (key, arr) ->
		unless arr
			arr = new Array JSON_ARGS_LENGTH
			arr[0] = JSON_CTOR_ID
		arr[JSON_NODE] = @node.getAccessPath @file.node
		arr
<commit_msg>'neft:use' now works with fragments across files<commit_after>'use strict'

utils = require 'utils'
assert = require 'assert'
log = require 'log'

assert = assert.scope 'View.Use'
log = log.scope 'View', 'Use'

module.exports = (File) -> class Use
	@__name__ = 'Use'
	@__path__ = 'File.Use'

	JSON_CTOR_ID = @JSON_CTOR_ID = File.JSON_CTORS.push(Use) - 1

	i = 1
	JSON_NODE = i++
	JSON_ARGS_LENGTH = @JSON_ARGS_LENGTH = i

	@_fromJSON = (file, arr, obj) ->
		unless obj
			node = file.node.getChildByAccessPath arr[JSON_NODE]
			obj = new Use file, node
		obj

	visibilityChangeListener = ->
		if @file.isRendered and not @isRendered
			@render()

	attrsChangeListener = (name) ->
		if name is 'neft:fragment'
			@name = @node.attrs.get 'neft:fragment'

			if @isRendered
				@revert()
				@render()
		return

	queue = []
	queuePending = false

	runQueue = ->
		style = queue.shift()
		file = queue.shift()

		if style.isRendered
			style.renderFragment file

		if queue.length
			requestAnimationFrame runQueue
		else
			queuePending = false
		return

	constructor: (@file, @node) ->
		assert.instanceOf file, File
		assert.instanceOf node, File.Element

		@name = node.attrs.get 'neft:fragment'
		@usedFragment = null
		@isRendered = false

		node.onVisibleChange visibilityChangeListener, @
		node.onAttrsChange attrsChangeListener, @

		`//<development>`
		if @constructor is Use
			Object.preventExtensions @
		`//</development>`

	`//<development>`
	usesWithNotFoundFragments = []
	logUsesWithNoFragments = ->
		while useElem = usesWithNotFoundFragments.pop()
			unless useElem.usedFragment
				log.warn "neft:fragment '#{useElem.name}' can't be find in file '#{useElem.file.path}'"
		return
	`//</development>`

	render: (file) ->
		assert.instanceOf file, File if file?

		return unless @node.visible

		if @isRendered
			@revert()

		@isRendered = true

		useAsync = utils.isClient
		useAsync &&= @node.attrs.has 'neft:async'
		useAsync &&= @node.attrs.get('neft:async') isnt false
		if useAsync
			queue.push this, file
			unless queuePending
				requestAnimationFrame runQueue
				queuePending = true
		else
			@renderFragment file

		return

	renderFragment: (file) ->
		fragment = @file.fragments[@name]
		if not file and not fragment and not File._files[@name]
			`//<development>`
			# if usesWithNotFoundFragments.push(@) is 1
			# 	setTimeout logUsesWithNoFragments
			`//</development>`
			return

		usedFragment = file or File.factory(fragment or @name)
		unless file
			usedFragment.storage = @file.storage

		if file
			file.parentUse?.detachUsedFragment()

		unless usedFragment.isRendered
			usedFragment = usedFragment.render @

		usedFragment.node.parent = @node
		@usedFragment = usedFragment

		# signal
		usedFragment.parentUse = @
		usedFragment.onReplaceByUse.emit @

		return

	revert: ->
		return unless @isRendered

		# destroy used fragment
		if @usedFragment
			@usedFragment.revert().destroy()

		@isRendered = false
		return

	detachUsedFragment: ->
		assert.isDefined @usedFragment

		@usedFragment.node.parent = null
		@usedFragment.parentUse = null
		@usedFragment = null
		return

	clone: (original, file) ->
		node = original.node.getCopiedElement @node, file.node

		new Use file, node

	toJSON: (key, arr) ->
		unless arr
			arr = new Array JSON_ARGS_LENGTH
			arr[0] = JSON_CTOR_ID
		arr[JSON_NODE] = @node.getAccessPath @file.node
		arr

{'fraction_non_alphanumeric': 0.11205737337516809, 'fraction_numerical': 0.0011952786493351262, 'mean_word_length': 3.6197377501725327, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 41, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4383861', 'n_tokens_mistral': 2564, 'n_tokens_neox': 2207, 'n_words': 549}