Class: Goat::Component

Inherits:
Object show all
Includes:
HTMLHelpers
Defined in:
lib/goat.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from HTMLHelpers

#jsesc

Constructor Details

#initializeComponent

Returns a new instance of Component.



1227
1228
1229
# File 'lib/goat.rb', line 1227

def initialize
  @id = 'dom_' + String.random(10)
end

Instance Attribute Details

#handlersObject (readonly)

Returns the value of attribute handlers.



1103
1104
1105
# File 'lib/goat.rb', line 1103

def handlers
  @handlers
end

#idObject (readonly)

Returns the value of attribute id.



1103
1104
1105
# File 'lib/goat.rb', line 1103

def id
  @id
end

#initargsObject (readonly)

Returns the value of attribute initargs.



1103
1104
1105
# File 'lib/goat.rb', line 1103

def initargs
  @initargs
end

#pageObject (readonly)

Returns the value of attribute page.



1103
1104
1105
# File 'lib/goat.rb', line 1103

def page
  @page
end

#paramsObject (readonly)

Returns the value of attribute params.



1103
1104
1105
# File 'lib/goat.rb', line 1103

def params
  @params
end

Class Method Details

.__cssObject



1267
# File 'lib/goat.rb', line 1267

def self.__css; @css; end

.__scriptObject



1258
# File 'lib/goat.rb', line 1258

def self.__script; @script; end

.clientside(js) ⇒ Object



1270
1271
1272
1273
# File 'lib/goat.rb', line 1270

def self.clientside(js)
  script(js)
  @wired = true
end

.css(css) ⇒ Object



1265
# File 'lib/goat.rb', line 1265

def self.css(css); @css = css; end

.from_skel(skel) ⇒ Object



1182
1183
1184
1185
1186
# File 'lib/goat.rb', line 1182

def self.from_skel(skel)
  inst = Goat.new_without_initialize(self)
  inst.load_skel(skel)
  inst
end

.get_rpc(name, opts = {}, &blk) ⇒ Object



1295
1296
1297
# File 'lib/goat.rb', line 1295

def self.get_rpc(name, opts={}, &blk)
  rpc(name, opts.merge(:is_get => true), &blk)
end

.live_enabledObject



1107
# File 'lib/goat.rb', line 1107

def self.live_enabled; @live_enabled = true; end

.live_enabled?Boolean

Returns:

  • (Boolean)


1108
# File 'lib/goat.rb', line 1108

def self.live_enabled?; @live_enabled; end

.live_rpc(name, opts = {}, &blk) ⇒ Object



1291
1292
1293
# File 'lib/goat.rb', line 1291

def self.live_rpc(name, opts={}, &blk)
  rpc(name, opts.merge(:live => true), &blk)
end

.rerender(skel) ⇒ Object



1127
1128
1129
1130
1131
1132
1133
1134
# File 'lib/goat.rb', line 1127

def self.rerender(skel)
  Profile.in(:create_component)
  c = Kernel.fetch_class(skel.cls).from_skel(skel)
  c.deserialize(skel.state)
  Profile.out(:create_component)
  
  c.rerender
end

.rerender_and_update(spec) ⇒ Object



1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
# File 'lib/goat.rb', line 1111

def self.rerender_and_update(spec)
  cls = self.name

  Profile.request_start

  Profile.in(:render_and_update)
  StateSrvClient.live_components(cls, spec).each do |skel|
    Profile.in(:cls_rerender)
    rerender(skel)
    Profile.out(:cls_rerender)
  end
  Profile.out(:render_and_update)

  Profile.request_end
end

.rpc(name, opts = {}, &blk) ⇒ Object



1284
1285
1286
1287
1288
1289
# File 'lib/goat.rb', line 1284

def self.rpc(name, opts={}, &blk)
  Goat.rpc_handlers[self.name.to_s] ||= {}
  Goat.rpc_handlers[self.name.to_s][name.to_s] = opts

  App.send(:define_method, "rpc_#{name}", blk)
