Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file keyboard_event_handler.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300openCoreopenImportmoduleCondition=structtypet=Keyboard_event.t->boollettrue__ev=trueletfalse__ev=falseletnot_t1ev=not(t1ev)letand_t1t2ev=t1ev&&t2evletor_t1t2ev=t1ev||t2evletget_targetev=Js.Opt.to_optionev##.targetletget_target_idev=Option.map(get_targetev)~f:(funelem->Js.to_stringelem##.id);;letget_target_class_listev=Option.map(get_targetev)~f:(funelem->elem##.classList);;letinput_condev~on_input~on_textarea=matchget_targetevwith|None->false|Someelem->(matchDom_html.taggedelemwith|Inputi->on_inputi|Textareat->on_textareat|_->false);;lethas_input_targetev=input_condev~on_input:(fun_->true)~on_textarea:(fun_->true);;lethas_text_input_targetev=input_condev~on_input:(funi->String.equal(Js.to_stringi##._type)"text")~on_textarea:(fun_->true);;lethas_number_input_targetev=input_condev~on_input:(funi->String.equal(Js.to_stringi##._type)"number")~on_textarea:(fun_->false);;lethas_form_element_targetev=letfi=Option.is_some(Js.Opt.to_optioni##.form)ininput_condev~on_input:f~on_textarea:f;;lethas_target_id~idev=matchget_target_idevwith|None->false|Sometarget_id->String.equalidtarget_id;;lethas_target_class~class_ev=matchget_target_class_listevwith|None->false|Someclass_list->Js.to_bool(class_list##contains(Js.stringclass_));;endmoduleHandler=structopenVdomtypet=Keyboard_event.t->unitUi_effect.t[@@derivingsexp]letprevent_default_ev=Effect.Prevent_defaultletwith_prevent_defaulttev=Effect.Many[Effect.Prevent_default;tev]lethandle_by_case?prevent_defaulttsev=matchList.find_mapts~f:(fun(cond,t)->Option.some_if(condev)t)with|None->Effect.Ignore|Somet->letevent=tevin(matchprevent_defaultwith|None->event|Some()->Effect.Many[event;Effect.Prevent_default]);;letonly_handle_if?prevent_defaultcondt=handle_by_case?prevent_default[cond,t]endmoduleUid=Unique_id.Int()moduleCommand=structtypet={keys:Keystroke.tlist;description:string;group:Grouped_help_text.Group_name.toption;handler:Handler.t}[@@derivingsexp]letget_help_text{keys;description;_}={Help_text.Command.keys;description}endmoduleAction=structtypet=|CommandofCommand.t|Disabled_keyofKeystroke.t[@@derivingsexp,variants]letkeys=function|Commandcommand->command.keys|Disabled_keykey->[key];;lethandler=function|Commandcommand->command.handler|Disabled_key_->Handler.prevent_default;;letget_help_text=function|Commandcommand->Command.get_help_textcommand|Disabled_keykey->{Help_text.Command.keys=[key];description="Disabled"};;letmerget1t2~keys=matcht1,t2with|Disabled_key_,Disabled_key_->t1|Disabled_key_,Commandcommand|Commandcommand,Disabled_key_->lethandlerev=Vdom.Effect.Many[Vdom.Effect.Prevent_default;command.handlerev]inCommand{commandwithhandler}|Commandcommand1,Commandcommand2->Command{keys;description=sprintf"%s/%s"command1.descriptioncommand2.description;group=Option.first_somecommand1.groupcommand2.group;handler=(funev->Vdom.Effect.Many[command1.handlerev;command2.handlerev])};;endtypet=(Uid.t*Action.t)Keystroke.Map.t[@@derivingsexp_of]letempty=Keystroke.Map.emptyletnew_entriesaction=letdata=Uid.create(),actioninList.map(Action.keysaction)~f:(funkey->key,data);;letof_action_list_exnactions=List.concat_mapactions~f:new_entries|>Keystroke.Map.of_alist_exn;;letof_command_list_exncommands=of_action_list_exn(List.mapcommands~f:Action.command);;letadd_action_coretactionmap_add=List.fold(new_entriesaction)~init:t~f:(funt(key,data)->map_addt~key~data);;letset_actiontaction=add_action_coretactionMap.setletset_commandtcommand=set_actiont(Commandcommand)letset_disabled_keytkey=set_actiont(Disabled_keykey)letadd_action_exntaction=add_action_coretactionMap.add_exnletadd_command_exntcommand=add_action_exnt(Commandcommand)letadd_disabled_key_exntkey=add_action_exnt(Disabled_keykey)letmerge_core=Map.merge_skewedletmerge_override_with_right=merge_core~combine:(fun~key:__id1id2->id2)letmerge_exn=merge_core~combine:(fun~key__->failwithf!"Duplicate key %{Keystroke#hum}"key());;moduleUid_pair=structmoduleT=structtypet=Uid.t*Uid.t[@@derivingsexp,hash,compare]endincludeTincludeHashable.Make(T)end(* [merge_both] is complicated because we want to (a) combine all keys that appear in both
t1 and t2, and (b) remove those keys from any other actions in t1 and t2. *)letmerge_botht1t2=letcombined_keys_by_id_pair=Uid_pair.Table.create()inletadd_combined_keys_by_id_pair~id1~id2~key=Hashtbl.updatecombined_keys_by_id_pair(id1,id2)~f:(function|None->Uid.create(),[key]|Some(id,keys)->id,keys@[key])inletcombined_keys_by_id=Uid.Table.create()inletadd_combined_keys_by_id~id~key=Hashtbl.updatecombined_keys_by_idid~f:(function|None->Keystroke.Set.singletonkey|Somekeys->Set.addkeyskey)inMap.iter2t1t2~f:(fun~key~data->matchdatawith|`Left_|`Right_->()|`Both((id1,_),(id2,_))->add_combined_keys_by_id_pair~id1~id2~key;add_combined_keys_by_id~id:id1~key;add_combined_keys_by_id~id:id2~key);Map.merget1t2~f:(fun~key:_->function|`Both((id1,action1),(id2,action2))->letnew_id,keys=Hashtbl.find_exncombined_keys_by_id_pair(id1,id2)inletaction=Action.mergeaction1action2~keysinSome(new_id,action)|`Left(id,action)|`Right(id,action)->(matchHashtbl.findcombined_keys_by_idid,actionwith|None,_->Some(id,action)(* this case is tricky: if the id is in [combined_keys_by_id] and the action is
disabling a key, then it *should* have appeared in the `Both case. *)|Some_,Action.Disabled_keykey->failwithf!"bug: [merge] failed on disabled key %{sexp: Keystroke.t}"key()|Somecombined_keys,Action.Commandcommand->letkeys_left=List.filtercommand.keys~f:(funk->not(Set.memcombined_keysk))in(matchkeys_leftwith(* if all the keys were combined, then this action can just go away *)|[]->None|keys->Some(id,Command{commandwithkeys}))));;letmerge~on_dup=matchon_dupwith|`Override_with_right->merge_override_with_right|`Both->merge_both|`Throw->merge_exn;;lethandle_eventtev=Option.map(Map.findt(Keystroke.of_eventev))~f:(fun(_,action)->Action.handleractionev);;lethandle_or_ignore_eventtev=Option.value~default:Vdom.Effect.Ignore(handle_eventtev);;letdisabled_key_group_name=Grouped_help_text.Group_name.of_string"Disabled keys"letget_help_text_commands?include_disabled_keyst=letactions=Map.foldt~init:Uid.Map.empty~f:(fun~key~data:(id,action)actions_by_id->Map.updateactions_by_idid~f:(funprev->letprev_keys=matchprevwith|None->[]|Some(_,prev_keys)->prev_keysinaction,prev_keys@[key]))|>Map.datainList.filter_mapactions~f:(fun(action,keys)->match(action:Action.t)with|Commandcommand->letcommand={commandwithkeys}inSome(command.group,Command.get_help_textcommand)|Disabled_keykey->Option.mapinclude_disabled_keys~f:(fun()->Somedisabled_key_group_name,Action.get_help_text(Disabled_keykey)));;letget_help_text?include_disabled_keyst=lethelp_text_commands=get_help_text_commands?include_disabled_keyst|>List.map~f:sndinHelp_text.of_command_listhelp_text_commands;;letget_grouped_help_text_core?include_disabled_keys?custom_group_ordert~get_group=lethelp_text_commands=get_help_text_commands?include_disabled_keyst|>List.map~f:(Tuple2.map_fst~f:get_group)inGrouped_help_text.of_command_list?custom_group_orderhelp_text_commands;;letget_grouped_help_text?include_disabled_keys?custom_group_ordert~default_group=get_grouped_help_text_core?include_disabled_keys?custom_group_ordert~get_group:(Option.value~default:default_group);;letget_grouped_help_text_exn?include_disabled_keys?custom_group_ordert=get_grouped_help_text_core?include_disabled_keys?custom_group_ordert~get_group:(Option.value_exn~here:[%here]);;