end

.scope_css(css, prefix, dot_or_hash) ⇒ Object



1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
# File 'lib/goat.rb', line 1328

def self.scope_css(css, prefix, dot_or_hash)
  # #%foo, .%bar, etc
  rep = css.gsub(/(.)%(\w+)([\ \t\{])/) do |str|
    p = $1
    m = $2
    ws = $3
    "#{p}#{prefix}_#{m}#{ws}"
  end
  rep.gsub(/(^|\W)%([\W\{])/) do |str|
    "#{$1}#{dot_or_hash}#{prefix}#{$2}"
  end
end

.scoped_cssObject



1341
1342
1343
# File 'lib/goat.rb', line 1341

def self.scoped_css
  scope_css(self.__css, self.name, '.')
end

.script(script) ⇒ Object



1256
# File 'lib/goat.rb', line 1256

def self.script(script); @script = AutoBind.process(script); end

.wired?Boolean

Returns:

  • (Boolean)


1275
# File 'lib/goat.rb', line 1275

def self.wired?; @wired; end

Instance Method Details

#__cssObject



1268
# File 'lib/goat.rb', line 1268

def __css; @css; end

#__scriptObject



1259
# File 'lib/goat.rb', line 1259

def __script; @script; end

#clientside_argsObject



1277
# File 'lib/goat.rb', line 1277

def clientside_args; []; end

#clientside_instanceObject



1279
1280
1281
1282
# File 'lib/goat.rb', line 1279

def clientside_instance
  args = [id, clientside_args].to_json[1..-2]
  "(new #{self.class.name}('#{self.class.name}', #{args}))"
end

#component(body) ⇒ Object



1311
1312
1313
1314
# File 'lib/goat.rb', line 1311

def component(body)
  [:div, {:id => id, :class => component_name_hierarchy.join(' ')},
    body]
end

#component_name_hierarchy(cls = self.class) ⇒ Object



1299
1300
1301
1302
1303
1304
1305
# File 'lib/goat.rb', line 1299

def component_name_hierarchy(cls=self.class)
  if cls == Component
    []
  else
    component_name_hierarchy(cls.superclass) + [cls.name]
  end
end

#css(css) ⇒ Object



1266
# File 'lib/goat.rb', line 1266

def css(css); @css = css; end

#deserialize(state) ⇒ Object



1239
1240
# File 'lib/goat.rb', line 1239

def deserialize(state)
end

#dom_as_expandedObject



1320
1321
1322
# File 'lib/goat.rb', line 1320

def dom_as_expanded
  @expanded_dom
end

#dom_html(dom) ⇒ Object



1324
1325
1326
# File 'lib/goat.rb', line 1324

def dom_html(dom)
  DOMTools::HTMLBuilder.new(dom).html
end

#erb(*args, &blk) ⇒ Object



1246
1247
1248
# File 'lib/goat.rb', line 1246

def erb(*args, &blk)
  ERBRunner.new(nil, nil, @params).erb(*args, &blk)
end

#expanded_domObject



1316
1317
1318
# File 'lib/goat.rb', line 1316

def expanded_dom
  @expanded_dom ||= DOMTools.expanded_dom(inject_prefixes(self.dom))
end

#inject_prefixes(dom) ⇒ Object



1307
1308
1309
# File 'lib/goat.rb', line 1307

def inject_prefixes(dom)
  DOMTools.inject_prefixes(self.id, dom)
end

#live_enabled?Boolean

Returns:

  • (Boolean)


1109
# File 'lib/goat.rb', line 1109

def live_enabled?; self.class.live_enabled?; end

#live_for(spec) ⇒ Object



1231
1232
1233
# File 'lib/goat.rb', line 1231

def live_for(spec)
  @live_spec = spec
end

#live_specObject



1242
1243
1244
# File 'lib/goat.rb', line 1242

def live_spec
  @live_spec ? @live_spec : raise("No live_spec specified")
end

#load_skel(skel) ⇒ Object



1188
1189
1190
1191
1192
1193
# File 'lib/goat.rb', line 1188

def load_skel(skel)
  @id = skel.id
  @pgid = skel.pgid
  @old_dom = skel.dom
  @live_spec = skel.spec
end

#model_changed(item, notif) ⇒ Object



1349
1350
1351
# File 'lib/goat.rb', line 1349

def model_changed(item, notif)
  render
end

#partial_erb(*args, &blk) ⇒ Object



1250
1251
1252
# File 'lib/goat.rb', line 1250

def partial_erb(*args, &blk)
  ERBRunner.new(nil, nil, @params).partial_erb(*args, &blk)
end

#pgid=(id) ⇒ Object



1169
# File 'lib/goat.rb', line 1169

def pgid=(id); @pgid = id; end

#register_callback(callback) ⇒ Object



1353
1354
1355
1356
1357
1358
1359
1360
1361
# File 'lib/goat.rb', line 1353

def register_callback(callback)
  # if @callbacks.values.include?(callback)
  #   @callbacks.to_a.detect{|k, v| k if v == callback}
  # else
    key = String.random
    @callbacks[key] = callback
    key
  # end
end

#rerenderObject



1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
# File 'lib/goat.rb', line 1140

def rerender
  Profile.in(:rerender)

  helper = ExpansionHelper.new

  Profile.in(:expansion)
  Dynamic.let(:expander => helper) do
    @expanded_dom = self.expanded_dom
  end
  Profile.out(:expansion)

  Profile.in(:diff)
  diff = DOMDiff.diff(@old_dom, @expanded_dom, @id)
  Profile.out(:diff)

  if diff.size == 0
    # pass
    $stderr.puts "No changes"
  elsif diff.size < 0 # TODO constant
    rerender_partially(diff)
  else
    rerender_fully(helper.components)
  end
rescue JustRerenderError # partial updater gave up
  rerender_fully(helper.components)
ensure
  Profile.out(:rerender)
end

#rerender_fully(cs) ⇒ Object



1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
# File 'lib/goat.rb', line 1204

def rerender_fully(cs)
  Profile.in(:distillation)
  distiller = DOMDistiller.new(@expanded_dom, cs + [self])
  js = distiller.script
  css = distiller.style
  Profile.out(:distillation)

  Profile.in(:update_send)

  UpdateDispatcher.component_updated(
    @pgid,
    ComponentUpdate.new(
      self.skel,
      [{'type' => 'rep',
        'html' => dom_html(@expanded_dom),
        'js' => js,
        'css' => css,
        'parent' => @id,
        'position' => nil}]))

  Profile.out(:update_send)
end

#rerender_partially(diff) ⇒ Object



1195
1196
1197
1198
1199
1200
1201
1202
# File 'lib/goat.rb', line 1195

def rerender_partially(diff)
  $stderr.puts "should do #{diff.inspect} in #{self.class.name}/#{@id}"
  StateSrvClient.component_updated(
    self.class.name,
    @id,
    @expanded_dom
  )
end

#scoped_cssObject



1345
1346
1347
# File 'lib/goat.rb', line 1345

def scoped_css
  self.class.scope_css(self.__css, @id, '#')
end

#script(script) ⇒ Object



1257
# File 'lib/goat.rb', line 1257

def script(script); @script = AutoBind.process(script); end

#serializeObject



1235
1236
1237
# File 'lib/goat.rb', line 1235

def serialize
  {}
end

#skelObject



1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
# File 'lib/goat.rb', line 1171

def skel
  ComponentSkeleton.new(
    @pgid,
    self.class.name,
    @id,
    live_spec,
    serialize,
    @expanded_dom
  )
end

#updateObject



1136
1137
1138
# File 'lib/goat.rb', line 1136

def update
  rerender
end

#wire_scriptObject



1261
1262
1263
# File 'lib/goat.rb', line 1261

def wire_script
  "Goat.wireComponent('#{id}', #{clientside_instance})"
end